From 856ab51b4cd08c6d207c0f151cecf5202c1d531b Mon Sep 17 00:00:00 2001 From: Emily Boudreaux Date: Thu, 19 Jun 2025 14:51:02 -0400 Subject: [PATCH] build(CppAD): brought in CppAD for autodiff we need an autodiff library at some point (or we need to roll our own but I do not think that makes sense). CppAD is well tested and header only and easy to include. It is also Liscene compatible with GPL v3.0. Here we bring it in as a dependency --- build-config/cppad/COPYING | 11 + .../cppad/include/cppad/CMakeLists.txt | 184 ++ .../cppad/include/cppad/base_require.hpp | 177 ++ .../cppad/include/cppad/configure.hpp | 238 +++ .../cppad/include/cppad/configure.hpp.in | 238 +++ .../include/cppad/core/abort_recording.hpp | 58 + build-config/cppad/include/cppad/core/abs.hpp | 132 ++ .../include/cppad/core/abs_normal_fun.hpp | 959 +++++++++ build-config/cppad/include/cppad/core/ad.hpp | 311 +++ .../cppad/include/cppad/core/ad_assign.hpp | 144 ++ .../cppad/include/cppad/core/ad_binary.hpp | 143 ++ .../cppad/include/cppad/core/ad_ctor.hpp | 199 ++ .../cppad/include/cppad/core/ad_fun.hpp | 876 +++++++++ .../cppad/include/cppad/core/ad_io.hpp | 220 +++ .../cppad/include/cppad/core/ad_to_string.hpp | 70 + .../cppad/include/cppad/core/ad_type.hpp | 59 + .../cppad/include/cppad/core/ad_valued.hpp | 50 + build-config/cppad/include/cppad/core/add.hpp | 131 ++ .../cppad/include/cppad/core/add_eq.hpp | 128 ++ .../cppad/include/cppad/core/arithmetic.hpp | 42 + .../cppad/include/cppad/core/atan2.hpp | 152 ++ .../include/cppad/core/atomic/atomic.omh | 26 + .../include/cppad/core/atomic/atomic_one.hpp | 1058 ++++++++++ .../cppad/core/atomic/atomic_three.hpp | 486 +++++ .../include/cppad/core/atomic/atomic_two.hpp | 613 ++++++ .../include/cppad/core/atomic/three_afun.hpp | 248 +++ .../include/cppad/core/atomic/three_ctor.hpp | 165 ++ .../cppad/core/atomic/three_for_type.hpp | 117 ++ .../cppad/core/atomic/three_forward.hpp | 346 ++++ .../cppad/core/atomic/three_hes_sparsity.hpp | 412 ++++ .../cppad/core/atomic/three_jac_sparsity.hpp | 355 ++++ .../cppad/core/atomic/three_rev_depend.hpp | 125 ++ .../cppad/core/atomic/three_reverse.hpp | 354 ++++ .../include/cppad/core/atomic/two_afun.hpp | 258 +++ .../include/cppad/core/atomic/two_clear.hpp | 91 + .../include/cppad/core/atomic/two_ctor.hpp | 173 ++ .../cppad/core/atomic/two_for_sparse_hes.hpp | 356 ++++ .../cppad/core/atomic/two_for_sparse_jac.hpp | 283 +++ .../include/cppad/core/atomic/two_forward.hpp | 402 ++++ .../include/cppad/core/atomic/two_option.hpp | 113 ++ .../cppad/core/atomic/two_rev_depend.hpp | 99 + .../cppad/core/atomic/two_rev_sparse_hes.hpp | 451 +++++ .../cppad/core/atomic/two_rev_sparse_jac.hpp | 289 +++ .../include/cppad/core/atomic/two_reverse.hpp | 291 +++ .../cppad/include/cppad/core/azmul.hpp | 247 +++ .../cppad/include/cppad/core/base2ad.hpp | 117 ++ .../cppad/include/cppad/core/base_complex.hpp | 384 ++++ .../include/cppad/core/base_cond_exp.hpp | 284 +++ .../cppad/include/cppad/core/base_double.hpp | 229 +++ .../cppad/include/cppad/core/base_float.hpp | 230 +++ .../cppad/include/cppad/core/base_hash.hpp | 84 + .../cppad/include/cppad/core/base_limits.hpp | 67 + .../include/cppad/core/base_std_math.hpp | 171 ++ .../include/cppad/core/base_to_string.hpp | 65 + .../cppad/include/cppad/core/bender_quad.hpp | 402 ++++ .../cppad/include/cppad/core/bool_fun.hpp | 241 +++ .../cppad/include/cppad/core/bool_valued.hpp | 49 + .../include/cppad/core/capacity_order.hpp | 256 +++ .../include/cppad/core/check_for_nan.hpp | 244 +++ .../cppad/core/chkpoint_one/chkpoint_one.hpp | 621 ++++++ .../include/cppad/core/chkpoint_one/ctor.hpp | 62 + .../core/chkpoint_one/for_sparse_jac.hpp | 135 ++ .../cppad/core/chkpoint_one/forward.hpp | 170 ++ .../core/chkpoint_one/rev_sparse_hes.hpp | 214 ++ .../core/chkpoint_one/rev_sparse_jac.hpp | 139 ++ .../cppad/core/chkpoint_one/reverse.hpp | 125 ++ .../core/chkpoint_one/set_hes_sparse_bool.hpp | 53 + .../core/chkpoint_one/set_hes_sparse_set.hpp | 57 + .../core/chkpoint_one/set_jac_sparse_bool.hpp | 56 + .../core/chkpoint_one/set_jac_sparse_set.hpp | 58 + .../cppad/core/chkpoint_two/chk_fun.omh | 65 + .../cppad/core/chkpoint_two/chkpoint_two.hpp | 311 +++ .../include/cppad/core/chkpoint_two/ctor.hpp | 222 +++ .../cppad/core/chkpoint_two/dynamic.hpp | 102 + .../cppad/core/chkpoint_two/for_type.hpp | 63 + .../cppad/core/chkpoint_two/forward.hpp | 130 ++ .../cppad/core/chkpoint_two/hes_sparsity.hpp | 86 + .../cppad/core/chkpoint_two/jac_sparsity.hpp | 86 + .../cppad/core/chkpoint_two/rev_depend.hpp | 66 + .../cppad/core/chkpoint_two/reverse.hpp | 139 ++ .../cppad/include/cppad/core/compare.hpp | 635 ++++++ .../include/cppad/core/compound_assign.hpp | 141 ++ .../cppad/include/cppad/core/con_dyn_var.hpp | 186 ++ .../cppad/include/cppad/core/cond_exp.hpp | 276 +++ .../cppad/include/cppad/core/convert.hpp | 50 + .../cppad/include/cppad/core/cppad_assert.hpp | 188 ++ .../cppad/include/cppad/core/dependent.hpp | 334 ++++ .../include/cppad/core/discrete/devel.omh | 22 + .../include/cppad/core/discrete/discrete.hpp | 334 ++++ .../include/cppad/core/discrete/user.omh | 146 ++ build-config/cppad/include/cppad/core/div.hpp | 130 ++ .../cppad/include/cppad/core/div_eq.hpp | 129 ++ .../cppad/include/cppad/core/drivers.hpp | 22 + .../cppad/include/cppad/core/epsilon.hpp | 60 + .../cppad/include/cppad/core/equal_op_seq.hpp | 118 ++ .../include/cppad/core/for_hes_sparsity.hpp | 287 +++ .../include/cppad/core/for_jac_sparsity.hpp | 305 +++ .../cppad/include/cppad/core/for_one.hpp | 163 ++ .../include/cppad/core/for_sparse_hes.hpp | 566 ++++++ .../include/cppad/core/for_sparse_jac.hpp | 764 ++++++++ .../cppad/include/cppad/core/for_two.hpp | 254 +++ .../cppad/core/forward/compare_change.omh | 156 ++ .../include/cppad/core/forward/devel.omh | 23 + .../include/cppad/core/forward/forward.hpp | 490 +++++ .../include/cppad/core/forward/forward.omh | 28 + .../cppad/core/forward/forward_dir.omh | 206 ++ .../cppad/core/forward/forward_one.omh | 111 ++ .../cppad/core/forward/forward_order.omh | 243 +++ .../cppad/core/forward/forward_two.omh | 148 ++ .../cppad/core/forward/forward_zero.omh | 116 ++ .../include/cppad/core/forward/size_order.omh | 97 + .../cppad/include/cppad/core/fun_check.hpp | 210 ++ .../include/cppad/core/fun_construct.hpp | 542 ++++++ .../cppad/include/cppad/core/fun_eval.hpp | 20 + .../include/cppad/core/graph/cpp_ad_graph.omh | 227 +++ .../include/cppad/core/graph/cpp_graph.hpp | 404 ++++ .../include/cppad/core/graph/cpp_graph.omh | 20 + .../include/cppad/core/graph/from_graph.hpp | 1498 ++++++++++++++ .../include/cppad/core/graph/from_json.hpp | 76 + .../cppad/core/graph/graph_op_enum.hpp | 238 +++ .../cppad/core/graph/json_ad_graph.omh | 330 ++++ .../cppad/core/graph/json_graph_op.omh | 430 ++++ .../include/cppad/core/graph/to_graph.hpp | 1199 ++++++++++++ .../include/cppad/core/graph/to_json.hpp | 96 + .../cppad/include/cppad/core/hash_code.hpp | 70 + .../cppad/include/cppad/core/hessian.hpp | 213 ++ .../cppad/include/cppad/core/identical.hpp | 100 + .../include/cppad/core/independent/devel.omh | 30 + .../cppad/core/independent/independent.hpp | 257 +++ .../include/cppad/core/independent/user.omh | 157 ++ .../cppad/include/cppad/core/integer.hpp | 111 ++ .../cppad/include/cppad/core/jacobian.hpp | 237 +++ .../cppad/include/cppad/core/lu_ratio.hpp | 335 ++++ build-config/cppad/include/cppad/core/mul.hpp | 136 ++ .../cppad/include/cppad/core/mul_eq.hpp | 138 ++ .../include/cppad/core/near_equal_ext.hpp | 187 ++ .../cppad/include/cppad/core/new_dynamic.hpp | 139 ++ .../cppad/include/cppad/core/num_skip.hpp | 124 ++ .../include/cppad/core/numeric_limits.hpp | 215 ++ .../include/cppad/core/omp_max_thread.hpp | 93 + .../cppad/include/cppad/core/opt_val_hes.hpp | 522 +++++ .../cppad/include/cppad/core/optimize.hpp | 376 ++++ .../cppad/include/cppad/core/ordered.hpp | 100 + .../cppad/include/cppad/core/parallel_ad.hpp | 117 ++ build-config/cppad/include/cppad/core/pow.hpp | 295 +++ .../cppad/include/cppad/core/print_for.hpp | 228 +++ .../include/cppad/core/rev_hes_sparsity.hpp | 253 +++ .../include/cppad/core/rev_jac_sparsity.hpp | 258 +++ .../cppad/include/cppad/core/rev_one.hpp | 161 ++ .../include/cppad/core/rev_sparse_hes.hpp | 643 ++++++ .../include/cppad/core/rev_sparse_jac.hpp | 654 +++++++ .../cppad/include/cppad/core/rev_two.hpp | 234 +++ .../cppad/include/cppad/core/reverse.hpp | 208 ++ .../cppad/include/cppad/core/sign.hpp | 121 ++ .../cppad/include/cppad/core/sparse.hpp | 38 + .../cppad/include/cppad/core/sparse_hes.hpp | 544 ++++++ .../include/cppad/core/sparse_hessian.hpp | 861 +++++++++ .../cppad/include/cppad/core/sparse_jac.hpp | 629 ++++++ .../include/cppad/core/sparse_jacobian.hpp | 1086 +++++++++++ .../include/cppad/core/standard_math.hpp | 118 ++ .../cppad/include/cppad/core/std_math_11.hpp | 884 +++++++++ build-config/cppad/include/cppad/core/sub.hpp | 125 ++ .../cppad/include/cppad/core/sub_eq.hpp | 124 ++ .../include/cppad/core/subgraph_jac_rev.hpp | 351 ++++ .../include/cppad/core/subgraph_reverse.hpp | 494 +++++ .../include/cppad/core/subgraph_sparsity.hpp | 242 +++ .../cppad/include/cppad/core/tape_link.hpp | 265 +++ .../cppad/include/cppad/core/test_vector.hpp | 135 ++ .../cppad/include/cppad/core/testvector.hpp | 116 ++ .../cppad/include/cppad/core/unary_minus.hpp | 100 + .../cppad/include/cppad/core/unary_plus.hpp | 97 + .../cppad/include/cppad/core/undef.hpp | 100 + .../cppad/include/cppad/core/user_ad.hpp | 71 + .../cppad/include/cppad/core/value.hpp | 95 + .../cppad/include/cppad/core/var2par.hpp | 88 + .../cppad/include/cppad/core/vec_ad/user.omh | 306 +++ .../include/cppad/core/vec_ad/vec_ad.hpp | 642 ++++++ .../cppad/include/cppad/core/zdouble.hpp | 528 +++++ build-config/cppad/include/cppad/cppad.hpp | 79 + .../cppad/example/atomic_three/mat_mul.hpp | 661 +++++++ .../example/atomic_two/eigen_cholesky.hpp | 376 ++++ .../example/atomic_two/eigen_mat_inv.hpp | 395 ++++ .../example/atomic_two/eigen_mat_mul.hpp | 658 +++++++ .../include/cppad/example/base_adolc.hpp | 359 ++++ .../include/cppad/example/code_gen_fun.hpp | 62 + .../include/cppad/example/cppad_eigen.hpp | 195 ++ .../include/cppad/example/eigen_plugin.hpp | 28 + .../cppad/include/cppad/ipopt/solve.hpp | 639 ++++++ .../include/cppad/ipopt/solve_callback.hpp | 1192 ++++++++++++ .../include/cppad/ipopt/solve_result.hpp | 73 + .../cppad/include/cppad/local/abs_op.hpp | 160 ++ .../cppad/include/cppad/local/acos_op.hpp | 263 +++ .../cppad/include/cppad/local/acosh_op.hpp | 264 +++ .../cppad/include/cppad/local/ad_tape.hpp | 186 ++ .../cppad/include/cppad/local/add_op.hpp | 338 ++++ .../cppad/include/cppad/local/asin_op.hpp | 263 +++ .../cppad/include/cppad/local/asinh_op.hpp | 264 +++ .../cppad/include/cppad/local/atan_op.hpp | 235 +++ .../cppad/include/cppad/local/atanh_op.hpp | 236 +++ .../cppad/include/cppad/local/atom_state.hpp | 32 + .../include/cppad/local/atomic_index.hpp | 161 ++ .../include/cppad/local/color_general.hpp | 275 +++ .../include/cppad/local/color_symmetric.hpp | 309 +++ .../cppad/include/cppad/local/comp_op.hpp | 420 ++++ .../cppad/include/cppad/local/cond_op.hpp | 1317 +++++++++++++ .../cppad/include/cppad/local/cos_op.hpp | 238 +++ .../cppad/include/cppad/local/cosh_op.hpp | 238 +++ .../include/cppad/local/cppad_colpack.hpp | 104 + .../cppad/include/cppad/local/cskip_op.hpp | 199 ++ .../cppad/include/cppad/local/csum_op.hpp | 612 ++++++ .../cppad/include/cppad/local/declare_ad.hpp | 183 ++ .../cppad/include/cppad/local/define.hpp | 321 +++ .../cppad/include/cppad/local/discrete_op.hpp | 121 ++ .../cppad/include/cppad/local/div_op.hpp | 574 ++++++ .../cppad/include/cppad/local/erf_op.hpp | 598 ++++++ .../cppad/include/cppad/local/exp_op.hpp | 194 ++ .../cppad/include/cppad/local/expm1_op.hpp | 199 ++ .../cppad/local/graph/cpp_graph_itr.hpp | 386 ++++ .../cppad/local/graph/cpp_graph_itr.omh | 23 + .../cppad/local/graph/cpp_graph_op.hpp | 94 + .../include/cppad/local/graph/dev_graph.omh | 28 + .../include/cppad/local/graph/json_lexer.hpp | 389 ++++ .../include/cppad/local/graph/json_lexer.omh | 24 + .../include/cppad/local/graph/json_parser.hpp | 55 + .../include/cppad/local/graph/json_writer.hpp | 54 + .../cppad/include/cppad/local/hash_code.hpp | 244 +++ .../cppad/include/cppad/local/independent.hpp | 119 ++ .../cppad/include/cppad/local/is_pod.hpp | 79 + .../cppad/include/cppad/local/is_pod.hpp.in | 41 + .../cppad/include/cppad/local/load_op.hpp | 697 +++++++ .../cppad/include/cppad/local/log1p_op.hpp | 203 ++ .../cppad/include/cppad/local/log_op.hpp | 202 ++ .../cppad/include/cppad/local/mul_op.hpp | 359 ++++ build-config/cppad/include/cppad/local/op.hpp | 59 + .../cppad/include/cppad/local/op_code_dyn.hpp | 439 +++++ .../cppad/include/cppad/local/op_code_var.hpp | 1512 +++++++++++++++ .../cppad/local/optimize/cexp_info.hpp | 123 ++ .../cppad/local/optimize/csum_op_info.hpp | 42 + .../cppad/local/optimize/csum_stacks.hpp | 47 + .../cppad/local/optimize/get_cexp_info.hpp | 260 +++ .../cppad/local/optimize/get_dyn_previous.hpp | 447 +++++ .../cppad/local/optimize/get_op_previous.hpp | 269 +++ .../cppad/local/optimize/get_op_usage.hpp | 853 ++++++++ .../cppad/local/optimize/get_par_usage.hpp | 506 +++++ .../cppad/local/optimize/hash_code.hpp | 57 + .../include/cppad/local/optimize/match_op.hpp | 292 +++ .../cppad/local/optimize/optimize_run.hpp | 1351 +++++++++++++ .../cppad/local/optimize/record_csum.hpp | 386 ++++ .../cppad/local/optimize/record_pv.hpp | 102 + .../cppad/local/optimize/record_vp.hpp | 101 + .../cppad/local/optimize/record_vv.hpp | 91 + .../cppad/local/optimize/size_pair.hpp | 32 + .../include/cppad/local/optimize/usage.hpp | 39 + .../include/cppad/local/parameter_op.hpp | 89 + .../include/cppad/local/play/addr_enum.hpp | 30 + .../include/cppad/local/play/atom_op_info.hpp | 89 + .../cppad/include/cppad/local/play/player.hpp | 853 ++++++++ .../cppad/local/play/random_iterator.hpp | 152 ++ .../include/cppad/local/play/random_setup.hpp | 144 ++ .../cppad/local/play/sequential_iterator.hpp | 290 +++ .../cppad/local/play/subgraph_iterator.hpp | 132 ++ .../cppad/include/cppad/local/pod_vector.hpp | 565 ++++++ .../cppad/include/cppad/local/pow_op.hpp | 672 +++++++ .../cppad/include/cppad/local/print_op.hpp | 147 ++ .../include/cppad/local/prototype_op.hpp | 1458 ++++++++++++++ .../include/cppad/local/record/comp_op.hpp | 287 +++ .../include/cppad/local/record/cond_exp.hpp | 176 ++ .../cppad/local/record/put_dyn_atomic.hpp | 169 ++ .../cppad/local/record/put_var_atomic.hpp | 150 ++ .../cppad/local/record/put_var_vecad.hpp | 130 ++ .../include/cppad/local/record/recorder.hpp | 848 ++++++++ .../include/cppad/local/record/recorder.omh | 25 + .../cppad/local/set_get_in_parallel.hpp | 66 + .../cppad/include/cppad/local/sign_op.hpp | 153 ++ .../cppad/include/cppad/local/sin_op.hpp | 240 +++ .../cppad/include/cppad/local/sinh_op.hpp | 239 +++ .../include/cppad/local/sparse/binary_op.hpp | 617 ++++++ .../include/cppad/local/sparse/dev_sparse.omh | 23 + .../include/cppad/local/sparse/internal.hpp | 455 +++++ .../cppad/local/sparse/list_setvec.hpp | 1721 +++++++++++++++++ .../cppad/local/sparse/list_setvec.omh | 32 + .../cppad/local/sparse/pack_setvec.hpp | 910 +++++++++ .../cppad/local/sparse/pack_setvec.omh | 32 + .../include/cppad/local/sparse/setvector.omh | 254 +++ .../cppad/local/sparse/svec_setvec.hpp | 1506 +++++++++++++++ .../include/cppad/local/sparse/unary_op.hpp | 317 +++ .../cppad/include/cppad/local/sqrt_op.hpp | 193 ++ .../cppad/include/cppad/local/std_set.hpp | 52 + .../cppad/include/cppad/local/store_op.hpp | 489 +++++ .../cppad/include/cppad/local/sub_op.hpp | 500 +++++ .../cppad/local/subgraph/arg_variable.hpp | 112 ++ .../cppad/local/subgraph/entire_call.hpp | 76 + .../include/cppad/local/subgraph/get_rev.hpp | 165 ++ .../include/cppad/local/subgraph/info.hpp | 334 ++++ .../include/cppad/local/subgraph/init_rev.hpp | 225 +++ .../include/cppad/local/subgraph/sparsity.hpp | 191 ++ .../include/cppad/local/sweep/call_atomic.hpp | 902 +++++++++ .../include/cppad/local/sweep/dev_sweep.omh | 24 + .../include/cppad/local/sweep/dynamic.hpp | 549 ++++++ .../include/cppad/local/sweep/for_hes.hpp | 670 +++++++ .../include/cppad/local/sweep/for_jac.hpp | 836 ++++++++ .../include/cppad/local/sweep/forward0.hpp | 995 ++++++++++ .../include/cppad/local/sweep/forward1.hpp | 1086 +++++++++++ .../include/cppad/local/sweep/forward2.hpp | 786 ++++++++ .../include/cppad/local/sweep/rev_hes.hpp | 802 ++++++++ .../include/cppad/local/sweep/rev_jac.hpp | 815 ++++++++ .../include/cppad/local/sweep/reverse.hpp | 809 ++++++++ .../cppad/include/cppad/local/tan_op.hpp | 231 +++ .../cppad/include/cppad/local/tanh_op.hpp | 230 +++ .../cppad/local/utility/cppad_vector_itr.hpp | 444 +++++ .../cppad/local/utility/vector_bool.hpp | 84 + .../cppad/include/cppad/local/zmul_op.hpp | 517 +++++ .../cppad/include/cppad/speed/det_33.hpp | 113 ++ .../cppad/include/cppad/speed/det_by_lu.hpp | 182 ++ .../include/cppad/speed/det_by_minor.hpp | 165 ++ .../cppad/include/cppad/speed/det_grad_33.hpp | 127 ++ .../include/cppad/speed/det_of_minor.hpp | 274 +++ .../cppad/include/cppad/speed/mat_sum_sq.hpp | 152 ++ .../include/cppad/speed/ode_evaluate.hpp | 236 +++ .../include/cppad/speed/sparse_hes_fun.hpp | 265 +++ .../include/cppad/speed/sparse_jac_fun.hpp | 219 +++ .../cppad/include/cppad/speed/uniform_01.hpp | 103 + build-config/cppad/include/cppad/utility.hpp | 52 + .../cppad/utility/check_numeric_type.hpp | 174 ++ .../cppad/utility/check_simple_vector.hpp | 199 ++ .../include/cppad/utility/elapsed_seconds.hpp | 121 ++ .../include/cppad/utility/error_handler.hpp | 235 +++ .../include/cppad/utility/index_sort.hpp | 177 ++ .../cppad/include/cppad/utility/lu_factor.hpp | 392 ++++ .../cppad/include/cppad/utility/lu_invert.hpp | 238 +++ .../cppad/include/cppad/utility/lu_solve.hpp | 345 ++++ .../include/cppad/utility/memory_leak.hpp | 213 ++ .../cppad/include/cppad/utility/nan.hpp | 193 ++ .../include/cppad/utility/near_equal.hpp | 271 +++ .../include/cppad/utility/ode_err_control.hpp | 598 ++++++ .../cppad/include/cppad/utility/ode_gear.hpp | 521 +++++ .../cppad/utility/ode_gear_control.hpp | 544 ++++++ .../cppad/utility/omh/cppad_vector.omh | 408 ++++ .../cppad/utility/omh/dev_cppad_vector.omh | 29 + .../include/cppad/utility/omh/dev_utility.omh | 25 + .../cppad/utility/omh/dev_vector_bool.omh | 30 + .../include/cppad/utility/omh/utility.omh | 156 ++ .../cppad/include/cppad/utility/omp_alloc.hpp | 747 +++++++ .../cppad/include/cppad/utility/poly.hpp | 192 ++ .../cppad/include/cppad/utility/pow_int.hpp | 140 ++ .../include/cppad/utility/romberg_mul.hpp | 325 ++++ .../include/cppad/utility/romberg_one.hpp | 213 ++ .../cppad/include/cppad/utility/rosen_34.hpp | 497 +++++ .../cppad/include/cppad/utility/runge_45.hpp | 427 ++++ .../cppad/include/cppad/utility/set_union.hpp | 91 + .../include/cppad/utility/sparse2eigen.hpp | 138 ++ .../cppad/include/cppad/utility/sparse_rc.hpp | 380 ++++ .../include/cppad/utility/sparse_rcv.hpp | 315 +++ .../include/cppad/utility/speed_test.hpp | 477 +++++ .../include/cppad/utility/test_boolofvoid.hpp | 172 ++ .../include/cppad/utility/thread_alloc.hpp | 1515 +++++++++++++++ .../cppad/include/cppad/utility/time_test.hpp | 300 +++ .../cppad/include/cppad/utility/to_string.hpp | 172 ++ .../include/cppad/utility/track_new_del.hpp | 533 +++++ .../cppad/include/cppad/utility/vector.hpp | 543 ++++++ .../include/cppad/utility/vector_bool.hpp | 521 +++++ .../cppad/include/cppad/wno_conversion.hpp | 45 + build-config/cppad/include/makefile.am | 348 ++++ build-config/cppad/include/makefile.in | 941 +++++++++ build-config/cppad/meson.build | 5 + build-config/cppad/readme.md | 50 + build-config/cppad/version | 2 + 367 files changed, 108392 insertions(+) create mode 100644 build-config/cppad/COPYING create mode 100644 build-config/cppad/include/cppad/CMakeLists.txt create mode 100644 build-config/cppad/include/cppad/base_require.hpp create mode 100644 build-config/cppad/include/cppad/configure.hpp create mode 100644 build-config/cppad/include/cppad/configure.hpp.in create mode 100644 build-config/cppad/include/cppad/core/abort_recording.hpp create mode 100644 build-config/cppad/include/cppad/core/abs.hpp create mode 100644 build-config/cppad/include/cppad/core/abs_normal_fun.hpp create mode 100644 build-config/cppad/include/cppad/core/ad.hpp create mode 100644 build-config/cppad/include/cppad/core/ad_assign.hpp create mode 100644 build-config/cppad/include/cppad/core/ad_binary.hpp create mode 100644 build-config/cppad/include/cppad/core/ad_ctor.hpp create mode 100644 build-config/cppad/include/cppad/core/ad_fun.hpp create mode 100644 build-config/cppad/include/cppad/core/ad_io.hpp create mode 100644 build-config/cppad/include/cppad/core/ad_to_string.hpp create mode 100644 build-config/cppad/include/cppad/core/ad_type.hpp create mode 100644 build-config/cppad/include/cppad/core/ad_valued.hpp create mode 100644 build-config/cppad/include/cppad/core/add.hpp create mode 100644 build-config/cppad/include/cppad/core/add_eq.hpp create mode 100644 build-config/cppad/include/cppad/core/arithmetic.hpp create mode 100644 build-config/cppad/include/cppad/core/atan2.hpp create mode 100644 build-config/cppad/include/cppad/core/atomic/atomic.omh create mode 100644 build-config/cppad/include/cppad/core/atomic/atomic_one.hpp create mode 100644 build-config/cppad/include/cppad/core/atomic/atomic_three.hpp create mode 100644 build-config/cppad/include/cppad/core/atomic/atomic_two.hpp create mode 100644 build-config/cppad/include/cppad/core/atomic/three_afun.hpp create mode 100644 build-config/cppad/include/cppad/core/atomic/three_ctor.hpp create mode 100644 build-config/cppad/include/cppad/core/atomic/three_for_type.hpp create mode 100644 build-config/cppad/include/cppad/core/atomic/three_forward.hpp create mode 100644 build-config/cppad/include/cppad/core/atomic/three_hes_sparsity.hpp create mode 100644 build-config/cppad/include/cppad/core/atomic/three_jac_sparsity.hpp create mode 100644 build-config/cppad/include/cppad/core/atomic/three_rev_depend.hpp create mode 100644 build-config/cppad/include/cppad/core/atomic/three_reverse.hpp create mode 100644 build-config/cppad/include/cppad/core/atomic/two_afun.hpp create mode 100644 build-config/cppad/include/cppad/core/atomic/two_clear.hpp create mode 100644 build-config/cppad/include/cppad/core/atomic/two_ctor.hpp create mode 100644 build-config/cppad/include/cppad/core/atomic/two_for_sparse_hes.hpp create mode 100644 build-config/cppad/include/cppad/core/atomic/two_for_sparse_jac.hpp create mode 100644 build-config/cppad/include/cppad/core/atomic/two_forward.hpp create mode 100644 build-config/cppad/include/cppad/core/atomic/two_option.hpp create mode 100644 build-config/cppad/include/cppad/core/atomic/two_rev_depend.hpp create mode 100644 build-config/cppad/include/cppad/core/atomic/two_rev_sparse_hes.hpp create mode 100644 build-config/cppad/include/cppad/core/atomic/two_rev_sparse_jac.hpp create mode 100644 build-config/cppad/include/cppad/core/atomic/two_reverse.hpp create mode 100644 build-config/cppad/include/cppad/core/azmul.hpp create mode 100644 build-config/cppad/include/cppad/core/base2ad.hpp create mode 100644 build-config/cppad/include/cppad/core/base_complex.hpp create mode 100644 build-config/cppad/include/cppad/core/base_cond_exp.hpp create mode 100644 build-config/cppad/include/cppad/core/base_double.hpp create mode 100644 build-config/cppad/include/cppad/core/base_float.hpp create mode 100644 build-config/cppad/include/cppad/core/base_hash.hpp create mode 100644 build-config/cppad/include/cppad/core/base_limits.hpp create mode 100644 build-config/cppad/include/cppad/core/base_std_math.hpp create mode 100644 build-config/cppad/include/cppad/core/base_to_string.hpp create mode 100644 build-config/cppad/include/cppad/core/bender_quad.hpp create mode 100644 build-config/cppad/include/cppad/core/bool_fun.hpp create mode 100644 build-config/cppad/include/cppad/core/bool_valued.hpp create mode 100644 build-config/cppad/include/cppad/core/capacity_order.hpp create mode 100644 build-config/cppad/include/cppad/core/check_for_nan.hpp create mode 100644 build-config/cppad/include/cppad/core/chkpoint_one/chkpoint_one.hpp create mode 100644 build-config/cppad/include/cppad/core/chkpoint_one/ctor.hpp create mode 100644 build-config/cppad/include/cppad/core/chkpoint_one/for_sparse_jac.hpp create mode 100644 build-config/cppad/include/cppad/core/chkpoint_one/forward.hpp create mode 100644 build-config/cppad/include/cppad/core/chkpoint_one/rev_sparse_hes.hpp create mode 100644 build-config/cppad/include/cppad/core/chkpoint_one/rev_sparse_jac.hpp create mode 100644 build-config/cppad/include/cppad/core/chkpoint_one/reverse.hpp create mode 100644 build-config/cppad/include/cppad/core/chkpoint_one/set_hes_sparse_bool.hpp create mode 100644 build-config/cppad/include/cppad/core/chkpoint_one/set_hes_sparse_set.hpp create mode 100644 build-config/cppad/include/cppad/core/chkpoint_one/set_jac_sparse_bool.hpp create mode 100644 build-config/cppad/include/cppad/core/chkpoint_one/set_jac_sparse_set.hpp create mode 100644 build-config/cppad/include/cppad/core/chkpoint_two/chk_fun.omh create mode 100644 build-config/cppad/include/cppad/core/chkpoint_two/chkpoint_two.hpp create mode 100644 build-config/cppad/include/cppad/core/chkpoint_two/ctor.hpp create mode 100644 build-config/cppad/include/cppad/core/chkpoint_two/dynamic.hpp create mode 100644 build-config/cppad/include/cppad/core/chkpoint_two/for_type.hpp create mode 100644 build-config/cppad/include/cppad/core/chkpoint_two/forward.hpp create mode 100644 build-config/cppad/include/cppad/core/chkpoint_two/hes_sparsity.hpp create mode 100644 build-config/cppad/include/cppad/core/chkpoint_two/jac_sparsity.hpp create mode 100644 build-config/cppad/include/cppad/core/chkpoint_two/rev_depend.hpp create mode 100644 build-config/cppad/include/cppad/core/chkpoint_two/reverse.hpp create mode 100644 build-config/cppad/include/cppad/core/compare.hpp create mode 100644 build-config/cppad/include/cppad/core/compound_assign.hpp create mode 100644 build-config/cppad/include/cppad/core/con_dyn_var.hpp create mode 100644 build-config/cppad/include/cppad/core/cond_exp.hpp create mode 100644 build-config/cppad/include/cppad/core/convert.hpp create mode 100644 build-config/cppad/include/cppad/core/cppad_assert.hpp create mode 100644 build-config/cppad/include/cppad/core/dependent.hpp create mode 100644 build-config/cppad/include/cppad/core/discrete/devel.omh create mode 100644 build-config/cppad/include/cppad/core/discrete/discrete.hpp create mode 100644 build-config/cppad/include/cppad/core/discrete/user.omh create mode 100644 build-config/cppad/include/cppad/core/div.hpp create mode 100644 build-config/cppad/include/cppad/core/div_eq.hpp create mode 100644 build-config/cppad/include/cppad/core/drivers.hpp create mode 100644 build-config/cppad/include/cppad/core/epsilon.hpp create mode 100644 build-config/cppad/include/cppad/core/equal_op_seq.hpp create mode 100644 build-config/cppad/include/cppad/core/for_hes_sparsity.hpp create mode 100644 build-config/cppad/include/cppad/core/for_jac_sparsity.hpp create mode 100644 build-config/cppad/include/cppad/core/for_one.hpp create mode 100644 build-config/cppad/include/cppad/core/for_sparse_hes.hpp create mode 100644 build-config/cppad/include/cppad/core/for_sparse_jac.hpp create mode 100644 build-config/cppad/include/cppad/core/for_two.hpp create mode 100644 build-config/cppad/include/cppad/core/forward/compare_change.omh create mode 100644 build-config/cppad/include/cppad/core/forward/devel.omh create mode 100644 build-config/cppad/include/cppad/core/forward/forward.hpp create mode 100644 build-config/cppad/include/cppad/core/forward/forward.omh create mode 100644 build-config/cppad/include/cppad/core/forward/forward_dir.omh create mode 100644 build-config/cppad/include/cppad/core/forward/forward_one.omh create mode 100644 build-config/cppad/include/cppad/core/forward/forward_order.omh create mode 100644 build-config/cppad/include/cppad/core/forward/forward_two.omh create mode 100644 build-config/cppad/include/cppad/core/forward/forward_zero.omh create mode 100644 build-config/cppad/include/cppad/core/forward/size_order.omh create mode 100644 build-config/cppad/include/cppad/core/fun_check.hpp create mode 100644 build-config/cppad/include/cppad/core/fun_construct.hpp create mode 100644 build-config/cppad/include/cppad/core/fun_eval.hpp create mode 100644 build-config/cppad/include/cppad/core/graph/cpp_ad_graph.omh create mode 100644 build-config/cppad/include/cppad/core/graph/cpp_graph.hpp create mode 100644 build-config/cppad/include/cppad/core/graph/cpp_graph.omh create mode 100644 build-config/cppad/include/cppad/core/graph/from_graph.hpp create mode 100644 build-config/cppad/include/cppad/core/graph/from_json.hpp create mode 100644 build-config/cppad/include/cppad/core/graph/graph_op_enum.hpp create mode 100644 build-config/cppad/include/cppad/core/graph/json_ad_graph.omh create mode 100644 build-config/cppad/include/cppad/core/graph/json_graph_op.omh create mode 100644 build-config/cppad/include/cppad/core/graph/to_graph.hpp create mode 100644 build-config/cppad/include/cppad/core/graph/to_json.hpp create mode 100644 build-config/cppad/include/cppad/core/hash_code.hpp create mode 100644 build-config/cppad/include/cppad/core/hessian.hpp create mode 100644 build-config/cppad/include/cppad/core/identical.hpp create mode 100644 build-config/cppad/include/cppad/core/independent/devel.omh create mode 100644 build-config/cppad/include/cppad/core/independent/independent.hpp create mode 100644 build-config/cppad/include/cppad/core/independent/user.omh create mode 100644 build-config/cppad/include/cppad/core/integer.hpp create mode 100644 build-config/cppad/include/cppad/core/jacobian.hpp create mode 100644 build-config/cppad/include/cppad/core/lu_ratio.hpp create mode 100644 build-config/cppad/include/cppad/core/mul.hpp create mode 100644 build-config/cppad/include/cppad/core/mul_eq.hpp create mode 100644 build-config/cppad/include/cppad/core/near_equal_ext.hpp create mode 100644 build-config/cppad/include/cppad/core/new_dynamic.hpp create mode 100644 build-config/cppad/include/cppad/core/num_skip.hpp create mode 100644 build-config/cppad/include/cppad/core/numeric_limits.hpp create mode 100644 build-config/cppad/include/cppad/core/omp_max_thread.hpp create mode 100644 build-config/cppad/include/cppad/core/opt_val_hes.hpp create mode 100644 build-config/cppad/include/cppad/core/optimize.hpp create mode 100644 build-config/cppad/include/cppad/core/ordered.hpp create mode 100644 build-config/cppad/include/cppad/core/parallel_ad.hpp create mode 100644 build-config/cppad/include/cppad/core/pow.hpp create mode 100644 build-config/cppad/include/cppad/core/print_for.hpp create mode 100644 build-config/cppad/include/cppad/core/rev_hes_sparsity.hpp create mode 100644 build-config/cppad/include/cppad/core/rev_jac_sparsity.hpp create mode 100644 build-config/cppad/include/cppad/core/rev_one.hpp create mode 100644 build-config/cppad/include/cppad/core/rev_sparse_hes.hpp create mode 100644 build-config/cppad/include/cppad/core/rev_sparse_jac.hpp create mode 100644 build-config/cppad/include/cppad/core/rev_two.hpp create mode 100644 build-config/cppad/include/cppad/core/reverse.hpp create mode 100644 build-config/cppad/include/cppad/core/sign.hpp create mode 100644 build-config/cppad/include/cppad/core/sparse.hpp create mode 100644 build-config/cppad/include/cppad/core/sparse_hes.hpp create mode 100644 build-config/cppad/include/cppad/core/sparse_hessian.hpp create mode 100644 build-config/cppad/include/cppad/core/sparse_jac.hpp create mode 100644 build-config/cppad/include/cppad/core/sparse_jacobian.hpp create mode 100644 build-config/cppad/include/cppad/core/standard_math.hpp create mode 100644 build-config/cppad/include/cppad/core/std_math_11.hpp create mode 100644 build-config/cppad/include/cppad/core/sub.hpp create mode 100644 build-config/cppad/include/cppad/core/sub_eq.hpp create mode 100644 build-config/cppad/include/cppad/core/subgraph_jac_rev.hpp create mode 100644 build-config/cppad/include/cppad/core/subgraph_reverse.hpp create mode 100644 build-config/cppad/include/cppad/core/subgraph_sparsity.hpp create mode 100644 build-config/cppad/include/cppad/core/tape_link.hpp create mode 100644 build-config/cppad/include/cppad/core/test_vector.hpp create mode 100644 build-config/cppad/include/cppad/core/testvector.hpp create mode 100644 build-config/cppad/include/cppad/core/unary_minus.hpp create mode 100644 build-config/cppad/include/cppad/core/unary_plus.hpp create mode 100644 build-config/cppad/include/cppad/core/undef.hpp create mode 100644 build-config/cppad/include/cppad/core/user_ad.hpp create mode 100644 build-config/cppad/include/cppad/core/value.hpp create mode 100644 build-config/cppad/include/cppad/core/var2par.hpp create mode 100644 build-config/cppad/include/cppad/core/vec_ad/user.omh create mode 100644 build-config/cppad/include/cppad/core/vec_ad/vec_ad.hpp create mode 100644 build-config/cppad/include/cppad/core/zdouble.hpp create mode 100644 build-config/cppad/include/cppad/cppad.hpp create mode 100644 build-config/cppad/include/cppad/example/atomic_three/mat_mul.hpp create mode 100644 build-config/cppad/include/cppad/example/atomic_two/eigen_cholesky.hpp create mode 100644 build-config/cppad/include/cppad/example/atomic_two/eigen_mat_inv.hpp create mode 100644 build-config/cppad/include/cppad/example/atomic_two/eigen_mat_mul.hpp create mode 100644 build-config/cppad/include/cppad/example/base_adolc.hpp create mode 100644 build-config/cppad/include/cppad/example/code_gen_fun.hpp create mode 100644 build-config/cppad/include/cppad/example/cppad_eigen.hpp create mode 100644 build-config/cppad/include/cppad/example/eigen_plugin.hpp create mode 100644 build-config/cppad/include/cppad/ipopt/solve.hpp create mode 100644 build-config/cppad/include/cppad/ipopt/solve_callback.hpp create mode 100644 build-config/cppad/include/cppad/ipopt/solve_result.hpp create mode 100644 build-config/cppad/include/cppad/local/abs_op.hpp create mode 100644 build-config/cppad/include/cppad/local/acos_op.hpp create mode 100644 build-config/cppad/include/cppad/local/acosh_op.hpp create mode 100644 build-config/cppad/include/cppad/local/ad_tape.hpp create mode 100644 build-config/cppad/include/cppad/local/add_op.hpp create mode 100644 build-config/cppad/include/cppad/local/asin_op.hpp create mode 100644 build-config/cppad/include/cppad/local/asinh_op.hpp create mode 100644 build-config/cppad/include/cppad/local/atan_op.hpp create mode 100644 build-config/cppad/include/cppad/local/atanh_op.hpp create mode 100644 build-config/cppad/include/cppad/local/atom_state.hpp create mode 100644 build-config/cppad/include/cppad/local/atomic_index.hpp create mode 100644 build-config/cppad/include/cppad/local/color_general.hpp create mode 100644 build-config/cppad/include/cppad/local/color_symmetric.hpp create mode 100644 build-config/cppad/include/cppad/local/comp_op.hpp create mode 100644 build-config/cppad/include/cppad/local/cond_op.hpp create mode 100644 build-config/cppad/include/cppad/local/cos_op.hpp create mode 100644 build-config/cppad/include/cppad/local/cosh_op.hpp create mode 100644 build-config/cppad/include/cppad/local/cppad_colpack.hpp create mode 100644 build-config/cppad/include/cppad/local/cskip_op.hpp create mode 100644 build-config/cppad/include/cppad/local/csum_op.hpp create mode 100644 build-config/cppad/include/cppad/local/declare_ad.hpp create mode 100644 build-config/cppad/include/cppad/local/define.hpp create mode 100644 build-config/cppad/include/cppad/local/discrete_op.hpp create mode 100644 build-config/cppad/include/cppad/local/div_op.hpp create mode 100644 build-config/cppad/include/cppad/local/erf_op.hpp create mode 100644 build-config/cppad/include/cppad/local/exp_op.hpp create mode 100644 build-config/cppad/include/cppad/local/expm1_op.hpp create mode 100644 build-config/cppad/include/cppad/local/graph/cpp_graph_itr.hpp create mode 100644 build-config/cppad/include/cppad/local/graph/cpp_graph_itr.omh create mode 100644 build-config/cppad/include/cppad/local/graph/cpp_graph_op.hpp create mode 100644 build-config/cppad/include/cppad/local/graph/dev_graph.omh create mode 100644 build-config/cppad/include/cppad/local/graph/json_lexer.hpp create mode 100644 build-config/cppad/include/cppad/local/graph/json_lexer.omh create mode 100644 build-config/cppad/include/cppad/local/graph/json_parser.hpp create mode 100644 build-config/cppad/include/cppad/local/graph/json_writer.hpp create mode 100644 build-config/cppad/include/cppad/local/hash_code.hpp create mode 100644 build-config/cppad/include/cppad/local/independent.hpp create mode 100644 build-config/cppad/include/cppad/local/is_pod.hpp create mode 100644 build-config/cppad/include/cppad/local/is_pod.hpp.in create mode 100644 build-config/cppad/include/cppad/local/load_op.hpp create mode 100644 build-config/cppad/include/cppad/local/log1p_op.hpp create mode 100644 build-config/cppad/include/cppad/local/log_op.hpp create mode 100644 build-config/cppad/include/cppad/local/mul_op.hpp create mode 100644 build-config/cppad/include/cppad/local/op.hpp create mode 100644 build-config/cppad/include/cppad/local/op_code_dyn.hpp create mode 100644 build-config/cppad/include/cppad/local/op_code_var.hpp create mode 100644 build-config/cppad/include/cppad/local/optimize/cexp_info.hpp create mode 100644 build-config/cppad/include/cppad/local/optimize/csum_op_info.hpp create mode 100644 build-config/cppad/include/cppad/local/optimize/csum_stacks.hpp create mode 100644 build-config/cppad/include/cppad/local/optimize/get_cexp_info.hpp create mode 100644 build-config/cppad/include/cppad/local/optimize/get_dyn_previous.hpp create mode 100644 build-config/cppad/include/cppad/local/optimize/get_op_previous.hpp create mode 100644 build-config/cppad/include/cppad/local/optimize/get_op_usage.hpp create mode 100644 build-config/cppad/include/cppad/local/optimize/get_par_usage.hpp create mode 100644 build-config/cppad/include/cppad/local/optimize/hash_code.hpp create mode 100644 build-config/cppad/include/cppad/local/optimize/match_op.hpp create mode 100644 build-config/cppad/include/cppad/local/optimize/optimize_run.hpp create mode 100644 build-config/cppad/include/cppad/local/optimize/record_csum.hpp create mode 100644 build-config/cppad/include/cppad/local/optimize/record_pv.hpp create mode 100644 build-config/cppad/include/cppad/local/optimize/record_vp.hpp create mode 100644 build-config/cppad/include/cppad/local/optimize/record_vv.hpp create mode 100644 build-config/cppad/include/cppad/local/optimize/size_pair.hpp create mode 100644 build-config/cppad/include/cppad/local/optimize/usage.hpp create mode 100644 build-config/cppad/include/cppad/local/parameter_op.hpp create mode 100644 build-config/cppad/include/cppad/local/play/addr_enum.hpp create mode 100644 build-config/cppad/include/cppad/local/play/atom_op_info.hpp create mode 100644 build-config/cppad/include/cppad/local/play/player.hpp create mode 100644 build-config/cppad/include/cppad/local/play/random_iterator.hpp create mode 100644 build-config/cppad/include/cppad/local/play/random_setup.hpp create mode 100644 build-config/cppad/include/cppad/local/play/sequential_iterator.hpp create mode 100644 build-config/cppad/include/cppad/local/play/subgraph_iterator.hpp create mode 100644 build-config/cppad/include/cppad/local/pod_vector.hpp create mode 100644 build-config/cppad/include/cppad/local/pow_op.hpp create mode 100644 build-config/cppad/include/cppad/local/print_op.hpp create mode 100644 build-config/cppad/include/cppad/local/prototype_op.hpp create mode 100644 build-config/cppad/include/cppad/local/record/comp_op.hpp create mode 100644 build-config/cppad/include/cppad/local/record/cond_exp.hpp create mode 100644 build-config/cppad/include/cppad/local/record/put_dyn_atomic.hpp create mode 100644 build-config/cppad/include/cppad/local/record/put_var_atomic.hpp create mode 100644 build-config/cppad/include/cppad/local/record/put_var_vecad.hpp create mode 100644 build-config/cppad/include/cppad/local/record/recorder.hpp create mode 100644 build-config/cppad/include/cppad/local/record/recorder.omh create mode 100644 build-config/cppad/include/cppad/local/set_get_in_parallel.hpp create mode 100644 build-config/cppad/include/cppad/local/sign_op.hpp create mode 100644 build-config/cppad/include/cppad/local/sin_op.hpp create mode 100644 build-config/cppad/include/cppad/local/sinh_op.hpp create mode 100644 build-config/cppad/include/cppad/local/sparse/binary_op.hpp create mode 100644 build-config/cppad/include/cppad/local/sparse/dev_sparse.omh create mode 100644 build-config/cppad/include/cppad/local/sparse/internal.hpp create mode 100644 build-config/cppad/include/cppad/local/sparse/list_setvec.hpp create mode 100644 build-config/cppad/include/cppad/local/sparse/list_setvec.omh create mode 100644 build-config/cppad/include/cppad/local/sparse/pack_setvec.hpp create mode 100644 build-config/cppad/include/cppad/local/sparse/pack_setvec.omh create mode 100644 build-config/cppad/include/cppad/local/sparse/setvector.omh create mode 100644 build-config/cppad/include/cppad/local/sparse/svec_setvec.hpp create mode 100644 build-config/cppad/include/cppad/local/sparse/unary_op.hpp create mode 100644 build-config/cppad/include/cppad/local/sqrt_op.hpp create mode 100644 build-config/cppad/include/cppad/local/std_set.hpp create mode 100644 build-config/cppad/include/cppad/local/store_op.hpp create mode 100644 build-config/cppad/include/cppad/local/sub_op.hpp create mode 100644 build-config/cppad/include/cppad/local/subgraph/arg_variable.hpp create mode 100644 build-config/cppad/include/cppad/local/subgraph/entire_call.hpp create mode 100644 build-config/cppad/include/cppad/local/subgraph/get_rev.hpp create mode 100644 build-config/cppad/include/cppad/local/subgraph/info.hpp create mode 100644 build-config/cppad/include/cppad/local/subgraph/init_rev.hpp create mode 100644 build-config/cppad/include/cppad/local/subgraph/sparsity.hpp create mode 100644 build-config/cppad/include/cppad/local/sweep/call_atomic.hpp create mode 100644 build-config/cppad/include/cppad/local/sweep/dev_sweep.omh create mode 100644 build-config/cppad/include/cppad/local/sweep/dynamic.hpp create mode 100644 build-config/cppad/include/cppad/local/sweep/for_hes.hpp create mode 100644 build-config/cppad/include/cppad/local/sweep/for_jac.hpp create mode 100644 build-config/cppad/include/cppad/local/sweep/forward0.hpp create mode 100644 build-config/cppad/include/cppad/local/sweep/forward1.hpp create mode 100644 build-config/cppad/include/cppad/local/sweep/forward2.hpp create mode 100644 build-config/cppad/include/cppad/local/sweep/rev_hes.hpp create mode 100644 build-config/cppad/include/cppad/local/sweep/rev_jac.hpp create mode 100644 build-config/cppad/include/cppad/local/sweep/reverse.hpp create mode 100644 build-config/cppad/include/cppad/local/tan_op.hpp create mode 100644 build-config/cppad/include/cppad/local/tanh_op.hpp create mode 100644 build-config/cppad/include/cppad/local/utility/cppad_vector_itr.hpp create mode 100644 build-config/cppad/include/cppad/local/utility/vector_bool.hpp create mode 100644 build-config/cppad/include/cppad/local/zmul_op.hpp create mode 100644 build-config/cppad/include/cppad/speed/det_33.hpp create mode 100644 build-config/cppad/include/cppad/speed/det_by_lu.hpp create mode 100644 build-config/cppad/include/cppad/speed/det_by_minor.hpp create mode 100644 build-config/cppad/include/cppad/speed/det_grad_33.hpp create mode 100644 build-config/cppad/include/cppad/speed/det_of_minor.hpp create mode 100644 build-config/cppad/include/cppad/speed/mat_sum_sq.hpp create mode 100644 build-config/cppad/include/cppad/speed/ode_evaluate.hpp create mode 100644 build-config/cppad/include/cppad/speed/sparse_hes_fun.hpp create mode 100644 build-config/cppad/include/cppad/speed/sparse_jac_fun.hpp create mode 100644 build-config/cppad/include/cppad/speed/uniform_01.hpp create mode 100644 build-config/cppad/include/cppad/utility.hpp create mode 100644 build-config/cppad/include/cppad/utility/check_numeric_type.hpp create mode 100644 build-config/cppad/include/cppad/utility/check_simple_vector.hpp create mode 100644 build-config/cppad/include/cppad/utility/elapsed_seconds.hpp create mode 100644 build-config/cppad/include/cppad/utility/error_handler.hpp create mode 100644 build-config/cppad/include/cppad/utility/index_sort.hpp create mode 100644 build-config/cppad/include/cppad/utility/lu_factor.hpp create mode 100644 build-config/cppad/include/cppad/utility/lu_invert.hpp create mode 100644 build-config/cppad/include/cppad/utility/lu_solve.hpp create mode 100644 build-config/cppad/include/cppad/utility/memory_leak.hpp create mode 100644 build-config/cppad/include/cppad/utility/nan.hpp create mode 100644 build-config/cppad/include/cppad/utility/near_equal.hpp create mode 100644 build-config/cppad/include/cppad/utility/ode_err_control.hpp create mode 100644 build-config/cppad/include/cppad/utility/ode_gear.hpp create mode 100644 build-config/cppad/include/cppad/utility/ode_gear_control.hpp create mode 100644 build-config/cppad/include/cppad/utility/omh/cppad_vector.omh create mode 100644 build-config/cppad/include/cppad/utility/omh/dev_cppad_vector.omh create mode 100644 build-config/cppad/include/cppad/utility/omh/dev_utility.omh create mode 100644 build-config/cppad/include/cppad/utility/omh/dev_vector_bool.omh create mode 100644 build-config/cppad/include/cppad/utility/omh/utility.omh create mode 100644 build-config/cppad/include/cppad/utility/omp_alloc.hpp create mode 100644 build-config/cppad/include/cppad/utility/poly.hpp create mode 100644 build-config/cppad/include/cppad/utility/pow_int.hpp create mode 100644 build-config/cppad/include/cppad/utility/romberg_mul.hpp create mode 100644 build-config/cppad/include/cppad/utility/romberg_one.hpp create mode 100644 build-config/cppad/include/cppad/utility/rosen_34.hpp create mode 100644 build-config/cppad/include/cppad/utility/runge_45.hpp create mode 100644 build-config/cppad/include/cppad/utility/set_union.hpp create mode 100644 build-config/cppad/include/cppad/utility/sparse2eigen.hpp create mode 100644 build-config/cppad/include/cppad/utility/sparse_rc.hpp create mode 100644 build-config/cppad/include/cppad/utility/sparse_rcv.hpp create mode 100644 build-config/cppad/include/cppad/utility/speed_test.hpp create mode 100644 build-config/cppad/include/cppad/utility/test_boolofvoid.hpp create mode 100644 build-config/cppad/include/cppad/utility/thread_alloc.hpp create mode 100644 build-config/cppad/include/cppad/utility/time_test.hpp create mode 100644 build-config/cppad/include/cppad/utility/to_string.hpp create mode 100644 build-config/cppad/include/cppad/utility/track_new_del.hpp create mode 100644 build-config/cppad/include/cppad/utility/vector.hpp create mode 100644 build-config/cppad/include/cppad/utility/vector_bool.hpp create mode 100644 build-config/cppad/include/cppad/wno_conversion.hpp create mode 100644 build-config/cppad/include/makefile.am create mode 100644 build-config/cppad/include/makefile.in create mode 100644 build-config/cppad/meson.build create mode 100644 build-config/cppad/readme.md create mode 100644 build-config/cppad/version diff --git a/build-config/cppad/COPYING b/build-config/cppad/COPYING new file mode 100644 index 00000000..bfb3d7bb --- /dev/null +++ b/build-config/cppad/COPYING @@ -0,0 +1,11 @@ +----------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-18 Bradley M. Bell + + CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + + This Source Code may also be made available under the following + Secondary License when the conditions for such availability set forth + in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +----------------------------------------------------------------------------- diff --git a/build-config/cppad/include/cppad/CMakeLists.txt b/build-config/cppad/include/cppad/CMakeLists.txt new file mode 100644 index 00000000..7c5e6f3e --- /dev/null +++ b/build-config/cppad/include/cppad/CMakeLists.txt @@ -0,0 +1,184 @@ +# ----------------------------------------------------------------------------- +# CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell +# +# CppAD is distributed under the terms of the +# Eclipse Public License Version 2.0. +# +# This Source Code may also be made available under the following +# Secondary License when the conditions for such availability set forth +# in the Eclipse Public License, Version 2.0 are satisfied: +# GNU General Public License, Version 2.0 or later. +# ----------------------------------------------------------------------------- +# Configure the CppAD include file directory +# ----------------------------------------------------------------------------- +# check_match +MACRO(check_match match_variable match_constant output_variable) + STRING(COMPARE EQUAL ${${match_variable}} ${match_constant} match_flag ) + IF( match_flag ) + SET(${output_variable} 1) + ELSE( match_flag ) + SET(${output_variable} 0) + ENDIF( match_flag ) + print_variable(${output_variable}) +ENDMACRO(check_match) +# ----------------------------------------------------------------------------- +# compiler_has_conversion_warn +SET( clang_or_gnu 0 ) +IF( "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" ) + SET(clang_or_gnu 1) +ENDIF( "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" ) +IF( "${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" ) + SET(clang_or_gnu 1) +ENDIF( "${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" ) +IF( clang_or_gnu ) + SET(backup "${cppad_cxx_flags}") + SET(cppad_cxx_flags "${backup} -Wfloat-conversion -Wconversion -Werror") + # + SET(source "int main(void) { return 0; }") + run_source_test("${source}" compiler_has_conversion_warn ) + # + SET(cppad_cxx_flags "${backup}") +ELSE( clang_or_gnu ) + SET( compiler_has_conversion_warn 0 ) +ENDIF( clang_or_gnu ) +# ----------------------------------------------------------------------------- +# cppad_boostvector, cppad_cppadvector, cppad_eigenvector, cppad_stdvector +# +check_match(cppad_testvector boost cppad_boostvector) +check_match(cppad_testvector cppad cppad_cppadvector) +check_match(cppad_testvector eigen cppad_eigenvector) +check_match(cppad_testvector std cppad_stdvector) +IF( NOT cppad_boostvector ) +IF( NOT cppad_cppadvector ) +IF( NOT cppad_eigenvector ) +IF( NOT cppad_stdvector ) +MESSAGE(FATAL_ERROR +"cppad_testvector not one of following: boost, cppad, eigen, std." +"This should have been found earlier, please report this as a bug." +) +ENDIF( NOT cppad_stdvector ) +ENDIF( NOT cppad_eigenvector ) +ENDIF( NOT cppad_cppadvector ) +ENDIF( NOT cppad_boostvector ) + +IF( cppad_boostvector ) + # FIND_PACKAGE(Boost) done by ../CMakeLists.txt + IF( NOT Boost_FOUND ) + MESSAGE(FATAL_ERROR +"cppad_testvector == boost but cannot find boost include files" + ) + ENDIF( NOT Boost_FOUND ) +ENDIF( cppad_boostvector ) +# +IF( cppad_eigenvector ) + IF( NOT include_eigen ) + MESSAGE(FATAL_ERROR +"cppad_testvector == eigen but eigen_prefix is not specified" + ) + ENDIF( NOT include_eigen ) +ENDIF( cppad_eigenvector ) +# +print_variable(cppad_cplusplus_201100_ok) +# ----------------------------------------------------------------------------- +# cppad_has_gettimeofday +# +SET(source " +# include +int main(void) +{ struct timeval time; + gettimeofday(&time, 0); + return 0; +}" +) +run_source_test("${source}" cppad_has_gettimeofday) +# ----------------------------------------------------------------------------- +# cppad_tape_addr_type, cppad_tape_id_type +# +FOREACH(cmake_var cppad_tape_id_type cppad_tape_addr_type ) + SET(source " +# include +int main(void) +{ bool is_unsigned = ! std::numeric_limits<${${cmake_var}}>::is_signed; + return int(! is_unsigned); +} +" + ) + run_source_test("${source}" ${cmake_var}_is_unsigned) + IF( ${cmake_var}_is_unsigned STREQUAL 0 ) + MESSAGE(STATUS +"Warning: using a signed ${cmake_var} is for CppAD developers only !" + ) + ENDIF( ${cmake_var}_is_unsigned STREQUAL 0 ) +ENDFOREACH( cmake_var ) +# ----------------------------------------------------------------------------- +# check that cppad_max_num_threads is >= 4 +# +SET(CMAKE_REQUIRED_DERINITIONS "") +SET(CMAKE_REQUIRED_INCLUDES "") +SET(CMAKE_REQUIRED_LIBRARIES "") +SET(CMAKE_REQUIRED_FLAGS "") +SET(source " +int main(void) +{ const char* number = \"${cppad_max_num_threads}\"; + int value = 0; + while( *number == ' ' ) + number++; + while( '0' <= *number && *number <= '9' ) + { value = 10 * value + (int)(*number - '0'); + number++; + } + while( *number == ' ' ) + number++; + if( *number != char(0) ) + return 1; + if( value < 4 ) + return 1; + return 0; +} +" ) +# Using CHECK_CXX_SOURCE_RUNS directly (instead of run_source_test). +IF( DEFINED cppad_max_num_threads_is_integer_ge_4 ) + MESSAGE( ERROR + "cppad_max_num_threads_is_integer_ge_4 is defined before expected" + ) +ENDIF( DEFINED cppad_max_num_threads_is_integer_ge_4 ) +CHECK_CXX_SOURCE_RUNS("${source}" cppad_max_num_threads_is_integer_ge_4 ) +IF( NOT cppad_max_num_threads_is_integer_ge_4 ) + MESSAGE(FATAL_ERROR + "cppad_max_num_threads is not an integer greater than or equal 4" + ) +ENDIF( NOT cppad_max_num_threads_is_integer_ge_4 ) +# ----------------------------------------------------------------------------- +# cppad_has_mkstemp +# +SET(source " +# include +# include +int main(void) +{ + char pattern[] = \"/tmp/fileXXXXXX\"; + int fd = mkstemp(pattern); + return 0; +} +" ) +run_source_test("${source}" cppad_has_mkstemp ) +# ----------------------------------------------------------------------------- +# cppad_has_tmpname_s +# +SET(source " +# include +int main(void) +{ char filename[L_tmpnam_s ]; + if( tmpnam_s(filename, L_tmpnam_s ) != 0 ) + return 1; + return 0; +} +" ) +run_source_test("${source}" cppad_has_tmpnam_s ) +# ----------------------------------------------------------------------------- +# configure.hpp +CONFIGURE_FILE( + ${CMAKE_CURRENT_SOURCE_DIR}/configure.hpp.in + ${CMAKE_CURRENT_SOURCE_DIR}/configure.hpp +) +# ----------------------------------------------------------------------------- diff --git a/build-config/cppad/include/cppad/base_require.hpp b/build-config/cppad/include/cppad/base_require.hpp new file mode 100644 index 00000000..af54fad7 --- /dev/null +++ b/build-config/cppad/include/cppad/base_require.hpp @@ -0,0 +1,177 @@ +# ifndef CPPAD_BASE_REQUIRE_HPP +# define CPPAD_BASE_REQUIRE_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-18 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +/* +$begin base_require$$ +$spell + azmul + ostream + alloc + eps + std + cppad.hpp + namespace + bool + const + CppAD + enum + inline + Op + std + CondExp +$$ + +$section AD Requirements for a CppAD Base Type$$ + +$head Syntax$$ +$code # include $$ + +$head Purpose$$ +This section lists the requirements for the type +$icode Base$$ so that the type $codei%AD<%Base%>%$$ can be used. + +$head API Warning$$ +Defining a CppAD $icode Base$$ type is an advanced use of CppAD. +This part of the CppAD API changes with time. The most common change +is adding more requirements. +Search for $code base_require$$ in the +current $cref whats_new$$ section for these changes. + +$head Standard Base Types$$ +In the case where $icode Base$$ is +$code float$$, +$code double$$, +$code std::complex$$, +$code std::complex$$, +or $codei%AD<%Other%>%$$, +these requirements are provided by including the file +$code cppad/cppad.hpp$$. +In the documentation, The notation $latex \B{R}$$ denotes +the field corresponding to the base type. +Multiplication must be commutative for this field, +but it need not be the reals; e.g., the complex numbers. + +$head Include Order$$ +If you are linking a non-standard base type to CppAD, +you must first include the file $code cppad/base_require.hpp$$, +then provide the specifications below, +and then include the file $code cppad/cppad.hpp$$. + +$head Numeric Type$$ +The type $icode Base$$ must support all the operations for a +$cref NumericType$$. + +$head Output Operator$$ +The type $icode Base$$ must support the syntax +$codei% + %os% << %x% +%$$ +where $icode os$$ is an $code std::ostream&$$ +and $icode x$$ is a $code const base_alloc&$$. +For example, see +$cref/base_alloc/base_alloc.hpp/Output Operator/$$. + +$head Integer$$ +The type $icode Base$$ must support the syntax +$codei% + %i% = CppAD::Integer(%x%) +%$$ +which converts $icode x$$ to an $code int$$. +The argument $icode x$$ has prototype +$codei% + const %Base%& %x% +%$$ +and the return value $icode i$$ has prototype +$codei% + int %i% +%$$ + +$subhead Suggestion$$ +In many cases, the $icode Base$$ version of the $code Integer$$ function +can be defined by +$codei% +namespace CppAD { + inline int Integer(const %Base%& x) + { return static_cast(x); } +} +%$$ +For example, see +$cref/base_float/base_float.hpp/Integer/$$ and +$cref/base_alloc/base_alloc.hpp/Integer/$$. + +$head Absolute Zero, azmul$$ +The type $icode Base$$ must support the syntax +$codei% + %z% = azmul(%x%, %y%) +%$$ +see; $cref azmul$$. +The following preprocessor macro invocation suffices +(for most $icode Base$$ types): +$codei% +namespace CppAD { + CPPAD_AZMUL(%Base%) +} +%$$ +where the macro is defined by +$srccode%cpp% */ +# define CPPAD_AZMUL(Base) \ + inline Base azmul(const Base& x, const Base& y) \ + { Base zero(0.0); \ + if( x == zero ) \ + return zero; \ + return x * y; \ + } +/* %$$ + +$childtable% + omh/base_require/base_member.omh% + include/cppad/core/base_cond_exp.hpp% + omh/base_require/base_identical.omh% + omh/base_require/base_ordered.omh% + include/cppad/core/base_std_math.hpp% + include/cppad/core/base_limits.hpp% + include/cppad/core/base_to_string.hpp% + include/cppad/core/base_hash.hpp% + omh/base_require/base_example.omh +%$$ + +$end +*/ + +// definitions that must come before base implementations +# include +# include +# include +# include + +// grouping documentation by feature +# include +# include +# include +# include +# include + +// must define template class numeric_limits before the base cases +# include +# include // deprecated + +// base cases that come with CppAD +# include +# include +# include + +// deprecated base type +# include + +# endif diff --git a/build-config/cppad/include/cppad/configure.hpp b/build-config/cppad/include/cppad/configure.hpp new file mode 100644 index 00000000..028064ec --- /dev/null +++ b/build-config/cppad/include/cppad/configure.hpp @@ -0,0 +1,238 @@ +# ifndef CPPAD_CONFIGURE_HPP +# define CPPAD_CONFIGURE_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +/*! +$begin configure.hpp$$ +$spell + noexcept + pragmas + unreferenced + CppAD + cppad + yyyymmdd + yyyy + mm + dd + adolc + cmake + colpack + eigen + ipopt + gettimeofday + namespace + mkstemp + tmpnam + nullptr + sizeof + std + hpp + addr +$$ + +$section Preprocessor Symbols Set By CMake Command$$ + +$head CPPAD_COMPILER_HAS_CONVERSION_WARN$$ +is the compiler a variant of g++ and has conversion warnings +$srccode%hpp% */ +# define CPPAD_COMPILER_HAS_CONVERSION_WARN 0 +/* %$$ + +$head CPPAD_DISABLE_SOME_MICROSOFT_COMPILER_WARNINGS$$ +This macro is only used to document the pragmas that disables the +follow warnings: + +$subhead C4100$$ +unreferenced formal parameter. + +$subhead C4127$$ +conditional expression is constant. + +$srccode%hpp% */ +# define CPPAD_DISABLE_SOME_MICROSOFT_COMPILER_WARNINGS 1 +# if _MSC_VER +# pragma warning( disable : 4100 ) +# pragma warning( disable : 4127 ) +# endif +# undef CPPAD_DISABLE_SOME_MICROSOFT_COMPILER_WARNINGS +/* %$$ + +$head CPPAD_USE_CPLUSPLUS_2011$$ +Deprecated 2020-12-03: +Should CppAD use C++11 features. This is always 1 (for true). +$srccode%hpp% */ +# define CPPAD_USE_CPLUSPLUS_2011 1 +/* %$$ + +$head CPPAD_PACKAGE_STRING$$ +cppad-yyyymmdd as a C string where yyyy is year, mm is month, and dd is day. +$srccode%hpp% */ +# define CPPAD_PACKAGE_STRING "cppad-20210000.8" +/* %$$ + +$head CPPAD_HAS_ADOLC$$ +Was include_adolc=true on the cmake command line. +$srccode%hpp% */ +# define CPPAD_HAS_ADOLC 0 +/* %$$ + +$head CPPAD_HAS_COLPACK$$ +Was a colpack_prefix specified on the cmake command line. +$srccode%hpp% */ +# define CPPAD_HAS_COLPACK 0 +/* %$$ + +$head CPPAD_HAS_EIGEN$$ +Was include_eigen=true on the cmake command line. +$srccode%hpp% */ +# define CPPAD_HAS_EIGEN 0 +/* %$$ + +$head CPPAD_HAS_IPOPT$$ +Was include_ipopt=true on the cmake command line. +$srccode%hpp% */ +# define CPPAD_HAS_IPOPT 0 +/* %$$ + +$head CPPAD_DEPRECATED$$ +This symbol is not currently being used. +$srccode%hpp% */ +# define CPPAD_DEPRECATED +/* %$$ + +$head CPPAD_BOOSTVECTOR$$ +If this symbol is one, and _MSC_VER is not defined, +we are using boost vector for CPPAD_TESTVECTOR. +It this symbol is zero, +we are not using boost vector for CPPAD_TESTVECTOR. +$srccode%hpp% */ +# define CPPAD_BOOSTVECTOR 0 +/* %$$ + +$head CPPAD_CPPADVECTOR$$ +If this symbol is one, +we are using CppAD vector for CPPAD_TESTVECTOR. +It this symbol is zero, +we are not using CppAD vector for CPPAD_TESTVECTOR. +$srccode%hpp% */ +# define CPPAD_CPPADVECTOR 1 +/* %$$ + +$head CPPAD_STDVECTOR$$ +If this symbol is one, +we are using standard vector for CPPAD_TESTVECTOR. +It this symbol is zero, +we are not using standard vector for CPPAD_TESTVECTOR. +$srccode%hpp% */ +# define CPPAD_STDVECTOR 0 +/* %$$ + +$head CPPAD_EIGENVECTOR$$ +If this symbol is one, +we are using Eigen vector for CPPAD_TESTVECTOR. +If this symbol is zero, +we are not using Eigen vector for CPPAD_TESTVECTOR. +$srccode%hpp% */ +# define CPPAD_EIGENVECTOR 0 +/* %$$ + +$head CPPAD_HAS_GETTIMEOFDAY$$ +If this symbol is one, and _MSC_VER is not defined, +this system supports the gettimeofday function. +Otherwise, this symbol should be zero. +$srccode%hpp% */ +# define CPPAD_HAS_GETTIMEOFDAY 1 +/* %$$ + +$head CPPAD_TAPE_ADDR_TYPE$$ +Is the type used to store address on the tape. If not size_t, then +sizeof(CPPAD_TAPE_ADDR_TYPE) <= sizeof( size_t ) +to conserve memory. +This type must support std::numeric_limits, +the <= operator, +and conversion to size_t. +Make sure that the type chosen returns true for is_pod +in pod_vector.hpp. +This type is later defined as addr_t in the CppAD namespace. +$srccode%hpp% */ +# define CPPAD_TAPE_ADDR_TYPE unsigned int +/* %$$ + +$head CPPAD_TAPE_ID_TYPE$$ +Is the type used to store tape identifiers. If not size_t, then +sizeof(CPPAD_TAPE_ID_TYPE) <= sizeof( size_t ) +to conserve memory. +This type must support std::numeric_limits, +the <= operator, +and conversion to size_t. +Make sure that the type chosen returns true for is_pod +in pod_vector.hpp. +This type is later defined as tape_id_t in the CppAD namespace. +$srccode%hpp% */ +# define CPPAD_TAPE_ID_TYPE unsigned int +/* %$$ + +$head CPPAD_MAX_NUM_THREADS$$ +Specifies the maximum number of threads that CppAD can support +(must be greater than or equal four). + +The user may define CPPAD_MAX_NUM_THREADS before including any of the CppAD +header files. If it is not yet defined, +$srccode%hpp% */ +# ifndef CPPAD_MAX_NUM_THREADS +# define CPPAD_MAX_NUM_THREADS 48 +# endif +/* %$$ + +$head CPPAD_HAS_MKSTEMP$$ +It true, mkstemp works in C++ on this system. +$srccode%hpp% */ +# define CPPAD_HAS_MKSTEMP 1 +/* %$$ + +$head CPPAD_HAS_TMPNAM_S$$ +It true, tmpnam_s works in C++ on this system. +$srccode%hpp% */ +# define CPPAD_HAS_TMPNAM_S 0 +/* %$$ + +$head CPPAD_NULL$$ +Deprecated 2020-12-03: +This preprocessor symbol was used for a null pointer before c++11. +Replace it by $code nullptr$$. + +$head CPPAD_NOEXCEPT$$ +Deprecated 2020-12-03: +This preprocessor symbol was used for no exception before c++11, +replace it by $code noexcept$$. + +$subhead CPPAD_NDEBUG_NOEXCEPT$$ +This preprocessor symbol is +$code noexcept$$ when C++11 is available and $code NDEBUG$$ is defined. +Otherwise it is empty. + + +$end +*/ +// ------------------------------------------------- +# define CPPAD_NULL nullptr +# define CPPAD_NOEXCEPT noexcept +// +# ifdef NDEBUG +# define CPPAD_NDEBUG_NOEXCEPT noexcept +# else +# define CPPAD_NDEBUG_NOEXCEPT +# endif +// ------------------------------------------------- + +# endif diff --git a/build-config/cppad/include/cppad/configure.hpp.in b/build-config/cppad/include/cppad/configure.hpp.in new file mode 100644 index 00000000..718e42cb --- /dev/null +++ b/build-config/cppad/include/cppad/configure.hpp.in @@ -0,0 +1,238 @@ +# ifndef CPPAD_CONFIGURE_HPP +# define CPPAD_CONFIGURE_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +/*! +$begin configure.hpp$$ +$spell + noexcept + pragmas + unreferenced + CppAD + cppad + yyyymmdd + yyyy + mm + dd + adolc + cmake + colpack + eigen + ipopt + gettimeofday + namespace + mkstemp + tmpnam + nullptr + sizeof + std + hpp + addr +$$ + +$section Preprocessor Symbols Set By CMake Command$$ + +$head CPPAD_COMPILER_HAS_CONVERSION_WARN$$ +is the compiler a variant of g++ and has conversion warnings +$srccode%hpp% */ +# define CPPAD_COMPILER_HAS_CONVERSION_WARN @compiler_has_conversion_warn@ +/* %$$ + +$head CPPAD_DISABLE_SOME_MICROSOFT_COMPILER_WARNINGS$$ +This macro is only used to document the pragmas that disables the +follow warnings: + +$subhead C4100$$ +unreferenced formal parameter. + +$subhead C4127$$ +conditional expression is constant. + +$srccode%hpp% */ +# define CPPAD_DISABLE_SOME_MICROSOFT_COMPILER_WARNINGS 1 +# if _MSC_VER +# pragma warning( disable : 4100 ) +# pragma warning( disable : 4127 ) +# endif +# undef CPPAD_DISABLE_SOME_MICROSOFT_COMPILER_WARNINGS +/* %$$ + +$head CPPAD_USE_CPLUSPLUS_2011$$ +Deprecated 2020-12-03: +Should CppAD use C++11 features. This is always 1 (for true). +$srccode%hpp% */ +# define CPPAD_USE_CPLUSPLUS_2011 1 +/* %$$ + +$head CPPAD_PACKAGE_STRING$$ +cppad-yyyymmdd as a C string where yyyy is year, mm is month, and dd is day. +$srccode%hpp% */ +# define CPPAD_PACKAGE_STRING "cppad-@cppad_version@" +/* %$$ + +$head CPPAD_HAS_ADOLC$$ +Was include_adolc=true on the cmake command line. +$srccode%hpp% */ +# define CPPAD_HAS_ADOLC @cppad_has_adolc@ +/* %$$ + +$head CPPAD_HAS_COLPACK$$ +Was a colpack_prefix specified on the cmake command line. +$srccode%hpp% */ +# define CPPAD_HAS_COLPACK @cppad_has_colpack@ +/* %$$ + +$head CPPAD_HAS_EIGEN$$ +Was include_eigen=true on the cmake command line. +$srccode%hpp% */ +# define CPPAD_HAS_EIGEN @cppad_has_eigen@ +/* %$$ + +$head CPPAD_HAS_IPOPT$$ +Was include_ipopt=true on the cmake command line. +$srccode%hpp% */ +# define CPPAD_HAS_IPOPT @cppad_has_ipopt@ +/* %$$ + +$head CPPAD_DEPRECATED$$ +This symbol is not currently being used. +$srccode%hpp% */ +# define CPPAD_DEPRECATED @cppad_deprecated_01@ +/* %$$ + +$head CPPAD_BOOSTVECTOR$$ +If this symbol is one, and _MSC_VER is not defined, +we are using boost vector for CPPAD_TESTVECTOR. +It this symbol is zero, +we are not using boost vector for CPPAD_TESTVECTOR. +$srccode%hpp% */ +# define CPPAD_BOOSTVECTOR @cppad_boostvector@ +/* %$$ + +$head CPPAD_CPPADVECTOR$$ +If this symbol is one, +we are using CppAD vector for CPPAD_TESTVECTOR. +It this symbol is zero, +we are not using CppAD vector for CPPAD_TESTVECTOR. +$srccode%hpp% */ +# define CPPAD_CPPADVECTOR @cppad_cppadvector@ +/* %$$ + +$head CPPAD_STDVECTOR$$ +If this symbol is one, +we are using standard vector for CPPAD_TESTVECTOR. +It this symbol is zero, +we are not using standard vector for CPPAD_TESTVECTOR. +$srccode%hpp% */ +# define CPPAD_STDVECTOR @cppad_stdvector@ +/* %$$ + +$head CPPAD_EIGENVECTOR$$ +If this symbol is one, +we are using Eigen vector for CPPAD_TESTVECTOR. +If this symbol is zero, +we are not using Eigen vector for CPPAD_TESTVECTOR. +$srccode%hpp% */ +# define CPPAD_EIGENVECTOR @cppad_eigenvector@ +/* %$$ + +$head CPPAD_HAS_GETTIMEOFDAY$$ +If this symbol is one, and _MSC_VER is not defined, +this system supports the gettimeofday function. +Otherwise, this symbol should be zero. +$srccode%hpp% */ +# define CPPAD_HAS_GETTIMEOFDAY @cppad_has_gettimeofday@ +/* %$$ + +$head CPPAD_TAPE_ADDR_TYPE$$ +Is the type used to store address on the tape. If not size_t, then +sizeof(CPPAD_TAPE_ADDR_TYPE) <= sizeof( size_t ) +to conserve memory. +This type must support std::numeric_limits, +the <= operator, +and conversion to size_t. +Make sure that the type chosen returns true for is_pod +in pod_vector.hpp. +This type is later defined as addr_t in the CppAD namespace. +$srccode%hpp% */ +# define CPPAD_TAPE_ADDR_TYPE @cppad_tape_addr_type@ +/* %$$ + +$head CPPAD_TAPE_ID_TYPE$$ +Is the type used to store tape identifiers. If not size_t, then +sizeof(CPPAD_TAPE_ID_TYPE) <= sizeof( size_t ) +to conserve memory. +This type must support std::numeric_limits, +the <= operator, +and conversion to size_t. +Make sure that the type chosen returns true for is_pod +in pod_vector.hpp. +This type is later defined as tape_id_t in the CppAD namespace. +$srccode%hpp% */ +# define CPPAD_TAPE_ID_TYPE @cppad_tape_id_type@ +/* %$$ + +$head CPPAD_MAX_NUM_THREADS$$ +Specifies the maximum number of threads that CppAD can support +(must be greater than or equal four). + +The user may define CPPAD_MAX_NUM_THREADS before including any of the CppAD +header files. If it is not yet defined, +$srccode%hpp% */ +# ifndef CPPAD_MAX_NUM_THREADS +# define CPPAD_MAX_NUM_THREADS @cppad_max_num_threads@ +# endif +/* %$$ + +$head CPPAD_HAS_MKSTEMP$$ +It true, mkstemp works in C++ on this system. +$srccode%hpp% */ +# define CPPAD_HAS_MKSTEMP @cppad_has_mkstemp@ +/* %$$ + +$head CPPAD_HAS_TMPNAM_S$$ +It true, tmpnam_s works in C++ on this system. +$srccode%hpp% */ +# define CPPAD_HAS_TMPNAM_S @cppad_has_tmpnam_s@ +/* %$$ + +$head CPPAD_NULL$$ +Deprecated 2020-12-03: +This preprocessor symbol was used for a null pointer before c++11. +Replace it by $code nullptr$$. + +$head CPPAD_NOEXCEPT$$ +Deprecated 2020-12-03: +This preprocessor symbol was used for no exception before c++11, +replace it by $code noexcept$$. + +$subhead CPPAD_NDEBUG_NOEXCEPT$$ +This preprocessor symbol is +$code noexcept$$ when C++11 is available and $code NDEBUG$$ is defined. +Otherwise it is empty. + + +$end +*/ +// ------------------------------------------------- +# define CPPAD_NULL nullptr +# define CPPAD_NOEXCEPT noexcept +// +# ifdef NDEBUG +# define CPPAD_NDEBUG_NOEXCEPT noexcept +# else +# define CPPAD_NDEBUG_NOEXCEPT +# endif +// ------------------------------------------------- + +# endif diff --git a/build-config/cppad/include/cppad/core/abort_recording.hpp b/build-config/cppad/include/cppad/core/abort_recording.hpp new file mode 100644 index 00000000..09c3a1f8 --- /dev/null +++ b/build-config/cppad/include/cppad/core/abort_recording.hpp @@ -0,0 +1,58 @@ +# ifndef CPPAD_CORE_ABORT_RECORDING_HPP +# define CPPAD_CORE_ABORT_RECORDING_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ +/* +$begin abort_recording$$ +$spell +$$ + +$section Abort Recording of an Operation Sequence$$ + + +$head Syntax$$ +$codei%AD<%Base%>::abort_recording()%$$ + +$head Purpose$$ +Sometimes it is necessary to abort the recording of an operation sequence +that started with a call of the form +$codei% + Independent(%x%) +%$$ +If such a recording is currently in progress, +$code abort_recording$$ will stop the recording and delete the +corresponding information. +Otherwise, $code abort_recording$$ has no effect. + +$children% + example/general/abort_recording.cpp +%$$ +$head Example$$ +The file +$cref abort_recording.cpp$$ +contains an example and test of this operation. + +$end +---------------------------------------------------------------------------- +*/ + + +namespace CppAD { + template + void AD::abort_recording(void) + { local::ADTape* tape = AD::tape_ptr(); + if( tape != nullptr ) + AD::tape_manage(delete_tape_manage); + } +} + +# endif diff --git a/build-config/cppad/include/cppad/core/abs.hpp b/build-config/cppad/include/cppad/core/abs.hpp new file mode 100644 index 00000000..f25d6e87 --- /dev/null +++ b/build-config/cppad/include/cppad/core/abs.hpp @@ -0,0 +1,132 @@ +# ifndef CPPAD_CORE_ABS_HPP +# define CPPAD_CORE_ABS_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +/* +------------------------------------------------------------------------------- +$begin abs$$ +$spell + fabs + Vec + std + faq + Taylor + Cpp + namespace + const + abs +$$ + +$section AD Absolute Value Functions: abs, fabs$$ + +$head Syntax$$ +$icode%y% = abs(%x%) +%$$ +$icode%y% = fabs(%x%)%$$ + +$head x, y$$ +See the $cref/possible types/unary_standard_math/Possible Types/$$ +for a unary standard math function. + +$head Atomic$$ +In the case where $icode x$$ is an AD type, +this is an $cref/atomic operation/glossary/Operation/Atomic/$$. + +$head Complex Types$$ +The functions $code abs$$ and $icode fabs$$ +are not defined for the base types +$code std::complex$$ or $code std::complex$$ +because the complex $code abs$$ function is not complex differentiable +(see $cref/complex types faq/Faq/Complex Types/$$). + +$head Derivative$$ +CppAD defines the derivative of the $code abs$$ function is +the $cref sign$$ function; i.e., +$latex \[ +{\rm abs}^{(1)} ( x ) = {\rm sign} (x ) = +\left\{ \begin{array}{rl} + +1 & {\rm if} \; x > 0 \\ + 0 & {\rm if} \; x = 0 \\ + -1 & {\rm if} \; x < 0 +\end{array} \right. +\] $$ +The result for $icode%x% == 0%$$ used to be a directional derivative. + +$head Example$$ +$children% + example/general/fabs.cpp +%$$ +The file +$cref fabs.cpp$$ +contains an example and test of this function. + +$end +------------------------------------------------------------------------------- +*/ + +// BEGIN CppAD namespace +namespace CppAD { + +template +AD AD::abs_me (void) const +{ + AD result; + result.value_ = abs(value_); + CPPAD_ASSERT_UNKNOWN( Parameter(result) ); + + // check if there is a recording in progress + local::ADTape* tape = AD::tape_ptr(); + if( tape == nullptr ) + return result; + + // check if operand is a constant parameter + if( tape_id_ != tape->id_ ) + return result; + + if(ad_type_ == dynamic_enum) + { // dynamic paramter argument + result.taddr_ = tape->Rec_.put_dyn_par( + result.value_, local::abs_dyn, taddr_ + ); + result.tape_id_ = tape_id_; + result.ad_type_ = dynamic_enum; + } + else + { // variable argument + CPPAD_ASSERT_UNKNOWN( local::NumRes(local::AbsOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( local::NumArg(local::AbsOp) == 1 ); + + // corresponding operand address + tape->Rec_.PutArg(taddr_); + + // put operator in the tape + result.taddr_ = tape->Rec_.PutOp(local::AbsOp); + + // make result a variable + result.tape_id_ = tape_id_; + result.ad_type_ = variable_enum; + } + return result; +} + +template +AD abs(const AD &x) +{ return x.abs_me(); } + +template +AD abs(const VecAD_reference &x) +{ return x.ADBase().abs_me(); } + +} // END CppAD namespace + +# endif diff --git a/build-config/cppad/include/cppad/core/abs_normal_fun.hpp b/build-config/cppad/include/cppad/core/abs_normal_fun.hpp new file mode 100644 index 00000000..c5a124b7 --- /dev/null +++ b/build-config/cppad/include/cppad/core/abs_normal_fun.hpp @@ -0,0 +1,959 @@ +# ifndef CPPAD_CORE_ABS_NORMAL_FUN_HPP +# define CPPAD_CORE_ABS_NORMAL_FUN_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-21 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ +/* +$begin abs_normal_fun$$ +$spell + const +$$ + + +$section Create An Abs-normal Representation of a Function$$ + +$head Syntax$$ +$icode%f%.abs_normal_fun(%g%, %a%)%$$ + +$head f$$ +The object $icode f$$ has prototype +$codei% + const ADFun<%Base%>& %f% +%$$ +It represents a function $latex f : \B{R}^n \rightarrow \B{R}^m$$. +We assume that the only non-smooth terms in the representation are +absolute value functions and use $latex s \in \B{Z}_+$$ +to represent the number of these terms. + +$subhead n$$ +We use $icode n$$ to denote the dimension of the domain space for $icode f$$. + +$subhead m$$ +We use $icode m$$ to denote the dimension of the range space for $icode f$$. + +$subhead s$$ +We use $icode s$$ to denote the number of absolute value terms in $icode f$$. + + +$head a$$ +The object $icode a$$ has prototype +$codei% + ADFun<%Base%> %a% +%$$ +The initial function representation in $icode a$$ is lost. +Upon return it represents the result of the absolute terms +$latex a : \B{R}^n \rightarrow \B{R}^s$$; see $latex a(x)$$ defined below. +Note that $icode a$$ is constructed by copying $icode f$$ +and then changing the dependent variables. There may +be many calculations in this representation that are not necessary +and can be removed using +$codei% + %a%.optimize() +%$$ +This optimization is not done automatically by $code abs_normal_fun$$ +because it may take a significant amount of time. + +$subhead zeta$$ +Let $latex \zeta_0 ( x )$$ +denote the argument for the first absolute value term in $latex f(x)$$, +$latex \zeta_1 ( x , |\zeta_0 (x)| )$$ for the second term, and so on. + +$subhead a(x)$$ +For $latex i = 0 , \ldots , {s-1}$$ define +$latex \[ +a_i (x) += +| \zeta_i ( x , a_0 (x) , \ldots , a_{i-1} (x ) ) | +\] $$ +This defines $latex a : \B{R}^n \rightarrow \B{R}^s$$. + +$head g$$ +The object $icode g$$ has prototype +$codei% + ADFun<%Base%> %g% +%$$ +The initial function representation in $icode g$$ is lost. +Upon return it represents the smooth function +$latex g : \B{R}^{n + s} \rightarrow \B{R}^{m + s}$$ is defined by +$latex \[ +g( x , u ) += +\left[ \begin{array}{c} y(x, u) \\ z(x, u) \end{array} \right] +\] $$ +were $latex y(x, u)$$ and $latex z(x, u)$$ are defined below. + +$subhead z(x, u)$$ +Define the smooth function +$latex z : \B{R}^{n + s} \rightarrow \B{R}^s$$ by +$latex \[ +z_i ( x , u ) = \zeta_i ( x , u_0 , \ldots , u_{i-1} ) +\] $$ +Note that the partial of $latex z_i$$ with respect to $latex u_j$$ is zero +for $latex j \geq i$$. + +$subhead y(x, u)$$ +There is a smooth function +$latex y : \B{R}^{n + s} \rightarrow \B{R}^m$$ +such that $latex y( x , u ) = f(x)$$ whenever $latex u = a(x)$$. + +$head Affine Approximation$$ +We define the affine approximations +$latex \[ +\begin{array}{rcl} +y[ \hat{x} ]( x , u ) +& = & +y ( \hat{x}, a( \hat{x} ) ) + + \partial_x y ( \hat{x}, a( \hat{x} ) ) ( x - \hat{x} ) + + \partial_u y ( \hat{x}, a( \hat{x} ) ) ( u - a( \hat{x} ) ) +\\ +z[ \hat{x} ]( x , u ) +& = & +z ( \hat{x}, a( \hat{x} ) ) + + \partial_x z ( \hat{x}, a( \hat{x} ) ) ( x - \hat{x} ) + + \partial_u z ( \hat{x}, a( \hat{x} ) ) ( u - a( \hat{x} ) ) +\end{array} +\] $$ +It follows that +$latex \[ +\begin{array}{rcl} +y( x , u ) +& = & +y[ \hat{x} ]( x , u ) + o ( x - \hat{x}, u - a( \hat{x} ) ) +\\ +z( x , u ) +& = & +z[ \hat{x} ]( x , u ) + o ( x - \hat{x}, u - a( \hat{x} ) ) +\end{array} +\] $$ + +$head Abs-normal Approximation$$ + +$subhead Approximating a(x)$$ +The function $latex a(x)$$ is not smooth, but it is equal to +$latex | z(x, u) |$$ when $latex u = a(x)$$. +Furthermore +$latex \[ +z[ \hat{x} ]( x , u ) += +z ( \hat{x}, a( \hat{x} ) ) + + \partial_x z ( \hat{x}, a( \hat{x} ) ) ( x - \hat{x} ) + + \partial_u z ( \hat{x}, a( \hat{x} ) ) ( u - a( \hat{x} ) ) +\] $$ +The partial of $latex z_i$$ with respect to $latex u_j$$ is zero +for $latex j \geq i$$. It follows that +$latex \[ +z_i [ \hat{x} ]( x , u ) += +z_i ( \hat{x}, a( \hat{x} ) ) + + \partial_x z_i ( \hat{x}, a( \hat{x} ) ) ( x - \hat{x} ) + + \sum_{j < i} \partial_{u(j)} + z_i ( \hat{x}, a( \hat{x} ) ) ( u_j - a_j ( \hat{x} ) ) +\] $$ +Considering the case $latex i = 0$$ we define +$latex \[ +a_0 [ \hat{x} ]( x ) += +| z_0 [ \hat{x} ]( x , u ) | += +\left| + z_0 ( \hat{x}, a( \hat{x} ) ) + + \partial_x z_0 ( \hat{x}, a( \hat{x} ) ) ( x - \hat{x} ) +\right| +\] $$ +It follows that +$latex \[ + a_0 (x) = a_0 [ \hat{x} ]( x ) + o ( x - \hat{x} ) +\] $$ +In general, we define $latex a_i [ \hat{x} ]$$ using +$latex a_j [ \hat{x} ]$$ for $latex j < i$$ as follows: +$latex \[ +a_i [ \hat{x} ]( x ) += +\left | + z_i ( \hat{x}, a( \hat{x} ) ) + + \partial_x z_i ( \hat{x}, a( \hat{x} ) ) ( x - \hat{x} ) + + \sum_{j < i} \partial_{u(j)} + z_i ( \hat{x}, a( \hat{x} ) ) + ( a_j [ \hat{x} ] ( x ) - a_j ( \hat{x} ) ) +\right| +\] $$ +It follows that +$latex \[ + a (x) = a[ \hat{x} ]( x ) + o ( x - \hat{x} ) +\] $$ +Note that in the case where $latex z(x, u)$$ and $latex y(x, u)$$ are +affine, +$latex \[ + a[ \hat{x} ]( x ) = a( x ) +\] $$ + + +$subhead Approximating f(x)$$ +$latex \[ +f(x) += +y ( x , a(x ) ) += +y [ \hat{x} ] ( x , a[ \hat{x} ] ( x ) ) ++ o( x - \hat{x} ) +\] $$ + +$head Correspondence to Literature$$ +Using the notation +$latex Z = \partial_x z(\hat{x}, \hat{u})$$, +$latex L = \partial_u z(\hat{x}, \hat{u})$$, +$latex J = \partial_x y(\hat{x}, \hat{u})$$, +$latex Y = \partial_u y(\hat{x}, \hat{u})$$, +the approximation for $latex z$$ and $latex y$$ are +$latex \[ +\begin{array}{rcl} +z[ \hat{x} ]( x , u ) +& = & +z ( \hat{x}, a( \hat{x} ) ) + Z ( x - \hat{x} ) + L ( u - a( \hat{x} ) ) +\\ +y[ \hat{x} ]( x , u ) +& = & +y ( \hat{x}, a( \hat{x} ) ) + J ( x - \hat{x} ) + Y ( u - a( \hat{x} ) ) +\end{array} +\] $$ +Moving the terms with $latex \hat{x}$$ together, we have +$latex \[ +\begin{array}{rcl} +z[ \hat{x} ]( x , u ) +& = & +z ( \hat{x}, a( \hat{x} ) ) - Z \hat{x} - L a( \hat{x} ) + Z x + L u +\\ +y[ \hat{x} ]( x , u ) +& = & +y ( \hat{x}, a( \hat{x} ) ) - J \hat{x} - Y a( \hat{x} ) + J x + Y u +\end{array} +\] $$ +Using the notation +$latex c = z ( \hat{x}, \hat{u} ) - Z \hat{x} - L \hat{u}$$, +$latex b = y ( \hat{x}, \hat{u} ) - J \hat{x} - Y \hat{u}$$, +we have +$latex \[ +\begin{array}{rcl} +z[ \hat{x} ]( x , u ) & = & c + Z x + L u +\\ +y[ \hat{x} ]( x , u ) & = & b + J x + Y u +\end{array} +\] $$ +Considering the affine case, where the approximations are exact, +and choosing $latex u = a(x) = |z(x, u)|$$, we obtain +$latex \[ +\begin{array}{rcl} +z( x , a(x ) ) & = & c + Z x + L |z( x , a(x ) )| +\\ +y( x , a(x ) ) & = & b + J x + Y |z( x , a(x ) )| +\end{array} +\] $$ +This is Equation (2) of the +$cref/reference/example_abs_normal/Reference/$$. + +$children%example/abs_normal/abs_normal.omh +%$$ +$head Example$$ +The file $cref abs_get_started.cpp$$ contains +an example and test using this operation. +The section $cref example_abs_normal$$ +has a links to all the abs normal examples. + +$end +------------------------------------------------------------------------------- +*/ +/*! +file abs_normal_fun.hpp +Create an abs-normal representation of a function +*/ + +namespace CppAD { // BEGIN_CPPAD_NAMESPACE +/*! +Create an abs-normal representation of an ADFun object. + +\tparam Base +base type for this abs-normal form and for the function beging represented; +i.e., f. + +\param f +is the function that this object will represent in abs-normal form. +This is effectively const except that the play back state play_ +is used. +*/ + +# ifndef NDEBUG +# define CPPAD_J_PAR_EQUAL_REC j_par = (size_t) rec +# else +# define CPPAD_J_PAR_EQUAL_REC rec +# endif + +template +void ADFun::abs_normal_fun(ADFun& g, ADFun& a) const +{ using namespace local; + + // ----------------------------------------------------------------------- + // Forward sweep to determine number of absolute value operations in f + // ----------------------------------------------------------------------- + // The argument and result index in f for each absolute value operator + CppAD::vector f_abs_arg; + CppAD::vector f_abs_res; + // + OpCode op; // this operator + const addr_t* arg = nullptr; // arguments for this operator + size_t i_var; // variable index for this operator + local::play::const_sequential_iterator itr = play_.begin(); + itr.op_info(op, arg, i_var); + CPPAD_ASSERT_UNKNOWN( op == BeginOp ); + // + bool more_operators = true; + while( op != EndOp ) + { + // next op + (++itr).op_info(op, arg, i_var); + switch( op ) + { // absolute value operator + case AbsOp: + CPPAD_ASSERT_NARG_NRES(op, 1, 1); + f_abs_arg.push_back( arg[0] ); + f_abs_res.push_back( i_var ); + break; + + default: + break; + } + } + // ------------------------------------------------------------------------ + // Forward sweep to create new recording + // ------------------------------------------------------------------------ + // dynamic parameter information in player + const pod_vector& dyn_par_is( play_.dyn_par_is() ); + const pod_vector& dyn_par_op( play_.dyn_par_op() ); + const pod_vector& dyn_par_arg( play_.dyn_par_arg() ); + // + // recorder for new operation sequence + recorder rec; + // + // number of parameters in both operation sequences + size_t num_par = play_.num_par_rec(); + // + // number of independent dynamic parameters + size_t num_dynamic_ind = play_.num_dynamic_par(); + rec.set_num_dynamic_ind(num_dynamic_ind); + // + // set all parameter to be exactly the same in rec as in play + size_t i_dyn = 0; // dynamic parameter index + size_t i_arg = 0; // dynamic parameter operator argument index + for(size_t i_par = 0; i_par < num_par; ++i_par) + { +# ifndef NDEBUG + size_t j_par = 0; +# endif + // value of this parameter + Base par = play_.GetPar(i_par); + if( ! dyn_par_is[i_par] ) + CPPAD_J_PAR_EQUAL_REC.put_con_par(par); + else + { // operator for this dynamic parameter + op_code_dyn op_dyn = op_code_dyn( dyn_par_op[i_dyn] ); + CPPAD_ASSERT_KNOWN( + op_dyn != local::atom_dyn, + "abs_normal_fun: not yet implemented for " + "atomic dynamic parameter functions" + ); + // + // number of arguments for this dynamic parameter + size_t n_arg = num_arg_dyn(op_dyn); + // + switch(n_arg) + { case 0: + CPPAD_J_PAR_EQUAL_REC.put_dyn_par(par, op_dyn); + break; + + case 1: + CPPAD_J_PAR_EQUAL_REC.put_dyn_par(par, op_dyn, + dyn_par_arg[i_arg + 0] + ); + break; + + case 2: + CPPAD_J_PAR_EQUAL_REC.put_dyn_par(par, op_dyn, + dyn_par_arg[i_arg + 0] , + dyn_par_arg[i_arg + 1] + ); + break; + + case 5: + CPPAD_J_PAR_EQUAL_REC.put_dyn_cond_exp(par, + CompareOp( dyn_par_arg[i_arg + 0] ) , + dyn_par_arg[i_arg + 1] , + dyn_par_arg[i_arg + 2] , + dyn_par_arg[i_arg + 3] , + dyn_par_arg[i_arg + 4] + ); + break; + + default: + CPPAD_ASSERT_UNKNOWN(false); + } + ++i_dyn; + i_arg += n_arg; + } + CPPAD_ASSERT_UNKNOWN( j_par == i_par ); + } + // + // number of variables in both operation sequences + // (the AbsOp operators are replace by InvOp operators) + const size_t num_var = play_.num_var_rec(); + // + // mapping from old variable index to new variable index + CPPAD_ASSERT_UNKNOWN( + size_t( (std::numeric_limits::max)() ) >= num_var + ); + CppAD::vector f2g_var(num_var); + for(i_var = 0; i_var < num_var; i_var++) + f2g_var[i_var] = addr_t( num_var ); // invalid (should not be used) + // + // record the independent variables in f + itr = play_.begin(); + itr.op_info(op, arg, i_var); + CPPAD_ASSERT_UNKNOWN( op == BeginOp ); + more_operators = true; + while( more_operators ) + { switch( op ) + { + // phantom variable + case BeginOp: + CPPAD_ASSERT_NARG_NRES(op, 1, 1); + CPPAD_ASSERT_UNKNOWN( arg[0] == 0 ); + rec.PutArg(0); + f2g_var[i_var] = rec.PutOp(op); + break; + + // independent variables + case InvOp: + CPPAD_ASSERT_NARG_NRES(op, 0, 1); + f2g_var[i_var] = rec.PutOp(op); + break; + + // end of independent variables + default: + more_operators = false; + break; + } + if( more_operators ) + (++itr).op_info(op, arg, i_var); + } + // add one for the phantom variable + CPPAD_ASSERT_UNKNOWN( 1 + Domain() == i_var ); + // + // record the independent variables corresponding AbsOp results + size_t index_abs; + for(index_abs = 0; index_abs < f_abs_res.size(); index_abs++) + f2g_var[ f_abs_res[index_abs] ] = rec.PutOp(InvOp); + // + // used to hold new argument vector + addr_t new_arg[6]; + // + // now loop through the rest of the + more_operators = true; + index_abs = 0; + while( more_operators ) + { addr_t mask; // temporary used in some switch cases + switch( op ) + { + // check setting of f_abs_arg and f_abs_res; + case AbsOp: + CPPAD_ASSERT_NARG_NRES(op, 1, 1); + CPPAD_ASSERT_UNKNOWN( f_abs_arg[index_abs] == arg[0] ); + CPPAD_ASSERT_UNKNOWN( f_abs_res[index_abs] == i_var ); + CPPAD_ASSERT_UNKNOWN( f2g_var[i_var] > 0 ); + ++index_abs; + break; + + // These operators come at beginning of take and are handled above + case InvOp: + CPPAD_ASSERT_UNKNOWN(false); + break; + + // --------------------------------------------------------------- + // Unary operators, argument a parameter, one result + case ParOp: + CPPAD_ASSERT_NARG_NRES(op, 1, 1); + new_arg[0] = arg[0]; // parameter + rec.PutArg( new_arg[0] ); + f2g_var[i_var] = rec.PutOp(op); + break; + + // -------------------------------------------------------------- + // Unary operators, argument a variable, one result + // (excluding the absolute value operator AbsOp) + case AcosOp: + case AcoshOp: + case AsinOp: + case AsinhOp: + case AtanOp: + case AtanhOp: + case CosOp: + case CoshOp: + case ExpOp: + case Expm1Op: + case LogOp: + case Log1pOp: + case SignOp: + case SinOp: + case SinhOp: + case SqrtOp: + case TanOp: + case TanhOp: + // some of these operators have an auxillary result; e.g., + // sine and cosine are computed togeather. + CPPAD_ASSERT_UNKNOWN( NumArg(op) == 1 ); + CPPAD_ASSERT_UNKNOWN( NumRes(op) == 1 || NumRes(op) == 2 ); + CPPAD_ASSERT_UNKNOWN( size_t( f2g_var[ arg[0] ] ) < num_var ); + new_arg[0] = f2g_var[ arg[0] ]; + rec.PutArg( new_arg[0] ); + f2g_var[i_var] = rec.PutOp( op ); + break; + + case ErfOp: + case ErfcOp: + CPPAD_ASSERT_NARG_NRES(op, 3, 5); + CPPAD_ASSERT_UNKNOWN( size_t( f2g_var[ arg[0] ] ) < num_var ); + // Error function is a special case + // second argument is always the parameter 0 + // third argument is always the parameter 2 / sqrt(pi) + rec.PutArg( arg[1] ); // parameter + rec.PutArg( arg[2] ); // parameter + f2g_var[i_var] = rec.PutOp(op); + break; + // -------------------------------------------------------------- + // Binary operators, left variable, right parameter, one result + case SubvpOp: + case DivvpOp: + case PowvpOp: + case ZmulvpOp: +# ifndef NDEBUG + if( op == PowvpOp ) + { CPPAD_ASSERT_NARG_NRES(op, 2, 3); + } + else + { CPPAD_ASSERT_NARG_NRES(op, 2, 1); + } +# endif + CPPAD_ASSERT_UNKNOWN( size_t( f2g_var[ arg[0] ] ) < num_var ); + new_arg[0] = f2g_var[ arg[0] ]; + new_arg[1] = arg[1]; // parameter + rec.PutArg( new_arg[0], new_arg[1] ); + f2g_var[i_var] = rec.PutOp(op); + break; + // --------------------------------------------------- + // Binary operators, left index, right variable, one result + case DisOp: + CPPAD_ASSERT_UNKNOWN( size_t( f2g_var[ arg[1] ] ) < num_var ); + new_arg[0] = arg[0]; + new_arg[1] = f2g_var[ arg[1] ]; + rec.PutArg( new_arg[0], new_arg[1] ); + f2g_var[i_var] = rec.PutOp(op); + break; + + // -------------------------------------------------------------- + // Binary operators, left parameter, right variable, one result + case AddpvOp: + case SubpvOp: + case MulpvOp: + case DivpvOp: + case PowpvOp: + case ZmulpvOp: +# ifndef NDEBUG + if( op == PowpvOp ) + { CPPAD_ASSERT_NARG_NRES(op, 2, 3); + } + else + { CPPAD_ASSERT_NARG_NRES(op, 2, 1); + } +# endif + CPPAD_ASSERT_UNKNOWN( size_t( f2g_var[ arg[1] ] ) < num_var ); + new_arg[0] = arg[0]; // parameter + new_arg[1] = f2g_var[ arg[1] ]; + rec.PutArg( new_arg[0], new_arg[1] ); + f2g_var[i_var] = rec.PutOp(op); + break; + // -------------------------------------------------------------- + // Binary operators, left and right variables, one result + case AddvvOp: + case SubvvOp: + case MulvvOp: + case DivvvOp: + case PowvvOp: + case ZmulvvOp: +# ifndef NDEBUG + if( op == PowvvOp ) + { CPPAD_ASSERT_NARG_NRES(op, 2, 3); + } + else + { CPPAD_ASSERT_NARG_NRES(op, 2, 1); + } +# endif + CPPAD_ASSERT_UNKNOWN( size_t( f2g_var[ arg[0] ] ) < num_var ); + CPPAD_ASSERT_UNKNOWN( size_t( f2g_var[ arg[1] ] ) < num_var ); + new_arg[0] = f2g_var[ arg[0] ]; + new_arg[1] = f2g_var[ arg[1] ]; + rec.PutArg( new_arg[0], new_arg[1] ); + f2g_var[i_var] = rec.PutOp(op); + break; + // --------------------------------------------------- + // Conditional expression operators + case CExpOp: + CPPAD_ASSERT_NARG_NRES(op, 6, 1); + new_arg[0] = arg[0]; + new_arg[1] = arg[1]; + mask = 1; + for(size_t i = 2; i < 6; i++) + { if( arg[1] & mask ) + { CPPAD_ASSERT_UNKNOWN( size_t(f2g_var[arg[i]]) < num_var ); + new_arg[i] = f2g_var[ arg[i] ]; + } + else + new_arg[i] = arg[i]; // parameter + mask = mask << 1; + } + rec.PutArg( + new_arg[0] , + new_arg[1] , + new_arg[2] , + new_arg[3] , + new_arg[4] , + new_arg[5] + ); + f2g_var[i_var] = rec.PutOp(op); + break; + + // -------------------------------------------------- + // Operators with no arguments and no results + case EndOp: + CPPAD_ASSERT_NARG_NRES(op, 0, 0); + rec.PutOp(op); + more_operators = false; + break; + + // --------------------------------------------------- + // Operations with two arguments and no results + case LepvOp: + case LtpvOp: + case EqpvOp: + case NepvOp: + CPPAD_ASSERT_NARG_NRES(op, 2, 0); + new_arg[0] = arg[0]; // parameter + new_arg[1] = f2g_var[ arg[1] ]; + rec.PutArg(new_arg[0], new_arg[1]); + rec.PutOp(op); + break; + // + case LevpOp: + case LtvpOp: + CPPAD_ASSERT_NARG_NRES(op, 2, 0); + new_arg[0] = f2g_var[ arg[0] ]; + new_arg[1] = arg[1]; // parameter + rec.PutArg(new_arg[0], new_arg[1]); + rec.PutOp(op); + break; + // + case LevvOp: + case LtvvOp: + case EqvvOp: + case NevvOp: + CPPAD_ASSERT_NARG_NRES(op, 2, 0); + new_arg[0] = f2g_var[ arg[0] ]; + new_arg[1] = f2g_var[ arg[1] ]; + rec.PutArg(new_arg[0], new_arg[1]); + rec.PutOp(op); + break; + + // --------------------------------------------------- + // print forward operator + case PriOp: + CPPAD_ASSERT_NARG_NRES(op, 5, 0); + // + // arg[0] + new_arg[0] = arg[0]; + // + // arg[1] + if( arg[0] & 1 ) + { + CPPAD_ASSERT_UNKNOWN( size_t( f2g_var[ arg[1] ] ) < num_var ); + new_arg[1] = f2g_var[ arg[1] ]; + } + else + { new_arg[1] = arg[1]; // parameter + } + // + // arg[3] + if( arg[0] & 2 ) + { + CPPAD_ASSERT_UNKNOWN( size_t( f2g_var[ arg[3] ] ) < num_var ); + new_arg[3] = f2g_var[ arg[3] ]; + } + else + { new_arg[3] = arg[3]; // parameter + } + new_arg[2] = rec.PutTxt( play_.GetTxt(size_t(arg[2])) ); + new_arg[4] = rec.PutTxt( play_.GetTxt(size_t(arg[4])) ); + // + rec.PutArg( + new_arg[0] , + new_arg[1] , + new_arg[2] , + new_arg[3] , + new_arg[4] + ); + // no result + rec.PutOp(op); + break; + + // --------------------------------------------------- + // VecAD operators + + // Load using a parameter index + case LdpOp: + CPPAD_ASSERT_NARG_NRES(op, 3, 1); + new_arg[0] = arg[0]; + new_arg[1] = arg[1]; // parameter + new_arg[2] = arg[2]; + rec.PutArg( + new_arg[0], + new_arg[1], + new_arg[2] + ); + f2g_var[i_var] = rec.PutLoadOp(op); + break; + + // Load using a variable index + case LdvOp: + CPPAD_ASSERT_NARG_NRES(op, 3, 1); + CPPAD_ASSERT_UNKNOWN( size_t( f2g_var[ arg[1] ] ) < num_var ); + new_arg[0] = arg[0]; + new_arg[1] = f2g_var[ arg[1] ]; + new_arg[2] = arg[2]; + rec.PutArg( + new_arg[0], + new_arg[1], + new_arg[2] + ); + f2g_var[i_var] = rec.PutLoadOp(op); + break; + + // Store a parameter using a parameter index + case StppOp: + CPPAD_ASSERT_NARG_NRES(op, 3, 0); + new_arg[0] = arg[0]; + new_arg[1] = arg[1]; // parameter + new_arg[2] = arg[2]; // parameter + rec.PutArg( + new_arg[0], + new_arg[1], + new_arg[2] + ); + rec.PutOp(op); + break; + + // Store a parameter using a variable index + case StvpOp: + CPPAD_ASSERT_NARG_NRES(op, 3, 0); + CPPAD_ASSERT_UNKNOWN( size_t( f2g_var[ arg[1] ] ) < num_var ); + new_arg[0] = arg[0]; + new_arg[1] = f2g_var[ arg[1] ]; + new_arg[2] = arg[2]; // parameter + rec.PutArg( + new_arg[0], + new_arg[1], + new_arg[2] + ); + rec.PutOp(op); + break; + + // Store a variable using a parameter index + case StpvOp: + CPPAD_ASSERT_NARG_NRES(op, 3, 0); + CPPAD_ASSERT_UNKNOWN( size_t( f2g_var[ arg[2] ] ) < num_var ); + new_arg[0] = arg[0]; + new_arg[1] = arg[1]; // parameter + new_arg[2] = f2g_var[ arg[2] ]; + rec.PutArg( + new_arg[0], + new_arg[1], + new_arg[2] + ); + rec.PutOp(op); + break; + + // Store a variable using a variable index + case StvvOp: + CPPAD_ASSERT_NARG_NRES(op, 3, 0); + CPPAD_ASSERT_UNKNOWN( size_t( f2g_var[ arg[1] ] ) < num_var ); + CPPAD_ASSERT_UNKNOWN( size_t( f2g_var[ arg[2] ] ) < num_var ); + new_arg[0] = arg[0]; + new_arg[1] = f2g_var[ arg[1] ]; + new_arg[2] = f2g_var[ arg[2] ]; + rec.PutArg( + new_arg[0], + new_arg[1], + new_arg[2] + ); + break; + + // ----------------------------------------------------------- + // atomic function call operators + + case AFunOp: + CPPAD_ASSERT_NARG_NRES(op, 4, 0); + // atom_index, atom_old, atom_n, atom_m + rec.PutArg(arg[0], arg[1], arg[2], arg[3]); + rec.PutOp(AFunOp); + break; + + case FunapOp: + CPPAD_ASSERT_NARG_NRES(op, 1, 0); + new_arg[0] = arg[0]; // parameter + rec.PutArg(new_arg[0]); + rec.PutOp(FunapOp); + break; + + case FunavOp: + CPPAD_ASSERT_NARG_NRES(op, 1, 0); + CPPAD_ASSERT_UNKNOWN( size_t( f2g_var[arg[0]] ) < num_var ); + new_arg[0] = f2g_var[ arg[0] ]; + rec.PutArg(new_arg[0]); + rec.PutOp(FunavOp); + break; + + case FunrpOp: + CPPAD_ASSERT_NARG_NRES(op, 1, 0); + new_arg[0] = arg[0]; // parameter + rec.PutArg(new_arg[0]); + rec.PutOp(FunrpOp); + break; + + case FunrvOp: + CPPAD_ASSERT_NARG_NRES(op, 0, 1); + f2g_var[i_var] = rec.PutOp(FunrvOp); + break; + // --------------------------------------------------- + + // all cases should be handled above + default: + CPPAD_ASSERT_UNKNOWN(false); + } + if( more_operators ) + (++itr).op_info(op, arg, i_var); + } + // Check a few expected results + CPPAD_ASSERT_UNKNOWN( rec.num_op_rec() == play_.num_op_rec() ); + CPPAD_ASSERT_UNKNOWN( rec.num_var_rec() == play_.num_var_rec() ); + CPPAD_ASSERT_UNKNOWN( rec.num_var_load_rec() == play_.num_var_load_rec() ); + + // ----------------------------------------------------------------------- + // Use rec to create the function g + // ----------------------------------------------------------------------- + + // number of variables in the recording + g.num_var_tape_ = rec.num_var_rec(); + + // dimension cskip_op vector to number of operators + g.cskip_op_.resize( rec.num_op_rec() ); + + // independent variables in g: (x, u) + size_t s = f_abs_res.size(); + size_t n = Domain(); + g.ind_taddr_.resize(n + s); + // (x, u) + for(size_t j = 0; j < n; j++) + { g.ind_taddr_[j] = size_t( f2g_var[ ind_taddr_[j] ] ); + CPPAD_ASSERT_UNKNOWN( g.ind_taddr_[j] == j + 1 ); + } + for(size_t j = 0; j < s; j++) + { g.ind_taddr_[n + j] = size_t( f2g_var[ f_abs_res[j] ] ); + CPPAD_ASSERT_UNKNOWN( g.ind_taddr_[n + j] == n + j + 1 ); + } + + // dependent variable in g: (y, z) + CPPAD_ASSERT_UNKNOWN( s == f_abs_arg.size() ); + size_t m = Range(); + g.dep_taddr_.resize(m + s); + for(size_t i = 0; i < m; i++) + { g.dep_taddr_[i] = size_t( f2g_var[ dep_taddr_[i] ] ); + CPPAD_ASSERT_UNKNOWN( g.dep_taddr_[i] < num_var ); + } + for(size_t i = 0; i < s; i++) + { g.dep_taddr_[m + i] = size_t( f2g_var[ f_abs_arg[i] ] ); + CPPAD_ASSERT_UNKNOWN( g.dep_taddr_[m + i] < num_var ); + } + + // which dependent variables are parameters + g.dep_parameter_.resize(m + s); + for(size_t i = 0; i < m; i++) + g.dep_parameter_[i] = dep_parameter_[i]; + for(size_t i = 0; i < s; i++) + g.dep_parameter_[m + i] = false; + + // free memory allocated for sparse Jacobian calculation + // (the resutls are no longer valid) + g.for_jac_sparse_pack_.resize(0, 0); + g.for_jac_sparse_set_.resize(0, 0); + + // free taylor coefficient memory + g.taylor_.clear(); + g.num_order_taylor_ = 0; + g.cap_order_taylor_ = 0; + + // Transferring the recording swaps its vectors so do this last + // replace the recording in g (this ADFun object) + g.play_.get_recording(rec, n + s); + + // resize subgraph_info_ + g.subgraph_info_.resize( + g.ind_taddr_.size(), // n_ind + g.dep_taddr_.size(), // n_dep + g.play_.num_op_rec(), // n_op + g.play_.num_var_rec() // n_var + ); + + // ------------------------------------------------------------------------ + // Create the function a + // ------------------------------------------------------------------------ + + // start with a copy of f + a = *this; + + // dependent variables in a(x) + CPPAD_ASSERT_UNKNOWN( s == f_abs_arg.size() ); + a.dep_taddr_.resize(s); + for(size_t i = 0; i < s; i++) + { a.dep_taddr_[i] = f_abs_res[i]; + CPPAD_ASSERT_UNKNOWN( a.dep_taddr_[i] < num_var ); + } + + // free memory allocated for sparse Jacobian calculation + // (the resutls are no longer valid) + a.for_jac_sparse_pack_.resize(0, 0); + a.for_jac_sparse_set_.resize(0, 0); + + // free taylor coefficient memory + a.taylor_.clear(); + a.num_order_taylor_ = 0; + a.cap_order_taylor_ = 0; +} + +// preprocessor symbols that are local to this file +# undef CPPAD_J_PAR_EQUAL_REC + +} // END_CPPAD_NAMESPACE + +# endif diff --git a/build-config/cppad/include/cppad/core/ad.hpp b/build-config/cppad/include/cppad/core/ad.hpp new file mode 100644 index 00000000..99acdabb --- /dev/null +++ b/build-config/cppad/include/cppad/core/ad.hpp @@ -0,0 +1,311 @@ +# ifndef CPPAD_CORE_AD_HPP +# define CPPAD_CORE_AD_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +// simple AD operations that must be defined for AD as well as base class +# include +# include + +// define the template classes that are used by the AD template class +# include +# include +# include +# include +# include +# include + +namespace CppAD { // BEGIN_CPPAD_NAMESPACE + +// tape_manage_enum +typedef enum { + new_tape_manage, + delete_tape_manage +} +tape_manage_enum; + +template +class AD { +private : + // ----------------------------------------------------------------------- + // Base type value for this object + Base value_; + // + // tape for this object + tape_id_t tape_id_; + // + // tape address for this object + // (when tape_id is current tape for AD) + addr_t taddr_; + // + // sub-type for this object + // (when tape_id is current tape for AD) + ad_type_enum ad_type_; + // ----------------------------------------------------------------------- + + // enable use of AD in parallel mode + template + friend void parallel_ad(void); + + // template friend functions where template parameter is not bound + template + friend void Independent( + ADVector& x , + size_t abort_op_index , + bool record_compare , + ADVector& dynamic + ); + + // one argument functions + friend bool Constant (const AD &u); + friend bool Constant (const VecAD &u); + // + friend bool Dynamic (const AD &u); + friend bool Dynamic (const VecAD &u); + // + friend bool Parameter (const AD &u); + friend bool Parameter (const VecAD &u); + // + friend bool Variable (const AD &u); + friend bool Variable (const VecAD &u); + // + friend int Integer (const AD &u); + friend AD Var2Par (const AD &u); + // + friend unsigned short hash_code (const AD &u); + // + // power function + friend AD pow + (const AD &x, const AD &y); + + // azmul function + friend AD azmul + (const AD &x, const AD &y); + + // order determining functions, see ordered.hpp + friend bool GreaterThanZero (const AD &x); + friend bool GreaterThanOrZero (const AD &x); + friend bool LessThanZero (const AD &x); + friend bool LessThanOrZero (const AD &x); + friend bool abs_geq + (const AD& x, const AD& y); + + // The identical property functions, see identical.hpp + friend bool IdenticalCon (const AD &x); + friend bool IdenticalZero (const AD &x); + friend bool IdenticalOne (const AD &x); + friend bool IdenticalEqualCon + (const AD &x, const AD &y); + + // EqualOpSeq function + friend bool EqualOpSeq + (const AD &u, const AD &v); + + // NearEqual function + friend bool NearEqual ( + const AD &x, const AD &y, const Base &r, const Base &a); + + friend bool NearEqual ( + const Base &x, const AD &y, const Base &r, const Base &a); + + friend bool NearEqual ( + const AD &x, const Base &y, const Base &r, const Base &a); + + // CondExp function + friend AD CondExpOp ( + enum CompareOp cop , + const AD &left , + const AD &right , + const AD &trueCase , + const AD &falseCase + ); + + // classes + friend class local::ADTape; + friend class local::recorder; + friend class ADFun; + friend class atomic_base; + friend class atomic_three; + friend class discrete; + friend class VecAD; + friend class VecAD_reference; + + // arithematic binary operators + friend AD operator + + (const AD &left, const AD &right); + friend AD operator - + (const AD &left, const AD &right); + friend AD operator * + (const AD &left, const AD &right); + friend AD operator / + (const AD &left, const AD &right); + + // comparison operators + friend bool operator < + (const AD &left, const AD &right); + friend bool operator <= + (const AD &left, const AD &right); + friend bool operator > + (const AD &left, const AD &right); + friend bool operator >= + (const AD &left, const AD &right); + friend bool operator == + (const AD &left, const AD &right); + friend bool operator != + (const AD &left, const AD &right); + + // input operator + friend std::istream& operator >> + (std::istream &is, AD &x); + + // output operations + friend std::ostream& operator << + (std::ostream &os, const AD &x); + friend void PrintFor ( + const AD& flag , + const char* before , + const AD& var , + const char* after + ); +public: + // type of value + typedef Base value_type; + + // implicit default constructor + AD(void); + + // destructor + ~AD(void) { } + + // use default implicit copy constructor + // AD(const AD &x); + +# ifdef CPPAD_FOR_TMB + // TMB would rather have implicit construction from double, + // CppAD uses default constructor and assignment to double instead. + AD(const double &d); +# else + // implicit construction from base type + AD(const Base &b); +# endif + + // implicit contructor from VecAD::reference + AD(const VecAD_reference &x); + + // explicit construction from some other type (depricated) + template explicit AD(const T &t); + + // conversion from AD to Base type + friend Base Value (const AD &x); + + // use default assignment operator + // AD& operator=(const AD &x); + + // assingment from base type + AD& operator=(const Base &b); + + // assignment from VecAD::reference + AD& operator=(const VecAD_reference &x); + + // assignment from some other type + template AD& operator=(const T &right); + + // compound assignment operators + AD& operator += (const AD &right); + AD& operator -= (const AD &right); + AD& operator *= (const AD &right); + AD& operator /= (const AD &right); + + // unary operators + AD operator +(void) const; + AD operator -(void) const; + + // interface so these functions need not be friends + AD abs_me(void) const; + AD acos_me(void) const; + AD asin_me(void) const; + AD atan_me(void) const; + AD cos_me(void) const; + AD cosh_me(void) const; + AD exp_me(void) const; + AD fabs_me(void) const; + AD log_me(void) const; + AD sin_me(void) const; + AD sign_me(void) const; + AD sinh_me(void) const; + AD sqrt_me(void) const; + AD tan_me(void) const; + AD tanh_me(void) const; + AD asinh_me(void) const; + AD acosh_me(void) const; + AD atanh_me(void) const; + AD erf_me(bool complemnet) const; + AD expm1_me(void) const; + AD log1p_me(void) const; + + // ---------------------------------------------------------- + // static public member functions + + // abort current AD recording + static void abort_recording(void); + + // set the maximum number of OpenMP threads (deprecated) + static void omp_max_thread(size_t number); + + // These functions declared public so can be accessed by user through + // a macro interface and are not intended for direct use. + // The macro interface is documented in bool_fun.hpp. + // Developer documentation for these fucntions is in bool_fun.hpp + static bool UnaryBool( + bool FunName(const Base &x), + const AD &x + ); + static bool BinaryBool( + bool FunName(const Base &x, const Base &y), + const AD &x , const AD &y + ); + +private: + // ----------------------------------------------------------------- + // Make this parameter a new variable + void make_variable(tape_id_t id, addr_t taddr) + { CPPAD_ASSERT_UNKNOWN( Parameter(*this) ); // currently a par + CPPAD_ASSERT_UNKNOWN( taddr > 0 ); // sure valid taddr + + tape_id_ = id; + taddr_ = taddr; + ad_type_ = variable_enum; + } + // --------------------------------------------------------------- + // tape linking functions + // + // not static + local::ADTape* tape_this(void) const; + // + // static + static tape_id_t* tape_id_ptr(size_t thread); + static local::ADTape** tape_handle(size_t thread); + static local::ADTape* tape_manage(tape_manage_enum job); + static local::ADTape* tape_ptr(void); + static local::ADTape* tape_ptr(tape_id_t tape_id); +}; +// --------------------------------------------------------------------------- + +} // END_CPPAD_NAMESPACE + +// tape linking private functions +# include + +// operations that expect the AD template class to be defined + + +# endif diff --git a/build-config/cppad/include/cppad/core/ad_assign.hpp b/build-config/cppad/include/cppad/core/ad_assign.hpp new file mode 100644 index 00000000..7da1c79b --- /dev/null +++ b/build-config/cppad/include/cppad/core/ad_assign.hpp @@ -0,0 +1,144 @@ +# ifndef CPPAD_CORE_AD_ASSIGN_HPP +# define CPPAD_CORE_AD_ASSIGN_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-18 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +/* +------------------------------------------------------------------------------ + +$begin ad_assign$$ +$spell + Vec + const +$$ + + +$section AD Assignment Operator$$ + +$head Syntax$$ +$icode%y% = %x%$$ + +$head Purpose$$ +Assigns the value in $icode x$$ to the object $icode y$$. +In either case, + +$head x$$ +The argument $icode x$$ has prototype +$codei% + const %Type% &%x% +%$$ +where $icode Type$$ is +$codei%VecAD<%Base%>::reference%$$, +$codei%AD<%Base%>%$$, +$icode Base$$, +or any type that has an implicit constructor of the form +$icode%Base%(%x%)%$$. + +$head y$$ +The target $icode y$$ has prototype +$codei% + AD<%Base%> %y% +%$$ + +$head Example$$ +$children% + example/general/ad_assign.cpp +%$$ +The file $cref ad_assign.cpp$$ contain examples and tests of these operations. +It test returns true if it succeeds and false otherwise. + +$end +------------------------------------------------------------------------------ +*/ + +namespace CppAD { // BEGIN_CPPAD_NAMESPACE + +/*! +\file ad_assign.hpp +AD constructors and and copy operations. +*/ + +/*! +\page AD_default_assign +Use default assignment operator +because they may be optimized better than the code below: +\code +template +AD& AD::operator=(const AD &right) +{ value_ = right.value_; + tape_id_ = right.tape_id_; + taddr_ = right.taddr_; + ad_type_ = right.ad_type_; + + return *this; +} +\endcode +*/ + +/*! +Assignment to Base type value. + +\tparam Base +Base type for this AD object. + +\param b +is the Base type value being assignment to this AD object. +The tape identifier will be an invalid tape identifier, +so this object is initially a parameter. +*/ +template +AD& AD::operator=(const Base &b) +{ value_ = b; + tape_id_ = 0; + // + CPPAD_ASSERT_UNKNOWN( ! ( Variable(*this) | Dynamic(*this) ) ); + return *this; +} + +/*! +Assignment to an ADVec element drops the vector information. + +\tparam Base +Base type for this AD object. +*/ +template +AD& AD::operator=(const VecAD_reference &x) +{ *this = x.ADBase(); + CPPAD_ASSERT_UNKNOWN( ! Dynamic(*this) ); + return *this; +} + +/*! +Assignment from any other type, converts to Base type, and then uses assignment +from Base type. + +\tparam Base +Base type for this AD object. + +\tparam T +is the the type that is being assigned to AD. +There must be an assignment for Base from Type. + +\param t +is the object that is being assigned to an AD object. +*/ +template +template +AD& AD::operator=(const T &t) +{ *this = Base(t); + CPPAD_ASSERT_UNKNOWN( ! ( Variable(*this) | Dynamic(*this) ) ); + return *this; +} + + +} // END_CPPAD_NAMESPACE +# endif diff --git a/build-config/cppad/include/cppad/core/ad_binary.hpp b/build-config/cppad/include/cppad/core/ad_binary.hpp new file mode 100644 index 00000000..e7c73218 --- /dev/null +++ b/build-config/cppad/include/cppad/core/ad_binary.hpp @@ -0,0 +1,143 @@ +# ifndef CPPAD_CORE_AD_BINARY_HPP +# define CPPAD_CORE_AD_BINARY_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-18 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +/* +------------------------------------------------------------------------------- +$begin ad_binary$$ +$spell + Op + VecAD + const +$$ + +$section AD Binary Arithmetic Operators$$ + + + + + + + +$head Syntax$$ +$icode%z% = %x% %Op% %y%$$ + +$head Purpose$$ +Performs arithmetic operations where either $icode x$$ or $icode y$$ +has type +$codei%AD<%Base%>%$$ or +$cref%VecAD::reference%VecAD%VecAD::reference%$$. + +$head Op$$ +The operator $icode Op$$ is one of the following +$table +$bold Op$$ $cnext $bold Meaning$$ $rnext +$code +$$ $cnext $icode z$$ is $icode x$$ plus $icode y$$ $rnext +$code -$$ $cnext $icode z$$ is $icode x$$ minus $icode y$$ $rnext +$code *$$ $cnext $icode z$$ is $icode x$$ times $icode y$$ $rnext +$code /$$ $cnext $icode z$$ is $icode x$$ divided by $icode y$$ +$tend + +$head Base$$ +The type $icode Base$$ is determined by the operand that +has type $codei%AD<%Base%>%$$ or $codei%VecAD<%Base%>::reference%$$. + +$head x$$ +The operand $icode x$$ has the following prototype +$codei% + const %Type% &%x% +%$$ +where $icode Type$$ is +$codei%VecAD<%Base%>::reference%$$, +$codei%AD<%Base%>%$$, +$icode Base$$, or +$code double$$. + +$head y$$ +The operand $icode y$$ has the following prototype +$codei% + const %Type% &%y% +%$$ +where $icode Type$$ is +$codei%VecAD<%Base%>::reference%$$, +$codei%AD<%Base%>%$$, +$icode Base$$, or +$code double$$. + + +$head z$$ +The result $icode z$$ has the following prototype +$codei% + %Type% %z% +%$$ +where $icode Type$$ is +$codei%AD<%Base%>%$$. + +$head Operation Sequence$$ +This is an $cref/atomic_base/glossary/Operation/Atomic/$$ +$cref/AD of Base/glossary/AD of Base/$$ operation +and hence it is part of the current +AD of $icode Base$$ +$cref/operation sequence/glossary/Operation/Sequence/$$. + +$children% + example/general/add.cpp% + example/general/sub.cpp% + example/general/mul.cpp% + example/general/div.cpp +%$$ + +$head Example$$ +The following files contain examples and tests of these functions. +Each test returns true if it succeeds and false otherwise. +$table +$rref add.cpp$$ +$rref sub.cpp$$ +$rref mul.cpp$$ +$rref div.cpp$$ +$tend + +$head Derivative$$ +If $latex f$$ and $latex g$$ are +$cref/Base functions/glossary/Base Function/$$ + +$subhead Addition$$ +$latex \[ + \D{[ f(x) + g(x) ]}{x} = \D{f(x)}{x} + \D{g(x)}{x} +\] $$ + +$subhead Subtraction$$ +$latex \[ + \D{[ f(x) - g(x) ]}{x} = \D{f(x)}{x} - \D{g(x)}{x} +\] $$ + +$subhead Multiplication$$ +$latex \[ + \D{[ f(x) * g(x) ]}{x} = g(x) * \D{f(x)}{x} + f(x) * \D{g(x)}{x} +\] $$ + +$subhead Division$$ +$latex \[ + \D{[ f(x) / g(x) ]}{x} = + [1/g(x)] * \D{f(x)}{x} - [f(x)/g(x)^2] * \D{g(x)}{x} +\] $$ + +$end +----------------------------------------------------------------------------- +*/ +# include +# include +# include +# include + +# endif diff --git a/build-config/cppad/include/cppad/core/ad_ctor.hpp b/build-config/cppad/include/cppad/core/ad_ctor.hpp new file mode 100644 index 00000000..27506f36 --- /dev/null +++ b/build-config/cppad/include/cppad/core/ad_ctor.hpp @@ -0,0 +1,199 @@ +# ifndef CPPAD_CORE_AD_CTOR_HPP +# define CPPAD_CORE_AD_CTOR_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-18 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +/* +------------------------------------------------------------------------------ + +$begin ad_ctor$$ +$spell + cppad + ctor + initializes + Vec + const +$$ + + +$section AD Constructors $$ + +$head Syntax$$ +$codei%AD<%Base%> %y%() +%$$ +$codei%AD<%Base%> %y%(%x%) +%$$ + +$head Purpose$$ +creates a new $codei%AD<%Base%>%$$ object $icode y$$ +and initializes its value as equal to $icode x$$. + +$head x$$ + +$subhead implicit$$ +There is an implicit constructor where $icode x$$ has one of the following +prototypes: +$codei% + const %Base%& %x% + const VecAD<%Base%>& %x% +%$$ + +$subhead explicit$$ +There is an explicit constructor where $icode x$$ has prototype +$codei% + const %Type%& %x% +%$$ +for any type that has an explicit constructor of the form +$icode%Base%(%x%)%$$. + +$head y$$ +The target $icode y$$ has prototype +$codei% + AD<%Base%> %y% +%$$ + +$head Example$$ +$children% + example/general/ad_ctor.cpp +%$$ +The files $cref ad_ctor.cpp$$ contain examples and tests of these operations. +It test returns true if it succeeds and false otherwise. + +$end +------------------------------------------------------------------------------ +*/ + +namespace CppAD { // BEGIN_CPPAD_NAMESPACE + +/*! +\file ad_ctor.hpp +AD constructors and and copy operations. +*/ + +/*! +\page AD_default_ctor +Use default copy constructor +because they may be optimized better than the code below: +\code +template +AD::AD(const AD &x) +{ + value_ = x.value_; + tape_id_ = x.tape_id_; + taddr_ = x.taddr_; + ad_type_ = x.ad_type_; + + return; +} +\endcode +*/ + +/*! +Default Constructor. + +\tparam Base +Base type for this AD object. +*/ +template +AD::AD(void) +: value_() +, tape_id_(0) +, taddr_(0) +, ad_type_(constant_enum) +{ } + +// -------------------------------------------------------------------------- +# ifdef CPPAD_FOR_TMB +/*! +Constructor from double. + +\param d +is value corresponding to this AD object. +The tape identifier will be an invalid tape identifier, +so this object is initially a parameter. + +\par CPPAD_FOR_TMB +This constructor is defined when CPPAD_FOR_TMB is defined. +*/ +template +AD::AD(const double &d) +: value_( Base(d) ) +, tape_id_(0) +, taddr_(0) +, ad_type_(constant_enum) +{ // check that this is a parameter + CPPAD_ASSERT_UNKNOWN( Parameter(*this) ); +} +// -------------------------------------------------------------------------- +# else +// -------------------------------------------------------------------------- +/*! +Constructor from Base type. + +\tparam Base +Base type for this AD object. + +\param b +is the Base type value corresponding to this AD object. +The tape identifier will be an invalid tape identifier, +so this object is initially a parameter. + +\par CPPAD_FOR_TMB +This constructor is defined when CPPAD_FOR_TMB is not defined. +*/ +template +AD::AD(const Base &b) +: value_(b) +, tape_id_(0) +, taddr_(0) +, ad_type_(constant_enum) +{ // check that this is a parameter + CPPAD_ASSERT_UNKNOWN( Parameter(*this) ); +} +# endif +// -------------------------------------------------------------------------- + +/*! +Constructor from an ADVec element drops the vector information. + +\tparam Base +Base type for this AD object. +*/ +template +AD::AD(const VecAD_reference &x) +{ *this = x.ADBase(); } + +/*! +Constructor from any other type, converts to Base type, and uses constructor +from Base type. + +\tparam Base +Base type for this AD object. + +\tparam T +is the the type that is being converted to AD. +There must be a constructor for Base from Type. + +\param t +is the object that is being converted from T to AD. +*/ +template +template +AD::AD(const T &t) +: value_(Base(t)) +, tape_id_(0) +, taddr_(0) +, ad_type_(constant_enum) +{ } + +} // END_CPPAD_NAMESPACE +# endif diff --git a/build-config/cppad/include/cppad/core/ad_fun.hpp b/build-config/cppad/include/cppad/core/ad_fun.hpp new file mode 100644 index 00000000..6dd5885a --- /dev/null +++ b/build-config/cppad/include/cppad/core/ad_fun.hpp @@ -0,0 +1,876 @@ +# ifndef CPPAD_CORE_AD_FUN_HPP +# define CPPAD_CORE_AD_FUN_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ +/* +$begin ADFun$$ +$spell + xk + Ind + bool + taylor_ + sizeof + const + std + ind_taddr_ + dep_taddr_ +$$ + +$spell +$$ + +$section ADFun Objects$$ + + +$head Purpose$$ +An AD of $icode Base$$ +$cref/operation sequence/glossary/Operation/Sequence/$$ +is stored in an $code ADFun$$ object by its $cref FunConstruct$$. +The $code ADFun$$ object can then be used to calculate function values, +derivative values, and other values related to the corresponding function. + +$childtable% + omh/adfun.omh% + include/cppad/core/optimize.hpp% + include/cppad/core/fun_check.hpp% + include/cppad/core/check_for_nan.hpp +%$$ + +$end +*/ +# include +# include +# include + +namespace CppAD { // BEGIN_CPPAD_NAMESPACE +/*! +\file ad_fun.hpp +File used to define the ADFun class. +*/ + +/*! +Class used to hold function objects + +\tparam Base +A function object has a recording of AD operations. +It does it calculations using Base operations. +*/ + + +template +class ADFun { + // ADFun must be a friend of ADFun< AD > for base2ad to work. + template friend class ADFun; +private: + // ------------------------------------------------------------ + // Private member variables + // ------------------------------------------------------------ + + /// name of this function (so far only json operations use this value) + std::string function_name_; + + /// Did the previous optimzation exceed the collision limit + bool exceed_collision_limit_; + + /// Has this ADFun object been optmized + bool has_been_optimized_; + + /// Check for nan's and report message to user (default value is true). + bool check_for_nan_; + + /// If zero, ignoring comparison operators. Otherwise is the + /// compare change count at which to store the operator index. + size_t compare_change_count_; + + /// If compare_change_count_ is zero, compare_change_number_ is also zero. + /// Otherwise, it is set to the number of comparison operations that had a + /// different result during the subsequent zero order forward. + size_t compare_change_number_; + + /// If compare_change_count is zero, compare_change_op_index_ is also + /// zero. Otherwise it is the operator index for the comparison operator + //// that corresponded to the number changing from count-1 to count. + size_t compare_change_op_index_; + + /// number of orders stored in taylor_ + size_t num_order_taylor_; + + /// maximum number of orders that will fit in taylor_ + size_t cap_order_taylor_; + + /// number of directions stored in taylor_ + size_t num_direction_taylor_; + + /// number of variables in the recording (play_) + size_t num_var_tape_; + + /// tape address for the independent variables + local::pod_vector ind_taddr_; + + /// tape address and parameter flag for the dependent variables + local::pod_vector dep_taddr_; + + /// which dependent variables are actually parameters + local::pod_vector dep_parameter_; + + /// which operations can be conditionally skipped + /// Set during forward pass of order zero + local::pod_vector cskip_op_; + + /// Variable on the tape corresponding to each vecad load operation + /// (if zero, the operation corresponds to a parameter). + local::pod_vector load_op2var_; + + /// results of the forward mode calculations + local::pod_vector_maybe taylor_; + + /// used for subgraph reverse mode calculations. + /// Declared here to avoid reallocation for each call to subgraph_reverse. + /// Not in subgraph_info_ because it depends on Base. + local::pod_vector_maybe subgraph_partial_; + + /// the operation sequence corresponding to this object + local::player play_; + + /// subgraph information for this object + local::subgraph::subgraph_info subgraph_info_; + + /// Packed results of the forward mode Jacobian sparsity calculations. + /// for_jac_sparse_pack_.n_set() != 0 implies other sparsity results + /// are empty + local::sparse::pack_setvec for_jac_sparse_pack_; + + /// Set results of the forward mode Jacobian sparsity calculations + /// for_jac_sparse_set_.n_set() != 0 implies for_sparse_pack_ is empty. + local::sparse::list_setvec for_jac_sparse_set_; + + + // ------------------------------------------------------------ + // Private member functions + // ------------------------------------------------------------ + + /// change the operation sequence corresponding to this object + template + void Dependent(local::ADTape *tape, const ADvector &y); + + // vector of bool version of ForSparseJac + // (doxygen in cppad/core/for_sparse_jac.hpp) + template + void ForSparseJacCase( + bool set_type , + bool transpose , + bool dependency, + size_t q , + const SetVector& r , + SetVector& s + ); + + // vector of std::set version of ForSparseJac + // (doxygen in cppad/core/for_sparse_jac.hpp) + template + void ForSparseJacCase( + const std::set& set_type , + bool transpose , + bool dependency, + size_t q , + const SetVector& r , + SetVector& s + ); + + // vector of bool version of RevSparseJac + // (doxygen in cppad/core/rev_sparse_jac.hpp) + template + void RevSparseJacCase( + bool set_type , + bool transpose , + bool dependency, + size_t p , + const SetVector& s , + SetVector& r + ); + + // vector of std::set version of RevSparseJac + // (doxygen in cppad/core/rev_sparse_jac.hpp) + template + void RevSparseJacCase( + const std::set& set_type , + bool transpose , + bool dependency, + size_t p , + const SetVector& s , + SetVector& r + ); + + // vector of bool version of ForSparseHes + // (doxygen in cppad/core/for_sparse_hes.hpp) + template + void ForSparseHesCase( + bool set_type , + const SetVector& r , + const SetVector& s , + SetVector& h + ); + + // vector of std::set version of ForSparseHes + // (doxygen in cppad/core/for_sparse_hes.hpp) + template + void ForSparseHesCase( + const std::set& set_type , + const SetVector& r , + const SetVector& s , + SetVector& h + ); + + // vector of bool version of RevSparseHes + // (doxygen in cppad/core/rev_sparse_hes.hpp) + template + void RevSparseHesCase( + bool set_type , + bool transpose , + size_t q , + const SetVector& s , + SetVector& h + ); + + // vector of std::set version of RevSparseHes + // (doxygen in cppad/core/rev_sparse_hes.hpp) + template + void RevSparseHesCase( + const std::set& set_type , + bool transpose , + size_t q , + const SetVector& s , + SetVector& h + ); + + // Forward mode version of SparseJacobian + // (doxygen in cppad/core/sparse_jacobian.hpp) + template + size_t SparseJacobianFor( + const BaseVector& x , + SetVector& p_transpose , + const SizeVector& row , + const SizeVector& col , + BaseVector& jac , + sparse_jacobian_work& work + ); + + // Reverse mode version of SparseJacobian + // (doxygen in cppad/core/sparse_jacobian.hpp) + template + size_t SparseJacobianRev( + const BaseVector& x , + SetVector& p , + const SizeVector& row , + const SizeVector& col , + BaseVector& jac , + sparse_jacobian_work& work + ); + + // combined sparse_list and sparse_pack version of SparseHessian + // (doxygen in cppad/core/sparse_hessian.hpp) + template + size_t SparseHessianCompute( + const BaseVector& x , + const BaseVector& w , + SetVector& sparsity , + const SizeVector& row , + const SizeVector& col , + BaseVector& hes , + sparse_hessian_work& work + ); + +public: + /// default constructor + ADFun(void); + + /// copy constructor + ADFun(const ADFun& g) = delete; + + // assignment operator + // (doxygen in cppad/core/fun_construct.hpp) + void operator=(const ADFun& f); + + // swap + void swap(ADFun& f); + + // move semenatics copy + ADFun(ADFun&& f); + + // move semantics assignment + void operator=(ADFun&& f); + + // create from Json or C++ AD graph + void from_json(const std::string& json); + void from_graph(const cpp_graph& graph_obj); + void from_graph( + const cpp_graph& graph_obj , + const vector& dyn2var , + const vector& var2dyn + ); + + // create a Json or C++ AD graph + std::string to_json(void); + void to_graph(cpp_graph& graph_obj); + + // create ADFun< AD > from this ADFun + // (doxygen in cppad/core/base2ad.hpp) + ADFun< AD, RecBase > base2ad(void) const; + + /// sequence constructor + template + ADFun(const ADvector &x, const ADvector &y); + + /// destructor + ~ADFun(void); + + /// set check_for_nan + void check_for_nan(bool value); + + /// get check_for_nan + bool check_for_nan(void) const; + + /// assign a new operation sequence + template + void Dependent(const ADvector &x, const ADvector &y); + + /// new_dynamic user API + template + void new_dynamic(const BaseVector& dynamic); + + /// forward mode user API, one order multiple directions. + template + BaseVector Forward(size_t q, size_t r, const BaseVector& x); + + /// forward mode user API, multiple orders one direction. + template + BaseVector Forward( + size_t q, const BaseVector& xq, std::ostream& s = std::cout + ); + + /// reverse mode sweep + template + BaseVector Reverse(size_t p, const BaseVector &v); + + // forward Jacobian sparsity pattern + // (doxygen in cppad/core/for_sparse_jac.hpp) + template + SetVector ForSparseJac( + size_t q, const SetVector &r, bool transpose = false, + bool dependency = false + ); + + // reverse Jacobian sparsity pattern + // (doxygen in cppad/core/rev_sparse_jac.hpp) + template + SetVector RevSparseJac( + size_t q, const SetVector &s, bool transpose = false, + bool dependency = false + ); + + // subgraph_reverse: select domain + // (doxygen in cppad/core/subgraph_reverse.hpp) + template + void subgraph_reverse( + const BoolVector& select_domain + ); + + // subgraph_reverse: compute derivative + // (doxygen in cppad/core/subgraph_reverse.hpp) + template + void subgraph_reverse_helper( + size_t q , + size_t ell , + SizeVector& col , + BaseVector& dw + ); + + // subgraph_reverse: compute derivative + // (doxygen in cppad/core/subgraph_reverse.hpp) + template + void subgraph_reverse( + size_t q , + size_t ell , + SizeVector& col , + BaseVector& dw + ); + + // subgraph_jac_rev: compute Jacobian + // (doxygen in cppad/core/subgraph_jac_rev.hpp) + template + void subgraph_jac_rev( + const BaseVector& x , + sparse_rcv& subset + ); + + // subgraph_jac_rev: compute Jacobian + // (doxygen missing in cppad/core/subgraph_jac_rev.hpp) + template + void subgraph_jac_rev( + const BoolVector& select_domain , + const BoolVector& select_range , + const BaseVector& x , + sparse_rcv& matrix_out + ); + + + // compute sparse Jacobian using forward mode + // (doxygen in cppad/core/sparse_jac.hpp) + template + size_t sparse_jac_for( + size_t group_max , + const BaseVector& x , + sparse_rcv& subset , + const sparse_rc& pattern , + const std::string& coloring , + sparse_jac_work& work + ); + + // compute sparse Jacobian using reverse mode + // (doxygen in cppad/core/sparse_jac.hpp) + template + size_t sparse_jac_rev( + const BaseVector& x , + sparse_rcv& subset , + const sparse_rc& pattern , + const std::string& coloring , + sparse_jac_work& work + ); + + // compute sparse Hessian + // (doxygen in cppad/core/sparse_hes.hpp) + template + size_t sparse_hes( + const BaseVector& x , + const BaseVector& w , + sparse_rcv& subset , + const sparse_rc& pattern , + const std::string& coloring , + sparse_hes_work& work + ); + + // compute sparsity pattern using subgraphs + // (doxygen in cppad/core/subgraph_sparsity.hpp) + template + void subgraph_sparsity( + const BoolVector& select_domain , + const BoolVector& select_range , + bool transpose , + sparse_rc& pattern_out + ); + + + // forward mode Jacobian sparsity pattern + // (doxygen in cppad/core/for_jac_sparsity.hpp) + template + void for_jac_sparsity( + const sparse_rc& pattern_in , + bool transpose , + bool dependency , + bool internal_bool , + sparse_rc& pattern_out + ); + + // reverse mode Jacobian sparsity pattern + // (doxygen in cppad/core/for_jac_sparsity.hpp) + template + void rev_jac_sparsity( + const sparse_rc& pattern_in , + bool transpose , + bool dependency , + bool internal_bool , + sparse_rc& pattern_out + ); + + // reverse mode Hessian sparsity pattern + // (doxygen in cppad/core/rev_hes_sparsity.hpp) + template + void rev_hes_sparsity( + const BoolVector& select_range , + bool transpose , + bool internal_bool , + sparse_rc& pattern_out + ); + + // forward mode Hessian sparsity pattern + // (doxygen in cppad/core/for_hes_sparsity.hpp) + template + void for_hes_sparsity( + const BoolVector& select_domain , + const BoolVector& select_range , + bool internal_bool , + sparse_rc& pattern_out + ); + + // forward mode Hessian sparsity pattern + // (see doxygen in cppad/core/for_sparse_hes.hpp) + template + SetVector ForSparseHes( + const SetVector &r, const SetVector &s + ); + + // internal set sparsity version of ForSparseHes + // (used by checkpoint functions only) + void ForSparseHesCheckpoint( + vector& r , + vector& s , + local::sparse::list_setvec& h + ); + + // reverse mode Hessian sparsity pattern + // (see doxygen in cppad/core/rev_sparse_hes.hpp) + template + SetVector RevSparseHes( + size_t q, const SetVector &s, bool transpose = false + ); + + // internal set sparsity version of RevSparseHes + // (doxygen in cppad/core/rev_sparse_hes.hpp) + // (used by checkpoint functions only) + void RevSparseHesCheckpoint( + size_t q , + vector& s , + bool transpose , + local::sparse::list_setvec& h + ); + + // internal set sparsity version of RevSparseJac + // (doxygen in cppad/core/rev_sparse_jac.hpp) + // (used by checkpoint functions only) + void RevSparseJacCheckpoint( + size_t q , + const local::sparse::list_setvec& r , + bool transpose , + bool dependency , + local::sparse::list_setvec& s + ); + + // internal set sparsity version of RevSparseJac + // (doxygen in cppad/core/for_sparse_jac.hpp) + // (used by checkpoint functions only) + void ForSparseJacCheckpoint( + size_t q , + const local::sparse::list_setvec& r , + bool transpose , + bool dependency , + local::sparse::list_setvec& s + ); + + /// did previous optimization exceed the collision limit + bool exceed_collision_limit(void) const + { return exceed_collision_limit_; } + + /// amount of memory used for boolean Jacobain sparsity pattern + size_t size_forward_bool(void) const + { return for_jac_sparse_pack_.memory(); } + + /// free memory used for Jacobain sparsity pattern + void size_forward_bool(size_t zero) + { CPPAD_ASSERT_KNOWN( + zero == 0, + "size_forward_bool: argument not equal to zero" + ); + for_jac_sparse_pack_.resize(0, 0); + } + + /// amount of memory used for vector of set Jacobain sparsity pattern + size_t size_forward_set(void) const + { return for_jac_sparse_set_.memory(); } + + /// free memory used for Jacobain sparsity pattern + void size_forward_set(size_t zero) + { CPPAD_ASSERT_KNOWN( + zero == 0, + "size_forward_bool: argument not equal to zero" + ); + for_jac_sparse_set_.resize(0, 0); + } + + /// number of operators in the operation sequence + size_t size_op(void) const + { return play_.num_op_rec(); } + + /// number of operator arguments in the operation sequence + size_t size_op_arg(void) const + { return play_.num_op_arg_rec(); } + + /// amount of memory required for the operation sequence + size_t size_op_seq(void) const + { return play_.size_op_seq(); } + + /// amount of memory currently allocated for random access + /// of the operation sequence + size_t size_random(void) const + { return play_.size_random(); } + + /// number of parameters in the operation sequence + size_t size_par(void) const + { return play_.num_par_rec(); } + + /// number of independent dynamic parameters + size_t size_dyn_ind(void) const + { return play_.num_dynamic_ind(); } + + /// number of dynamic parameters + size_t size_dyn_par(void) const + { return play_.num_dynamic_par(); } + + /// number of dynamic parameters arguments + size_t size_dyn_arg(void) const + { return play_.num_dynamic_arg(); } + + /// number taylor coefficient orders calculated + size_t size_order(void) const + { return num_order_taylor_; } + + /// number taylor coefficient directions calculated + size_t size_direction(void) const + { return num_direction_taylor_; } + + /// number of characters in the operation sequence + size_t size_text(void) const + { return play_.num_text_rec(); } + + /// number of variables in opertion sequence + size_t size_var(void) const + { return num_var_tape_; } + + /// number of VecAD indices in the operation sequence + size_t size_VecAD(void) const + { return play_.num_var_vecad_ind_rec(); } + + /// set number of orders currently allocated (user API) + void capacity_order(size_t c); + + /// set number of orders and directions currently allocated + void capacity_order(size_t c, size_t r); + + /// number of variables in conditional expressions that can be skipped + size_t number_skip(void); + + /// number of independent variables + size_t Domain(void) const + { return ind_taddr_.size(); } + + /// number of dependent variables + size_t Range(void) const + { return dep_taddr_.size(); } + + /// is variable a parameter + bool Parameter(size_t i) + { CPPAD_ASSERT_KNOWN( + i < dep_taddr_.size(), + "Argument to Parameter is >= dimension of range space" + ); + return dep_parameter_[i]; + } + + /// Deprecated: number of comparison operations that changed + /// for the previous zero order forward (than when function was recorded) + size_t CompareChange(void) const + { return compare_change_number_; } + + /// count as which to store operator index + void compare_change_count(size_t count) + { compare_change_count_ = count; + compare_change_number_ = 0; + compare_change_op_index_ = 0; + } + + /// number of comparison operations that changed + size_t compare_change_number(void) const + { return compare_change_number_; } + + /// operator index for the count-th comparison change + size_t compare_change_op_index(void) const + { if( has_been_optimized_ ) + return 0; + return compare_change_op_index_; + } + + /// calculate entire Jacobian + template + BaseVector Jacobian(const BaseVector &x); + + /// calculate Hessian for one component of f + template + BaseVector Hessian(const BaseVector &x, const BaseVector &w); + template + BaseVector Hessian(const BaseVector &x, size_t i); + + /// forward mode calculation of partial w.r.t one domain component + template + BaseVector ForOne( + const BaseVector &x , + size_t j ); + + /// reverse mode calculation of derivative of one range component + template + BaseVector RevOne( + const BaseVector &x , + size_t i ); + + /// forward mode calculation of a subset of second order partials + template + BaseVector ForTwo( + const BaseVector &x , + const SizeVector_t &J , + const SizeVector_t &K ); + + /// reverse mode calculation of a subset of second order partials + template + BaseVector RevTwo( + const BaseVector &x , + const SizeVector_t &I , + const SizeVector_t &J ); + + /// calculate sparse Jacobians + template + BaseVector SparseJacobian( + const BaseVector &x + ); + template + BaseVector SparseJacobian( + const BaseVector &x , + const SetVector &p + ); + template + size_t SparseJacobianForward( + const BaseVector& x , + const SetVector& p , + const SizeVector& r , + const SizeVector& c , + BaseVector& jac , + sparse_jacobian_work& work + ); + template + size_t SparseJacobianReverse( + const BaseVector& x , + const SetVector& p , + const SizeVector& r , + const SizeVector& c , + BaseVector& jac , + sparse_jacobian_work& work + ); + + /// calculate sparse Hessians + template + BaseVector SparseHessian( + const BaseVector& x , + const BaseVector& w + ); + template + BaseVector SparseHessian( + const BaseVector& x , + const BaseVector& w , + const BoolVector& p + ); + template + size_t SparseHessian( + const BaseVector& x , + const BaseVector& w , + const SetVector& p , + const SizeVector& r , + const SizeVector& c , + BaseVector& hes , + sparse_hessian_work& work + ); + + // Optimize the tape + // (see doxygen documentation in optimize.hpp) + void optimize( const std::string& options = "" ); + + // create abs-normal representation of the function f(x) + void abs_normal_fun( ADFun& g, ADFun& a ) const; + + // clear all subgraph information + void clear_subgraph(void); + // ------------------- Deprecated ----------------------------- + + /// deprecated: assign a new operation sequence + template + void Dependent(const ADvector &y); + + /// Deprecated: number of variables in opertion sequence + size_t Size(void) const + { return num_var_tape_; } + + /// Deprecated: # taylor_ coefficients currently stored + /// (per variable,direction) + size_t Order(void) const + { return num_order_taylor_ - 1; } + + /// Deprecated: amount of memory for this object + /// Note that an approximation is used for the std::set memory + size_t Memory(void) const + { size_t pervar = cap_order_taylor_ * sizeof(Base) + + for_jac_sparse_pack_.memory() + + for_jac_sparse_set_.memory(); + size_t total = num_var_tape_ * pervar; + total += play_.size_op_seq(); + total += play_.size_random(); + total += subgraph_info_.memory(); + return total; + } + + /// Deprecated: # taylor_ coefficient orderss stored + /// (per variable,direction) + size_t taylor_size(void) const + { return num_order_taylor_; } + + /// Deprecated: Does this AD operation sequence use + /// VecAD::reference operands + bool use_VecAD(void) const + { return play_.num_var_vecad_ind_rec() > 0; } + + /// Deprecated: # taylor_ coefficient orders calculated + /// (per variable,direction) + size_t size_taylor(void) const + { return num_order_taylor_; } + + /// Deprecated: set number of orders currently allocated + /// (per variable,direction) + void capacity_taylor(size_t per_var); +}; +// --------------------------------------------------------------------------- + +} // END_CPPAD_NAMESPACE + +// non-user interfaces +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include + +// user interfaces +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include + +# endif diff --git a/build-config/cppad/include/cppad/core/ad_io.hpp b/build-config/cppad/include/cppad/core/ad_io.hpp new file mode 100644 index 00000000..4ac757ab --- /dev/null +++ b/build-config/cppad/include/cppad/core/ad_io.hpp @@ -0,0 +1,220 @@ +# ifndef CPPAD_CORE_AD_IO_HPP +# define CPPAD_CORE_AD_IO_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +/* +$begin ad_input$$ +$spell + VecAD + std + istream + const +$$ + + +$section AD Input Stream Operator$$ + +$head Syntax$$ +$icode%is% >> %x%$$ + +$head Purpose$$ +Sets $icode x$$ to a $cref/parameter/glossary/Parameter/$$ +with value $icode b$$ corresponding to +$codei% + %is% >> %b% +%$$ +where $icode b$$ is a $icode Base$$ object. +It is assumed that this $icode Base$$ input operation returns +a reference to $icode is$$. + +$head is$$ +The operand $icode is$$ has prototype +$codei% + std::istream& %is% +%$$ + +$head x$$ +The operand $icode x$$ has one of the following prototypes +$codei% + AD<%Base%>& %x% +%$$ + +$head Result$$ +The result of this operation can be used as a reference to $icode is$$. +For example, if the operand $icode y$$ has prototype +$codei% + AD<%Base%> %y% +%$$ +then the syntax +$codei% + %is% >> %x% >> %y% +%$$ +will first read the $icode Base$$ value of $icode x$$ from $icode is$$, +and then read the $icode Base$$ value to $icode y$$. + +$head Operation Sequence$$ +The result of this operation is not an +$cref/AD of Base/glossary/AD of Base/$$ object. +Thus it will not be recorded as part of an +AD of $icode Base$$ +$cref/operation sequence/glossary/Operation/Sequence/$$. + +$head Example$$ +$children% + example/general/ad_input.cpp +%$$ +The file +$cref ad_input.cpp$$ +contains an example and test of this operation. + +$end +------------------------------------------------------------------------------ +$begin ad_output$$ +$spell + VecAD + std + ostream + const +$$ + + +$section AD Output Stream Operator$$ + +$head Syntax$$ +$icode%os% << %x%$$ + +$head See Also$$ +$cref PrintFor$$ + +$head Purpose$$ +Writes the $icode Base$$ value, corresponding to $icode x$$, +to the output stream $icode os$$. + +$head Assumption$$ +If $icode b$$ is a $icode Base$$ object, +$codei% + %os% << %b% +%$$ +returns a reference to $icode os$$. + +$head os$$ +The operand $icode os$$ has prototype +$codei% + std::ostream& %os% +%$$ + +$head x$$ +The operand $icode x$$ has one of the following prototypes +$codei% + const AD<%Base%>& %x% + const VecAD<%Base%>::reference& %x% +%$$ + +$head Result$$ +The result of this operation can be used as a reference to $icode os$$. +For example, if the operand $icode y$$ has prototype +$codei% + AD<%Base%> %y% +%$$ +then the syntax +$codei% + %os% << %x% << %y% +%$$ +will output the value corresponding to $icode x$$ +followed by the value corresponding to $icode y$$. + +$head Operation Sequence$$ +The result of this operation is not an +$cref/AD of Base/glossary/AD of Base/$$ object. +Thus it will not be recorded as part of an +AD of $icode Base$$ +$cref/operation sequence/glossary/Operation/Sequence/$$. + +$head Example$$ +$children% + example/general/ad_output.cpp +%$$ +The file +$cref ad_output.cpp$$ +contains an example and test of this operation. + +$end +------------------------------------------------------------------------------ +*/ +namespace CppAD { // BEGIN_CPPAD_NAMESPACE +/*! +\file ad_io.hpp +AD input and ouput stream operators. +*/ +// --------------------------------------------------------------------------- +/*! +Read an AD object from an input stream. + +\tparam Base +Base type for the AD object. + +\param is [in,out] +Is the input stream from which that value is read. + +\param x [out] +is the object that is being set to a value. +Upone return, x.value_ is read from the input stream +and x.tape_is_ is zero; i.e., x is a parameter. +*/ +template +CPPAD_INLINE_FRIEND_TEMPLATE_FUNCTION +std::istream& operator >> (std::istream& is, AD& x) +{ // like assignment to a base type value + x.tape_id_ = 0; + CPPAD_ASSERT_UNKNOWN( Parameter(x) ); + return (is >> x.value_); +} +// --------------------------------------------------------------------------- +/*! +Write an AD object to an output stream. + +\tparam Base +Base type for the AD object. + +\param os [in,out] +Is the output stream to which that value is written. + +\param x +is the object that is being written to the output stream. +This is equivalent to writing x.value_ to the output stream. +*/ +template +CPPAD_INLINE_FRIEND_TEMPLATE_FUNCTION +std::ostream& operator << (std::ostream &os, const AD &x) +{ return (os << x.value_); } +// --------------------------------------------------------------------------- +/*! +Write a VecAD_reference object to an output stream. + +\tparam Base +Base type for the VecAD_reference object. + +\param os [in,out] +Is the output stream to which that value is written. + +\param x +is the element of the VecAD object that is being written to the output stream. +This is equivalent to writing the corresponing Base value to the stream. +*/ +template +CPPAD_INLINE_FRIEND_TEMPLATE_FUNCTION +std::ostream& operator << (std::ostream &os, const VecAD_reference &x) +{ return (os << x.ADBase()); } + +} // END_CPPAD_NAMESPACE +# endif diff --git a/build-config/cppad/include/cppad/core/ad_to_string.hpp b/build-config/cppad/include/cppad/core/ad_to_string.hpp new file mode 100644 index 00000000..71c669f7 --- /dev/null +++ b/build-config/cppad/include/cppad/core/ad_to_string.hpp @@ -0,0 +1,70 @@ +# ifndef CPPAD_CORE_AD_TO_STRING_HPP +# define CPPAD_CORE_AD_TO_STRING_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-16 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +/* +$begin ad_to_string$$ +$spell + const + std +$$ + +$section Convert An AD or Base Type to String$$ + +$head Syntax$$ +$icode%s% = to_string(%value%)%$$. + +$head See Also$$ +$cref to_string$$, $cref base_to_string$$ + +$head value$$ +The argument $icode value$$ has prototype +$codei% + const AD<%Base%>& %value% + const %Base%& %value% +%$$ +where $icode Base$$ is a type that supports the +$cref base_to_string$$ type requirement. + +$head s$$ +The return value has prototype +$codei% + std::string %s% +%$$ +and contains a representation of the specified $icode value$$. +If $icode value$$ is an AD type, +the result has the same precision as for the $icode Base$$ type. + +$head Example$$ +The file $cref to_string.cpp$$ +includes an example and test of $code to_string$$ with AD types. + +$end +*/ +# include +# include + +namespace CppAD { + + // Template definition is in cppad/utility/to_string.hpp. + // Partial specialzation for AD types + template + struct to_string_struct< CppAD::AD > + { std::string operator()(const CppAD::AD& value) + { to_string_struct ts; + return ts( Value( Var2Par( value ) ) ); } + }; + +} + +# endif diff --git a/build-config/cppad/include/cppad/core/ad_type.hpp b/build-config/cppad/include/cppad/core/ad_type.hpp new file mode 100644 index 00000000..4b1194c4 --- /dev/null +++ b/build-config/cppad/include/cppad/core/ad_type.hpp @@ -0,0 +1,59 @@ +# ifndef CPPAD_CORE_AD_TYPE_HPP +# define CPPAD_CORE_AD_TYPE_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +# include + +namespace CppAD { // BEGIN_CPPAD_NAMESPACE +/* +$begin ad_type_enum$$ +$spell + enum + typedef + CppAD + namespace +$$ + +$section Type of AD an Object$$ + +$head User API$$ +The values $code constant_enum$$, $code dynamic_enum$$ and +$code variable_enum$$ are in the user API; see +$cref/ad_type/atomic_three/ad_type/$$ for $code atomic_three$$ functions. + +$head typedef$$ +This typedef is in the $code CppAD$$ namespace: +$srccode%hpp% */ + typedef enum { + constant_enum, // constant parameter + dynamic_enum, // dynamic parameter + variable_enum, // variable + number_ad_type_enum // number of valid values for type_ad_enum + } ad_type_enum; +/* %$$ + +$head is_pod$$ +The following informs $cref is_pod$$ that this is plain old data. +$srccode%hpp% */ + namespace local { + template <> inline bool + is_pod(void) { return true; } + } +/* %$$ +$end +*/ + +} // END_CPPAD_NAMESPACE + + +# endif diff --git a/build-config/cppad/include/cppad/core/ad_valued.hpp b/build-config/cppad/include/cppad/core/ad_valued.hpp new file mode 100644 index 00000000..5db4344a --- /dev/null +++ b/build-config/cppad/include/cppad/core/ad_valued.hpp @@ -0,0 +1,50 @@ +# ifndef CPPAD_CORE_AD_VALUED_HPP +# define CPPAD_CORE_AD_VALUED_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +/* +$begin ADValued$$ +$spell +$$ + + +$section AD Valued Operations and Functions$$ + +$comment atomic.omh includes atomic_two.hpp$$ +$childtable% + include/cppad/core/arithmetic.hpp% + include/cppad/core/standard_math.hpp% + include/cppad/core/cond_exp.hpp% + include/cppad/core/discrete/user.omh% + include/cppad/core/numeric_limits.hpp% + include/cppad/core/atomic/atomic.omh +%$$ + +$end +*/ + +// include MathOther.h after CondExp.h because some MathOther.h routines use +// CondExp.h and CondExp.h is not sufficently declared in Declare.h + +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include + +# endif diff --git a/build-config/cppad/include/cppad/core/add.hpp b/build-config/cppad/include/cppad/core/add.hpp new file mode 100644 index 00000000..9b41670f --- /dev/null +++ b/build-config/cppad/include/cppad/core/add.hpp @@ -0,0 +1,131 @@ +# ifndef CPPAD_CORE_ADD_HPP +# define CPPAD_CORE_ADD_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +// BEGIN CppAD namespace +namespace CppAD { + +template +AD operator + (const AD &left , const AD &right) +{ + // compute the Base part of this AD object + AD result; + result.value_ = left.value_ + right.value_; + CPPAD_ASSERT_UNKNOWN( Parameter(result) ); + + // check if there is a recording in progress + local::ADTape* tape = AD::tape_ptr(); + if( tape == nullptr ) + return result; + tape_id_t tape_id = tape->id_; + // tape_id cannot match the default value for tape_id_; i.e., 0 + CPPAD_ASSERT_UNKNOWN( tape_id > 0 ); + + // check if left and right tapes match + bool match_left = left.tape_id_ == tape_id; + bool match_right = right.tape_id_ == tape_id; + + // check if left and right are dynamic parameters + bool dyn_left = match_left & (left.ad_type_ == dynamic_enum); + bool dyn_right = match_right & (right.ad_type_ == dynamic_enum); + + // check if left and right are variables + bool var_left = match_left & (left.ad_type_ != dynamic_enum); + bool var_right = match_right & (right.ad_type_ != dynamic_enum); + + CPPAD_ASSERT_KNOWN( + left.tape_id_ == right.tape_id_ || ! match_left || ! match_right , + "Add: AD variables or dynamic parameters on different threads." + ); + if( var_left ) + { if( var_right ) + { // result = variable + variable + CPPAD_ASSERT_UNKNOWN( local::NumRes(local::AddvvOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( local::NumArg(local::AddvvOp) == 2 ); + + // put operand addresses in tape + tape->Rec_.PutArg(left.taddr_, right.taddr_); + // put operator in the tape + result.taddr_ = tape->Rec_.PutOp(local::AddvvOp); + // make result a variable + result.tape_id_ = tape_id; + result.ad_type_ = variable_enum; + } + else if( (! dyn_right) & IdenticalZero(right.value_) ) + { // result = variable + 0 + result.make_variable(left.tape_id_, left.taddr_); + } + else + { // result = variable + parameter + // = parameter + variable + CPPAD_ASSERT_UNKNOWN( local::NumRes(local::AddpvOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( local::NumArg(local::AddpvOp) == 2 ); + + // put operand addresses in tape + addr_t p = right.taddr_; + if( ! dyn_right ) + p = tape->Rec_.put_con_par(right.value_); + tape->Rec_.PutArg(p, left.taddr_); + // put operator in the tape + result.taddr_ = tape->Rec_.PutOp(local::AddpvOp); + // make result a variable + result.tape_id_ = tape_id; + result.ad_type_ = variable_enum; + } + } + else if( var_right ) + { if( (! dyn_left) & IdenticalZero(left.value_) ) + { // result = 0 + variable + result.make_variable(right.tape_id_, right.taddr_); + } + else + { // result = parameter + variable + CPPAD_ASSERT_UNKNOWN( local::NumRes(local::AddpvOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( local::NumArg(local::AddpvOp) == 2 ); + + // put operand addresses in tape + addr_t p = left.taddr_; + if( ! dyn_left ) + p = tape->Rec_.put_con_par(left.value_); + tape->Rec_.PutArg(p, right.taddr_); + // put operator in the tape + result.taddr_ = tape->Rec_.PutOp(local::AddpvOp); + // make result a variable + result.tape_id_ = tape_id; + result.ad_type_ = variable_enum; + } + } + else if( dyn_left | dyn_right ) + { addr_t arg0 = left.taddr_; + addr_t arg1 = right.taddr_; + if( ! dyn_left ) + arg0 = tape->Rec_.put_con_par(left.value_); + if( ! dyn_right ) + arg1 = tape->Rec_.put_con_par(right.value_); + // + // parameters with a dynamic parameter result + result.taddr_ = tape->Rec_.put_dyn_par( + result.value_, local::add_dyn, arg0, arg1 + ); + result.tape_id_ = tape_id; + result.ad_type_ = dynamic_enum; + } + return result; +} + +// convert other cases into the case above +CPPAD_FOLD_AD_VALUED_BINARY_OPERATOR(+) + +} // END CppAD namespace + +# endif diff --git a/build-config/cppad/include/cppad/core/add_eq.hpp b/build-config/cppad/include/cppad/core/add_eq.hpp new file mode 100644 index 00000000..eb96b0b4 --- /dev/null +++ b/build-config/cppad/include/cppad/core/add_eq.hpp @@ -0,0 +1,128 @@ +# ifndef CPPAD_CORE_ADD_EQ_HPP +# define CPPAD_CORE_ADD_EQ_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +// BEGIN CppAD namespace +namespace CppAD { + +template +AD& AD::operator += (const AD &right) +{ + // compute the Base part + Base left; + left = value_; + value_ += right.value_; + + // check if there is a recording in progress + local::ADTape* tape = AD::tape_ptr(); + if( tape == nullptr ) + return *this; + tape_id_t tape_id = tape->id_; + // tape_id cannot match the default value for tape_id_; i.e., 0 + CPPAD_ASSERT_UNKNOWN( tape_id > 0 ); + + // check if left and right tapes match + bool match_left = tape_id_ == tape_id; + bool match_right = right.tape_id_ == tape_id; + + // check if left and right are dynamic parameters + bool dyn_left = match_left & (ad_type_ == dynamic_enum); + bool dyn_right = match_right & (right.ad_type_ == dynamic_enum); + + // check if left and right are variables + bool var_left = match_left & (ad_type_ != dynamic_enum); + bool var_right = match_right & (right.ad_type_ != dynamic_enum); + + CPPAD_ASSERT_KNOWN( + tape_id_ == right.tape_id_ || ! match_left || ! match_right , + "+= : AD variables or dynamic parameters on different threads." + ); + if( var_left ) + { if( var_right ) + { // this = variable + variable + CPPAD_ASSERT_UNKNOWN( local::NumRes(local::AddvvOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( local::NumArg(local::AddvvOp) == 2 ); + + // put operand addresses in tape + tape->Rec_.PutArg(taddr_, right.taddr_); + // put operator in the tape + taddr_ = tape->Rec_.PutOp(local::AddvvOp); + // check that this is a variable + CPPAD_ASSERT_UNKNOWN( tape_id_ == tape_id ); + CPPAD_ASSERT_UNKNOWN( ad_type_ == variable_enum); + } + else if( dyn_right | (! IdenticalZero(right.value_) ) ) + { // this = variable + parameter + // = parameter + variable + CPPAD_ASSERT_UNKNOWN( local::NumRes(local::AddpvOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( local::NumArg(local::AddpvOp) == 2 ); + + // put operand addresses in tape + addr_t p = right.taddr_; + if( ! dyn_right ) + p = tape->Rec_.put_con_par(right.value_); + tape->Rec_.PutArg(p, taddr_); + // put operator in the tape + taddr_ = tape->Rec_.PutOp(local::AddpvOp); + // check that this is a variable + CPPAD_ASSERT_UNKNOWN( tape_id_ == tape_id ); + CPPAD_ASSERT_UNKNOWN( ad_type_ == variable_enum); + } + } + else if( var_right ) + { if( (! dyn_left) & IdenticalZero(left) ) + { // this = 0 + right + make_variable(right.tape_id_, right.taddr_); + } + else + { // this = parameter + variable + CPPAD_ASSERT_UNKNOWN( local::NumRes(local::AddpvOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( local::NumArg(local::AddpvOp) == 2 ); + + // put operand addresses in tape + addr_t p = taddr_; + if( ! dyn_left ) + p = tape->Rec_.put_con_par(left); + tape->Rec_.PutArg(p, right.taddr_); + + // put operator in the tape + taddr_ = tape->Rec_.PutOp(local::AddpvOp); + + // make this a variable + tape_id_ = tape_id; + ad_type_ = variable_enum; + } + } + else if( dyn_left | dyn_right ) + { addr_t arg0 = taddr_; + addr_t arg1 = right.taddr_; + if( ! dyn_left ) + arg0 = tape->Rec_.put_con_par(left); + if( ! dyn_right ) + arg1 = tape->Rec_.put_con_par(right.value_); + // + // parameters with a dynamic parameter results + taddr_ = tape->Rec_.put_dyn_par( + value_, local::add_dyn, arg0, arg1 + ); + tape_id_ = tape_id; + ad_type_ = dynamic_enum; + } + return *this; +} + +CPPAD_FOLD_ASSIGNMENT_OPERATOR(+=) + +} // END CppAD namespace + +# endif diff --git a/build-config/cppad/include/cppad/core/arithmetic.hpp b/build-config/cppad/include/cppad/core/arithmetic.hpp new file mode 100644 index 00000000..40484071 --- /dev/null +++ b/build-config/cppad/include/cppad/core/arithmetic.hpp @@ -0,0 +1,42 @@ +# ifndef CPPAD_CORE_ARITHMETIC_HPP +# define CPPAD_CORE_ARITHMETIC_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-17 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +/* +------------------------------------------------------------------------------- +$begin Arithmetic$$ +$spell + Op + const +$$ + + + +$section AD Arithmetic Operators and Compound Assignments$$ + +$childtable% + include/cppad/core/unary_plus.hpp% + include/cppad/core/unary_minus.hpp% + include/cppad/core/ad_binary.hpp% + include/cppad/core/compound_assign.hpp +%$$ + +$end +------------------------------------------------------------------------------- +*/ +# include +# include +# include +# include + +# endif diff --git a/build-config/cppad/include/cppad/core/atan2.hpp b/build-config/cppad/include/cppad/core/atan2.hpp new file mode 100644 index 00000000..d975d7b6 --- /dev/null +++ b/build-config/cppad/include/cppad/core/atan2.hpp @@ -0,0 +1,152 @@ +# ifndef CPPAD_CORE_ATAN2_HPP +# define CPPAD_CORE_ATAN2_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-21 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +/* +------------------------------------------------------------------------------- +$begin atan2$$ +$spell + Vec + CppAD + namespace + std + atan + const +$$ + + +$section AD Two Argument Inverse Tangent Function$$ + +$head Syntax$$ +$icode%theta% = atan2(%y%, %x%)%$$ + + +$head Purpose$$ +Determines an angle $latex \theta \in [ - \pi , + \pi ]$$ +such that +$latex \[ +\begin{array}{rcl} + \sin ( \theta ) & = & y / \sqrt{ x^2 + y^2 } \\ + \cos ( \theta ) & = & x / \sqrt{ x^2 + y^2 } +\end{array} +\] $$ + +$head y$$ +The argument $icode y$$ has one of the following prototypes +$codei% + const AD<%Base%> &%y% + const VecAD<%Base%>::reference &%y% +%$$ + +$head x$$ +The argument $icode x$$ has one of the following prototypes +$codei% + const AD<%Base%> &%x% + const VecAD<%Base%>::reference &%x% +%$$ + +$head theta$$ +The result $icode theta$$ has prototype +$codei% + AD<%Base%> %theta% +%$$ + +$head Operation Sequence$$ +The AD of $icode Base$$ +operation sequence used to calculate $icode theta$$ is +$cref/independent/glossary/Operation/Independent/$$ +of $icode x$$ and $icode y$$. + +$head Example$$ +$children% + example/general/atan2.cpp +%$$ +The file +$cref atan2.cpp$$ +contains an example and test of this function. + +$end +------------------------------------------------------------------------------- +*/ + +namespace CppAD { // BEGIN CppAD namespace + +inline float atan2(float x, float y) +{ return std::atan2(x, y); } + +inline double atan2(double x, double y) +{ return std::atan2(x, y); } + +// The code below is used as an example by the CondExp documentation. +// BEGIN CondExp +template +AD atan2 (const AD &y, const AD &x) +{ // + // zero, pi2, pi + AD zero(0.); + AD pi2(2. * atan(1.)); + AD pi(2. * pi2); + // + // abs_x, abs_y + // Not using fabs because its derivative is zero at zero + AD abs_x = CondExpGe(x, zero, x, -x); + AD abs_y = CondExpGe(y, zero, y, -y); + // + // first + // This is the result for first quadrant: x >= 0 , y >= 0 + AD alpha = atan(abs_y / abs_x); + AD beta = pi2 - atan(abs_x / abs_y); + AD first = CondExpGt(abs_x, abs_y, alpha, beta); + // + // second + // This is the result for second quadrant: x <= 0 , y >= 0 + AD second = pi - first; + // + // third + // This is the result for third quadrant: x <= 0 , y <= 0 + AD third = - pi + first; + // + // fourth + // This is the result for fourth quadrant: x >= 0 , y <= 0 + AD fourth = - first; + // + // alpha + // This is the result for x >= 0 + alpha = CondExpGe(y, zero, first, fourth); + // + // beta + // This is the result for x <= 0 + beta = CondExpGe(y, zero, second, third); + // + // + AD result = CondExpGe(x, zero, alpha, beta); + return result; +} +// END CondExp + +template +AD atan2 (const VecAD_reference &y, const AD &x) +{ return atan2( y.ADBase() , x ); } + +template +AD atan2 (const AD &y, const VecAD_reference &x) +{ return atan2( y , x.ADBase() ); } + +template +AD atan2 +(const VecAD_reference &y, const VecAD_reference &x) +{ return atan2( y.ADBase() , x.ADBase() ); } + +} // END CppAD namespace + +# endif diff --git a/build-config/cppad/include/cppad/core/atomic/atomic.omh b/build-config/cppad/include/cppad/core/atomic/atomic.omh new file mode 100644 index 00000000..30dc4b19 --- /dev/null +++ b/build-config/cppad/include/cppad/core/atomic/atomic.omh @@ -0,0 +1,26 @@ +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-18 Bradley M. Bell + + CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + + This Source Code may also be made available under the following + Secondary License when the conditions for such availability set forth + in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +-------------------------------------------------------------------------- */ +$begin atomic$$ + +$section Atomic AD Functions$$ + +$childtable% + include/cppad/core/atomic/atomic_three.hpp% + include/cppad/core/chkpoint_two/chkpoint_two.hpp +%$$ + +$head Deprecated Atomic Function$$ +$cref atomic_one$$, +$cref atomic_two$$, +$cref chkpoint_one$$. + +$end diff --git a/build-config/cppad/include/cppad/core/atomic/atomic_one.hpp b/build-config/cppad/include/cppad/core/atomic/atomic_one.hpp new file mode 100644 index 00000000..9b0bd155 --- /dev/null +++ b/build-config/cppad/include/cppad/core/atomic/atomic_one.hpp @@ -0,0 +1,1058 @@ +# ifndef CPPAD_CORE_ATOMIC_ATOMIC_ONE_HPP +# define CPPAD_CORE_ATOMIC_ATOMIC_ONE_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-18 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ +/* +$begin atomic_one$$ +$spell + hes + std + Jacobian + jac + Tvector + afun + vx + vy + bool + namespace + CppAD + const + Taylor + tx + ty + px + py +$$ + +$section Defining Atomic Functions: First Generation$$ + +$head Deprecated 2013-05-27$$ +Using $code CPPAD_USER_ATOMIC$$ has been deprecated. +Use $cref atomic_three$$ instead. + +$head Syntax Function$$ +$codei%CPPAD_USER_ATOMIC(%afun%, %Tvector%, %Base%, + %forward%, %reverse%, %for_jac_sparse%, %rev_jac_sparse%, %rev_hes_sparse% +) +%$$ + +$subhead Use Function$$ +$icode%afun%(%id%, %ax%, %ay%) +%$$ + +$subhead Callback Routines$$ +$icode%ok% = %forward%(%id%, %k%, %n%, %m%, %vx%, %vy%, %tx%, %ty%) +%$$ +$icode%ok% = %reverse%(%id%, %k%, %n%, %m%, %tx%, %ty%, %px%, %py%) +%$$ +$icode%ok% = %for_jac_sparse%(%id%, %n%, %m%, %q%, %r%, %s%) +%$$ +$icode%ok% = %rev_jac_sparse%(%id%, %n%, %m%, %q%, %r%, %s%) +%$$ +$icode%ok% = %rev_hes_sparse%(%id%, %n%, %m%, %q%, %r%, %s%, %t%, %u%, %v%) +%$$ + +$subhead Free Static Memory$$ +$codei%user_atomic<%Base%>::clear()%$$ + +$head Purpose$$ +In some cases, the user knows how to compute the derivative +of a function +$latex \[ + y = f(x) \; {\rm where} \; f : \B{R}^n \rightarrow \B{R}^m +\] $$ +more efficiently than by coding it using $codei%AD<%Base%>%$$ +$cref/atomic_base/glossary/Operation/Atomic/$$ operations +and letting CppAD do the rest. +In this case, $code CPPAD_USER_ATOMIC$$ can be used +add the user code for $latex f(x)$$, and its derivatives, +to the set of $codei%AD<%Base%>%$$ atomic operations. +$pre + +$$ +Another possible purpose is to reduce the size of the tape. + +$head Partial Implementation$$ +The routines +$cref/forward/atomic_one/forward/$$, +$cref/reverse/atomic_one/reverse/$$, +$cref/for_jac_sparse/atomic_one/for_jac_sparse/$$, +$cref/rev_jac_sparse/atomic_one/rev_jac_sparse/$$, and +$cref/rev_hes_sparse/atomic_one/rev_hes_sparse/$$, +must be defined by the user. +The $icode forward$$ the routine, +for the case $icode%k% = 0%$$, must be implemented. +Functions with the correct prototype, +that just return $code false$$, +can be used for the other cases +(unless they are required by your calculations). +For example, you need not implement +$icode forward$$ for the case $icode%k% == 2%$$ until you require +forward mode calculation of second derivatives. + +$head CPPAD_USER_ATOMIC$$ +The macro +$codei% +CPPAD_USER_ATOMIC(%afun%, %Tvector%, %Base%, + %forward%, %reverse%, %for_jac_sparse%, %rev_jac_sparse%, %rev_hes_sparse% +) +%$$ +defines the $codei%AD<%Base%>%$$ routine $icode afun$$. +This macro can be placed within a namespace +(not the $code CppAD$$ namespace) +but must be outside of any routine. + +$subhead Tvector$$ +The macro argument $icode Tvector$$ must be a +$cref/simple vector template class/SimpleVector/$$. +It determines the type of vectors used as arguments to the routine +$icode afun$$. + +$subhead Base$$ +The macro argument $icode Base$$ specifies the +$cref/base type/base_require/$$ +corresponding to $codei%AD<%Base>%$$ operation sequences. +Calling the routine $icode afun$$ will add the operator defined +by this macro to an $codei%AD<%Base>%$$ operation sequence. + +$head ok$$ +For all routines documented below, +the return value $icode ok$$ has prototype +$codei% + bool %ok% +%$$ +If it is $code true$$, the corresponding evaluation succeeded, +otherwise it failed. + +$head id$$ +For all routines documented below, +the argument $icode id$$ has prototype +$codei% + size_t %id% +%$$ +Its value in all other calls is the same as in the corresponding +call to $icode afun$$. +It can be used to store and retrieve extra information about +a specific call to $icode afun$$. + +$head k$$ +For all routines documented below, the argument $icode k$$ has prototype +$codei% + size_t %k% +%$$ +The value $icode%k%$$ is the order of the Taylor coefficient that +we are evaluating ($cref/forward/atomic_one/forward/$$) +or taking the derivative of ($cref/reverse/atomic_one/reverse/$$). + +$head n$$ +For all routines documented below, +the argument $icode n$$ has prototype +$codei% + size_t %n% +%$$ +It is the size of the vector $icode ax$$ in the corresponding call to +$icode%afun%(%id%, %ax%, %ay%)%$$; i.e., +the dimension of the domain space for $latex y = f(x)$$. + +$head m$$ +For all routines documented below, the argument $icode m$$ has prototype +$codei% + size_t %m% +%$$ +It is the size of the vector $icode ay$$ in the corresponding call to +$icode%afun%(%id%, %ax%, %ay%)%$$; i.e., +the dimension of the range space for $latex y = f(x)$$. + +$head tx$$ +For all routines documented below, +the argument $icode tx$$ has prototype +$codei% + const CppAD::vector<%Base%>& %tx% +%$$ +and $icode%tx%.size() >= (%k% + 1) * %n%$$. +For $latex j = 0 , \ldots , n-1$$ and $latex \ell = 0 , \ldots , k$$, +we use the Taylor coefficient notation +$latex \[ +\begin{array}{rcl} + x_j^\ell & = & tx [ j * ( k + 1 ) + \ell ] + \\ + X_j (t) & = & x_j^0 + x_j^1 t^1 + \cdots + x_j^k t^k +\end{array} +\] $$ +If $icode%tx%.size() > (%k% + 1) * %n%$$, +the other components of $icode tx$$ are not specified and should not be used. +Note that superscripts represent an index for $latex x_j^\ell$$ +and an exponent for $latex t^\ell$$. +Also note that the Taylor coefficients for $latex X(t)$$ correspond +to the derivatives of $latex X(t)$$ at $latex t = 0$$ in the following way: +$latex \[ + x_j^\ell = \frac{1}{ \ell ! } X_j^{(\ell)} (0) +\] $$ + +$head ty$$ +In calls to $cref/forward/atomic_one/forward/$$, +the argument $icode ty$$ has prototype +$codei% + CppAD::vector<%Base%>& %ty% +%$$ +while in calls to $cref/reverse/atomic_one/reverse/$$ it has prototype +$codei% + const CppAD::vector<%Base%>& %ty% +%$$ +For all calls, $icode%tx%.size() >= (%k% + 1) * %m%$$. +For $latex i = 0 , \ldots , m-1$$ and $latex \ell = 0 , \ldots , k$$, +we use the Taylor coefficient notation +$latex \[ +\begin{array}{rcl} + y_i^\ell & = & ty [ i * ( k + 1 ) + \ell ] + \\ + Y_i (t) & = & y_i^0 + y_i^1 t^1 + \cdots + y_i^k t^k + o ( t^k ) +\end{array} +\] $$ +where $latex o( t^k ) / t^k \rightarrow 0$$ as $latex t \rightarrow 0$$. +If $icode%ty%.size() > (%k% + 1) * %m%$$, +the other components of $icode ty$$ are not specified and should not be used. +Note that superscripts represent an index for $latex y_j^\ell$$ +and an exponent for $latex t^\ell$$. +Also note that the Taylor coefficients for $latex Y(t)$$ correspond +to the derivatives of $latex Y(t)$$ at $latex t = 0$$ in the following way: +$latex \[ + y_j^\ell = \frac{1}{ \ell ! } Y_j^{(\ell)} (0) +\] $$ + +$subhead forward$$ +In the case of $icode forward$$, +for $latex i = 0 , \ldots , m-1$$, $latex ty[ i *( k + 1) + k ]$$ is an output +and all the other components of $icode ty$$ are inputs. + +$subhead reverse$$ +In the case of $icode reverse$$, +all the components of $icode ty$$ are inputs. + +$head afun$$ +The macro argument $icode afun$$, +is the name of the AD function corresponding to this atomic +operation (as it is used in the source code). +CppAD uses the other functions, +where the arguments are vectors with elements of type $icode Base$$, +to implement the function +$codei% + %afun%(%id%, %ax%, %ay%) +%$$ +where the argument are vectors with elements of type $codei%AD<%Base%>%$$. + +$subhead ax$$ +The $icode afun$$ argument $icode ax$$ has prototype +$codei% + const %Tvector%< AD<%Base%> >& %ax% +%$$ +It is the argument vector $latex x \in \B{R}^n$$ +at which the $codei%AD<%Base%>%$$ version of +$latex y = f(x)$$ is to be evaluated. +The dimension of the domain space for $latex y = f (x)$$ +is specified by $cref/n/atomic_one/n/$$ $codei%= %ax%.size()%$$, +which must be greater than zero. + +$subhead ay$$ +The $icode afun$$ result $icode ay$$ has prototype +$codei% + %Tvector%< AD<%Base%> >& %ay% +%$$ +The input values of its elements +are not specified (must not matter). +Upon return, it is the $codei%AD<%Base%>%$$ version of the +result vector $latex y = f(x)$$. +The dimension of the range space for $latex y = f (x)$$ +is specified by $cref/m/atomic_one/m/$$ $codei%= %ay%.size()%$$, +which must be greater than zero. + +$subhead Parallel Mode$$ +The first call to +$codei% + %afun%(%id%, %ax%, %ay%) +%$$ +must not be in $cref/parallel/ta_in_parallel/$$ mode. +In addition, the +$cref/atomic_one clear/atomic_one/clear/$$ +routine cannot be called while in parallel mode. + +$head forward$$ +The macro argument $icode forward$$ is a +user defined function +$codei% + %ok% = %forward%(%id%, %k%, %n%, %m%, %vx%, %vy%, %tx%, %ty%) +%$$ +that computes results during a $cref/forward/Forward/$$ mode sweep. +For this call, we are given the Taylor coefficients in $icode tx$$ +form order zero through $icode k$$, +and the Taylor coefficients in $icode ty$$ with order less than $icode k$$. +The $icode forward$$ routine computes the +$icode k$$ order Taylor coefficients for $latex y$$ using the definition +$latex Y(t) = f[ X(t) ]$$. +For example, for $latex i = 0 , \ldots , m-1$$, +$latex \[ +\begin{array}{rcl} +y_i^0 & = & Y(0) + = f_i ( x^0 ) +\\ +y_i^1 & = & Y^{(1)} ( 0 ) + = f_i^{(1)} ( x^0 ) X^{(1)} ( 0 ) + = f_i^{(1)} ( x^0 ) x^1 +\\ +y_i^2 +& = & \frac{1}{2 !} Y^{(2)} (0) +\\ +& = & \frac{1}{2} X^{(1)} (0)^\R{T} f_i^{(2)} ( x^0 ) X^{(1)} ( 0 ) + + \frac{1}{2} f_i^{(1)} ( x^0 ) X^{(2)} ( 0 ) +\\ +& = & \frac{1}{2} (x^1)^\R{T} f_i^{(2)} ( x^0 ) x^1 + + f_i^{(1)} ( x^0 ) x^2 +\end{array} +\] $$ +Then, for $latex i = 0 , \ldots , m-1$$, it sets +$latex \[ + ty [ i * (k + 1) + k ] = y_i^k +\] $$ +The other components of $icode ty$$ must be left unchanged. + +$subhead Usage$$ +This routine is used, +with $icode%vx%.size() > 0%$$ and $icode%k% == 0%$$, +by calls to $icode afun$$. +It is used, +with $icode%vx%.size() = 0%$$ and +$icode k$$ equal to the order of the derivative begin computed, +by calls to $cref/forward/forward_order/$$. + +$subhead vx$$ +The $icode forward$$ argument $icode vx$$ has prototype +$codei% + const CppAD::vector& %vx% +%$$ +The case $icode%vx%.size() > 0%$$ occurs +once for each call to $icode afun$$, +during the call, +and before any of the other callbacks corresponding to that call. +Hence such a call can be used to cache information attached to +the corresponding $icode id$$ +(such as the elements of $icode vx$$). +If $icode%vx%.size() > 0%$$ then +$icode%k% == 0%$$, +$icode%vx%.size() >= %n%$$, and +for $latex j = 0 , \ldots , n-1$$, +$icode%vx%[%j%]%$$ is true if and only if +$icode%ax%[%j%]%$$ is a $cref/variable/glossary/Variable/$$. +$pre + +$$ +If $icode%vx%.size() == 0%$$, +then $icode%vy%.size() == 0%$$ and neither of these vectors +should be used. + +$subhead vy$$ +The $icode forward$$ argument $icode vy$$ has prototype +$codei% + CppAD::vector& %vy% +%$$ +If $icode%vy%.size() == 0%$$, it should not be used. +Otherwise, +$icode%k% == 0%$$ and $icode%vy%.size() >= %m%$$. +The input values of the elements of $icode vy$$ +are not specified (must not matter). +Upon return, for $latex j = 0 , \ldots , m-1$$, +$icode%vy%[%i%]%$$ is true if and only if +$icode%ay%[%j%]%$$ is a variable. +(CppAD uses $icode vy$$ to reduce the necessary computations.) + +$head reverse$$ +The macro argument $icode reverse$$ +is a user defined function +$codei% + %ok% = %reverse%(%id%, %k%, %n%, %m%, %tx%, %ty%, %px%, %py%) +%$$ +that computes results during a $cref/reverse/Reverse/$$ mode sweep. +The input value of the vectors $icode tx$$ and $icode ty$$ +contain Taylor coefficient, up to order $icode k$$, +for $latex X(t)$$ and $latex Y(t)$$ respectively. +We use the $latex \{ x_j^\ell \}$$ and $latex \{ y_i^\ell \}$$ +to denote these Taylor coefficients where the implicit range indices are +$latex i = 0 , \ldots , m-1$$, +$latex j = 0 , \ldots , n-1$$, +$latex \ell = 0 , \ldots , k$$. +Using the calculations done by $cref/forward/atomic_one/forward/$$, +the Taylor coefficients $latex \{ y_i^\ell \}$$ are a function of the Taylor +coefficients for $latex \{ x_j^\ell \}$$; i.e., given $latex y = f(x)$$ +we define the function +$latex F : \B{R}^{n \times (k+1)} \rightarrow \B{R}^{m \times (k+1)}$$ by +$latex \[ +y_i^\ell = F_i^\ell ( \{ x_j^\ell \} ) +\] $$ +We use $latex G : \B{R}^{m \times (k+1)} \rightarrow \B{R}$$ +to denote an arbitrary scalar valued function of the Taylor coefficients for +$latex Y(t)$$ and write $latex z = G( \{ y_i^\ell \} )$$. +The $code reverse$$ routine +is given the derivative of $latex z$$ with respect to +$latex \{ y_i^\ell \}$$ and computes its derivative with respect +to $latex \{ x_j^\ell \}$$. + +$subhead Usage$$ +This routine is used, +with $icode%k% + 1%$$ equal to the order of the derivative being calculated, +by calls to $cref/reverse/reverse_any/$$. + +$subhead py$$ +The $icode reverse$$ argument $icode py$$ has prototype +$codei% + const CppAD::vector<%Base%>& %py% +%$$ +and $icode%py%.size() >= (%k% + 1) * %m%$$. +For $latex i = 0 , \ldots , m-1$$ and $latex \ell = 0 , \ldots , k$$, +$latex \[ + py[ i * (k + 1 ) + \ell ] = \partial G / \partial y_i^\ell +\] $$ +If $icode%py%.size() > (%k% + 1) * %m%$$, +the other components of $icode py$$ are not specified and should not be used. + +$subhead px$$ +We define the function +$latex \[ +H ( \{ x_j^\ell \} ) = G[ F( \{ x_j^\ell \} ) ] +\] $$ +The $icode reverse$$ argument $icode px$$ has prototype +$codei% + CppAD::vector<%Base%>& %px% +%$$ +and $icode%px%.size() >= (%k% + 1) * %n%$$. +The input values of the elements of $icode px$$ +are not specified (must not matter). +Upon return, +for $latex j = 0 , \ldots , n-1$$ and $latex p = 0 , \ldots , k$$, +$latex \[ +\begin{array}{rcl} +px [ j * (k + 1) + p ] & = & \partial H / \partial x_j^p +\\ +& = & +( \partial G / \partial \{ y_i^\ell \} ) + ( \partial \{ y_i^\ell \} / \partial x_j^p ) +\\ +& = & +\sum_{i=0}^{m-1} \sum_{\ell=0}^k +( \partial G / \partial y_i^\ell ) ( \partial y_i^\ell / \partial x_j^p ) +\\ +& = & +\sum_{i=0}^{m-1} \sum_{\ell=p}^k +py[ i * (k + 1 ) + \ell ] ( \partial F_i^\ell / \partial x_j^p ) +\end{array} +\] $$ +Note that we have used the fact that for $latex \ell < p$$, +$latex \partial F_i^\ell / \partial x_j^p = 0$$. +If $icode%px%.size() > (%k% + 1) * %n%$$, +the other components of $icode px$$ are not specified and should not be used. + +$head for_jac_sparse$$ +The macro argument $icode for_jac_sparse$$ +is a user defined function +$codei% + %ok% = %for_jac_sparse%(%id%, %n%, %m%, %q%, %r%, %s%) +%$$ +that is used to compute results during a forward Jacobian sparsity sweep. +For a fixed $latex n \times q$$ matrix $latex R$$, +the Jacobian of $latex f( x + R * u)$$ with respect to $latex u \in \B{R}^q$$ is +$latex \[ + S(x) = f^{(1)} (x) * R +\] $$ +Given a $cref/sparsity pattern/glossary/Sparsity Pattern/$$ for $latex R$$, +$icode for_jac_sparse$$ computes a sparsity pattern for $latex S(x)$$. + +$subhead Usage$$ +This routine is used by calls to $cref ForSparseJac$$. + +$subhead q$$ +The $icode for_jac_sparse$$ argument $icode q$$ has prototype +$codei% + size_t %q% +%$$ +It specifies the number of columns in +$latex R \in \B{R}^{n \times q}$$ and the Jacobian +$latex S(x) \in \B{R}^{m \times q}$$. + +$subhead r$$ +The $icode for_jac_sparse$$ argument $icode r$$ has prototype +$codei% + const CppAD::vector< std::set >& %r% +%$$ +and $icode%r%.size() >= %n%$$. +For $latex j = 0 , \ldots , n-1$$, +all the elements of $icode%r%[%j%]%$$ are between +zero and $icode%q%-1%$$ inclusive. +This specifies a sparsity pattern for the matrix $latex R$$. + +$subhead s$$ +The $icode for_jac_sparse$$ return value $icode s$$ has prototype +$codei% + CppAD::vector< std::set >& %s% +%$$ +and $icode%s%.size() >= %m%%$$. +The input values of its sets +are not specified (must not matter). Upon return +for $latex i = 0 , \ldots , m-1$$, +all the elements of $icode%s%[%i%]%$$ are between +zero and $icode%q%-1%$$ inclusive. +This represents a sparsity pattern for the matrix $latex S(x)$$. + +$head rev_jac_sparse$$ +The macro argument $icode rev_jac_sparse$$ +is a user defined function +$codei% + %ok% = %rev_jac_sparse%(%id%, %n%, %m%, %q%, %r%, %s%) +%$$ +that is used to compute results during a reverse Jacobian sparsity sweep. +For a fixed $latex q \times m$$ matrix $latex S$$, +the Jacobian of $latex S * f( x )$$ with respect to $latex x \in \B{R}^n$$ is +$latex \[ + R(x) = S * f^{(1)} (x) +\] $$ +Given a $cref/sparsity pattern/glossary/Sparsity Pattern/$$ for $latex S$$, +$icode rev_jac_sparse$$ computes a sparsity pattern for $latex R(x)$$. + +$subhead Usage$$ +This routine is used by calls to $cref RevSparseJac$$ +and to $cref optimize$$. + + +$subhead q$$ +The $icode rev_jac_sparse$$ argument $icode q$$ has prototype +$codei% + size_t %q% +%$$ +It specifies the number of rows in +$latex S \in \B{R}^{q \times m}$$ and the Jacobian +$latex R(x) \in \B{R}^{q \times n}$$. + +$subhead s$$ +The $icode rev_jac_sparse$$ argument $icode s$$ has prototype +$codei% + const CppAD::vector< std::set >& %s% +%$$ +and $icode%s%.size() >= %m%$$. +For $latex i = 0 , \ldots , m-1$$, +all the elements of $icode%s%[%i%]%$$ +are between zero and $icode%q%-1%$$ inclusive. +This specifies a sparsity pattern for the matrix $latex S^\R{T}$$. + +$subhead r$$ +The $icode rev_jac_sparse$$ return value $icode r$$ has prototype +$codei% + CppAD::vector< std::set >& %r% +%$$ +and $icode%r%.size() >= %n%$$. +The input values of its sets +are not specified (must not matter). +Upon return for $latex j = 0 , \ldots , n-1$$, +all the elements of $icode%r%[%j%]%$$ +are between zero and $icode%q%-1%$$ inclusive. +This represents a sparsity pattern for the matrix $latex R(x)^\R{T}$$. + +$head rev_hes_sparse$$ +The macro argument $icode rev_hes_sparse$$ +is a user defined function +$codei% + %ok% = %rev_hes_sparse%(%id%, %n%, %m%, %q%, %r%, %s%, %t%, %u%, %v%) +%$$ +There is an unspecified scalar valued function +$latex g : \B{R}^m \rightarrow \B{R}$$. +Given a sparsity pattern for $latex R$$ +and information about the function $latex z = g(y)$$, +this routine computes the sparsity pattern for +$latex \[ + V(x) = (g \circ f)^{(2)}( x ) R +\] $$ + +$subhead Usage$$ +This routine is used by calls to $cref RevSparseHes$$. + +$subhead q$$ +The $icode rev_hes_sparse$$ argument $icode q$$ has prototype +$codei% + size_t %q% +%$$ +It specifies the number of columns in the sparsity patterns. + +$subhead r$$ +The $icode rev_hes_sparse$$ argument $icode r$$ has prototype +$codei% + const CppAD::vector< std::set >& %r% +%$$ +and $icode%r%.size() >= %n%$$. +For $latex j = 0 , \ldots , n-1$$, +all the elements of $icode%r%[%j%]%$$ are between +zero and $icode%q%-1%$$ inclusive. +This specifies a sparsity pattern for the matrix $latex R \in \B{R}^{n \times q}$$. + +$subhead s$$ +The $icode rev_hes_sparse$$ argument $icode s$$ has prototype +$codei% + const CppAD::vector& %s% +%$$ +and $icode%s%.size() >= %m%$$. +This specifies a sparsity pattern for the matrix +$latex S(x) = g^{(1)} (y) \in \B{R}^{1 \times m}$$. + +$subhead t$$ +The $icode rev_hes_sparse$$ argument $icode t$$ has prototype +$codei% + CppAD::vector& %t% +%$$ +and $icode%t%.size() >= %n%$$. +The input values of its elements +are not specified (must not matter). +Upon return it represents a sparsity pattern for the matrix +$latex T(x) \in \B{R}^{1 \times n}$$ defined by +$latex \[ +T(x) = (g \circ f)^{(1)} (x) = S(x) * f^{(1)} (x) +\] $$ + +$subhead u$$ +The $icode rev_hes_sparse$$ argument $icode u$$ has prototype +$codei% + const CppAD::vector< std::set >& %u% +%$$ +and $icode%u%.size() >= %m%$$. +For $latex i = 0 , \ldots , m-1$$, +all the elements of $icode%u%[%i%]%$$ +are between zero and $icode%q%-1%$$ inclusive. +This specifies a sparsity pattern +for the matrix $latex U(x) \in \B{R}^{m \times q}$$ defined by +$latex \[ +\begin{array}{rcl} +U(x) +& = & +\partial_u \{ \partial_y g[ y + f^{(1)} (x) R u ] \}_{u=0} +\\ +& = & +\partial_u \{ g^{(1)} [ y + f^{(1)} (x) R u ] \}_{u=0} +\\ +& = & +g^{(2)} (y) f^{(1)} (x) R +\end{array} +\] $$ + +$subhead v$$ +The $icode rev_hes_sparse$$ argument $icode v$$ has prototype +$codei% + CppAD::vector< std::set >& %v% +%$$ +and $icode%v%.size() >= %n%$$. +The input values of its elements +are not specified (must not matter). +Upon return, for $latex j = 0, \ldots , n-1$$, +all the elements of $icode%v%[%j%]%$$ +are between zero and $icode%q%-1%$$ inclusive. +This represents a sparsity pattern for the matrix +$latex V(x) \in \B{R}^{n \times q}$$ defined by +$latex \[ +\begin{array}{rcl} +V(x) +& = & +\partial_u [ \partial_x (g \circ f) ( x + R u ) ]_{u=0} +\\ +& = & +\partial_u [ (g \circ f)^{(1)}( x + R u ) ]_{u=0} +\\ +& = & +(g \circ f)^{(2)}( x ) R +\\ +& = & +f^{(1)} (x)^\R{T} g^{(2)} ( y ) f^{(1)} (x) R ++ +\sum_{i=1}^m [ g^{(1)} (y) ]_i \; f_i^{(2)} (x) R +\\ +& = & +f^{(1)} (x)^\R{T} U(x) ++ +\sum_{i=1}^m S(x)_i \; f_i^{(2)} (x) R +\end{array} +\] $$ + +$head clear$$ +User atomic functions hold onto static work space in order to +increase speed by avoiding system memory allocation calls. +The function call $codei% + user_atomic<%Base%>::clear() +%$$ +makes to work space $cref/available/ta_available/$$ to +for other uses by the same thread. +This should be called when you are done using the +atomic functions for a specific value of $icode Base$$. + +$subhead Restriction$$ +The atomic function $code clear$$ routine cannot be called +while in $cref/parallel/ta_in_parallel/$$ execution mode. + +$end +------------------------------------------------------------------------------ +*/ +# include +# include + +// needed before one can use CPPAD_ASSERT_FIRST_CALL_NOT_PARALLEL +# include + +namespace CppAD { // BEGIN_CPPAD_NAMESPACE +/*! +\file atomic_one.hpp +user defined atomic operations. +*/ + +/*! +\def CPPAD_USER_ATOMIC(afun, Tvector, + forward, reverse, for_jac_sparse, rev_jac_sparse, rev_hes_sparse +) +Defines the function afun(id, ax, ay) +where id is ax and ay are vectors with AD elements. + +\par Tvector +the Simple Vector template class for this function. + +\par Base +the base type for the atomic operation. + +\par afun +name of the CppAD defined function that corresponding to this operation. +Note that afun, preceeded by a pound sign, +is a version of afun with quotes arround it. + +\par forward +name of the user defined function that computes corresponding +results during forward mode. + +\par reverse +name of the user defined function that computes corresponding +results during reverse mode. + +\par for_jac_sparse +name of the user defined routine that computes corresponding +results during forward mode jacobian sparsity sweeps. + +\par rev_jac_sparse +name of the user defined routine that computes corresponding +results during reverse mode jacobian sparsity sweeps. + +\par rev_hes_sparse +name of the user defined routine that computes corresponding +results during reverse mode Hessian sparsity sweeps. + +\par memory allocation +Note that atomic_one is used as a static object, so its objects +do note get deallocated until the program terminates. +*/ +# define CPPAD_USER_ATOMIC( \ + afun , \ + Tvector , \ + Base , \ + forward , \ + reverse , \ + for_jac_sparse , \ + rev_jac_sparse , \ + rev_hes_sparse \ +) \ +inline void afun ( \ + size_t id , \ + const Tvector< CppAD::AD >& ax , \ + Tvector< CppAD::AD >& ay \ +) \ +{ CPPAD_ASSERT_FIRST_CALL_NOT_PARALLEL; \ + static CppAD::atomic_one fun( \ + #afun , \ + forward , \ + reverse , \ + for_jac_sparse , \ + rev_jac_sparse , \ + rev_hes_sparse \ + ); \ + fun(id, ax, ay); \ +} + +/// link so that user_atomic::clear() still works +template class user_atomic : public atomic_base { +}; + +/*! +Class that actually implements the afun(id, ax, ay) calls. + +A new atomic_one object is generated each time the user invokes +the CPPAD_USER_ATOMIC macro; see static object in that macro. +*/ +template +class atomic_one : public atomic_base { +public: + /// disable atomic_one::clear(void) + static void clear(void) + { CPPAD_ASSERT_KNOWN( + false, + "Depreacted API uses user_atomic::clear()" + ); + } + /// type for user routine that computes forward mode results + typedef bool (*F) ( + size_t id , + size_t k , + size_t n , + size_t m , + const vector& vx , + vector& vy , + const vector& tx , + vector& ty + ); + /// type for user routine that computes reverse mode results + typedef bool (*R) ( + size_t id , + size_t k , + size_t n , + size_t m , + const vector& tx , + const vector& ty , + vector& px , + const vector& py + ); + /// type for user routine that computes forward mode Jacobian sparsity + typedef bool (*FJS) ( + size_t id , + size_t n , + size_t m , + size_t q , + const vector< std::set >& r , + vector< std::set >& s + ); + /// type for user routine that computes reverse mode Jacobian sparsity + typedef bool (*RJS) ( + size_t id , + size_t n , + size_t m , + size_t q , + vector< std::set >& r , + const vector< std::set >& s + ); + /// type for user routine that computes reverse mode Hessian sparsity + typedef bool (*RHS) ( + size_t id , + size_t n , + size_t m , + size_t q , + const vector< std::set >& r , + const vector& s , + vector& t , + const vector< std::set >& u , + vector< std::set >& v + ); +private: + /// id value corresponding to next virtual callback + size_t id_; + /// user's implementation of forward mode + const F f_; + /// user's implementation of reverse mode + const R r_; + /// user's implementation of forward jacobian sparsity calculations + const FJS fjs_; + /// user's implementation of reverse jacobian sparsity calculations + const RJS rjs_; + /// user's implementation of reverse Hessian sparsity calculations + const RHS rhs_; + +public: + /*! + Constructor called for each invocation of CPPAD_USER_ATOMIC. + + Put this object in the list of all objects for this class and set + the constant private data f_, r_, fjs_, rjs_, rhs_. + + \param afun + is the user's name for the AD version of this atomic operation. + + \param f + user routine that does forward mode calculations for this operation. + + \param r + user routine that does reverse mode calculations for this operation. + + \param fjs + user routine that does forward Jacobian sparsity calculations. + + \param rjs + user routine that does reverse Jacobian sparsity calculations. + + \param rhs + user routine that does reverse Hessian sparsity calculations. + + \par + This constructor can not be used in parallel mode because + atomic_base has this restriction. + */ + atomic_one(const char* afun, F f, R r, FJS fjs, RJS rjs, RHS rhs) : + atomic_base(afun) // name = afun + , f_(f) + , r_(r) + , fjs_(fjs) + , rjs_(rjs) + , rhs_(rhs) + { this->option( atomic_base::set_sparsity_enum ); + } + /*! + Implement the user call to afun(id, ax, ay). + + \tparam ADVector + A simple vector class with elements of type AD. + + \param id + extra information vector that is just passed through by CppAD, + and possibly used by user's routines. + + \param ax + is the argument vector for this call, + ax.size() determines the number of arguments. + + \param ay + is the result vector for this call, + ay.size() determines the number of results. + */ + template + void operator()(size_t id, const ADVector& ax, ADVector& ay) + { // call atomic_base function object + this->atomic_base::operator()(ax, ay, id); + return; + } + /*! + Store id for next virtual function callback + + \param id + id value corresponding to next virtual callback + */ + virtual void set_old(size_t id) + { id_ = id; } + /*! + Link from atomic_one to forward mode + + \copydetails atomic_base::forward + */ + virtual bool forward( + size_t p , + size_t q , + const vector& vx , + vector& vy , + const vector& tx , + vector& ty ) + { CPPAD_ASSERT_UNKNOWN( tx.size() % (q+1) == 0 ); + CPPAD_ASSERT_UNKNOWN( ty.size() % (q+1) == 0 ); + size_t n = tx.size() / (q+1); + size_t m = ty.size() / (q+1); + size_t i, j, k, ell; + + vector x(n * (q+1)); + vector y(m * (q+1)); + vector empty; + + // atomic_one interface can only handel one order at a time + // so must just throuh hoops to get multiple orders at one time. + bool ok = true; + for(k = p; k <= q; k++) + { for(j = 0; j < n; j++) + for(ell = 0; ell <= k; ell++) + x[ j * (k+1) + ell ] = tx[ j * (q+1) + ell ]; + for(i = 0; i < m; i++) + for(ell = 0; ell < k; ell++) + y[ i * (k+1) + ell ] = ty[ i * (q+1) + ell ]; + if( k == 0 ) + ok &= f_(id_, k, n, m, vx, vy, x, y); + else + ok &= f_(id_, k, n, m, empty, empty, x, y); + for(i = 0; i < m; i++) + ty[ i * (q+1) + k ] = y[ i * (k+1) + k]; + } + return ok; + } + /*! + Link from atomic_one to reverse mode + + \copydetails atomic_base::reverse + */ + virtual bool reverse( + size_t q , + const vector& tx , + const vector& ty , + vector& px , + const vector& py ) + { CPPAD_ASSERT_UNKNOWN( tx.size() % (q+1) == 0 ); + CPPAD_ASSERT_UNKNOWN( ty.size() % (q+1) == 0 ); + size_t n = tx.size() / (q+1); + size_t m = ty.size() / (q+1); + bool ok = r_(id_, q, n, m, tx, ty, px, py); + return ok; + } + /*! + Link from forward Jacobian sparsity sweep to atomic_one + + \copydetails atomic_base::for_sparse_jac + */ + virtual bool for_sparse_jac( + size_t q , + const vector< std::set >& r , + vector< std::set >& s , + const vector& x ) + { size_t n = r.size(); + size_t m = s.size(); + bool ok = fjs_(id_, n, m, q, r, s); + return ok; + } + + /*! + Link from reverse Jacobian sparsity sweep to atomic_one. + + \copydetails atomic_base::rev_sparse_jac + */ + virtual bool rev_sparse_jac( + size_t q , + const vector< std::set >& rt , + vector< std::set >& st , + const vector& x ) + { size_t n = st.size(); + size_t m = rt.size(); + bool ok = rjs_(id_, n, m, q, st, rt); + return ok; + } + /*! + Link from reverse Hessian sparsity sweep to atomic_one + + \copydetails atomic_base::rev_sparse_hes + */ + virtual bool rev_sparse_hes( + const vector& vx, + const vector& s , + vector& t , + size_t q , + const vector< std::set >& r , + const vector< std::set >& u , + vector< std::set >& v , + const vector& x ) + { size_t m = u.size(); + size_t n = v.size(); + CPPAD_ASSERT_UNKNOWN( r.size() == n ); + CPPAD_ASSERT_UNKNOWN( s.size() == m ); + CPPAD_ASSERT_UNKNOWN( t.size() == n ); + // + // old interface used id instead of vx + bool ok = rhs_(id_, n, m, q, r, s, t, u, v); + return ok; + } +}; + +} // END_CPPAD_NAMESPACE +# endif diff --git a/build-config/cppad/include/cppad/core/atomic/atomic_three.hpp b/build-config/cppad/include/cppad/core/atomic/atomic_three.hpp new file mode 100644 index 00000000..1afae080 --- /dev/null +++ b/build-config/cppad/include/cppad/core/atomic/atomic_three.hpp @@ -0,0 +1,486 @@ +# ifndef CPPAD_CORE_ATOMIC_ATOMIC_THREE_HPP +# define CPPAD_CORE_ATOMIC_ATOMIC_THREE_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ +/* +$begin atomic_three$$ +$spell + taylor + ctor + afun + arg + jac + hes + CppAD + enum + mul + hpp + const +$$ + +$section Defining Atomic Functions: Third Generation$$ + +$head Syntax$$ + +$subhead Define Class$$ +$codei%class %atomic_user% : public CppAD::atomic_three<%Base%> { + %...% +};%$$ + +$subhead Construct Atomic Function$$ +$icode%atomic_user% %afun%(%ctor_arg_list%)%$$ + +$subhead Use Atomic Function$$ +$icode%afun%(%ax%, %ay%)%$$ + +$subhead Class Member Callbacks$$ +$icode%ok% = %afun%.for_type( + %parameter_x%, %type_x%, %type_y% +) +%ok% = %afun%.forward( + %parameter_x%, %type_x%, + %need_y%, %order_low%, %order_up%, %taylor_x%, %taylor_y% +) +%ok% = %afun%.reverse( + %parameter_x%, %type_x%, + %order_up%, %taylor_x%, %taylor_y%, %partial_x%, %partial_y% +) +%ok% = %afun%.jac_sparsity( + %parameter_x%, %type_x%, %dependency%, %select_x% %select_y%, %pattern_out% +) +%ok% = %afun%.hes_sparsity( + %parameter_x%, %type_x%, %select_x% %select_y%, %pattern_out% +) +%ok% = %afun%.rev_depend( + %parameter_x%, %type_x%, %depend_x%, %depend_y% +)%$$ + +$head See Also$$ +$cref chkpoint_two$$, $cref atomic_two$$ + +$head Purpose$$ + +$subhead Speed$$ +In some cases, it is possible to compute derivatives of a function +$latex \[ + y = g(x) \; {\rm where} \; g : \B{R}^n \rightarrow \B{R}^m +\] $$ +more efficiently than by coding it using $codei%AD<%Base%>%$$ +$cref/atomic/glossary/Operation/Atomic/$$ operations +and letting CppAD do the rest. +The class $codei%atomic_three%<%Base%>%$$ is used to +create a new atomic operation corresponding to a function $latex g(x)$$ +where the user specifies how to compute the derivatives +and sparsity patterns for $latex g(x)$$. + +$subhead Reduce Memory$$ +If the function $latex g(x)$$ is many times during the recording +of an $cref ADFun$$ object, +using an atomic version of $latex g(x)$$ removed the need for repeated +copies of the corresponding $codei%AD<%Base%>%$$ operations and variables +in the recording. + +$head ad_type$$ +The type $code CppAD::ad_type_enum$$ +is used to specify if an AD object is a +$cref/constant parameter/glossary/Parameter/Constant/$$ +$cref/dynamic parameter/glossary/Parameter/Dynamic/$$ +or $cref/variable/glossary/Variable/$$. +It has the following possible values: +$center +$table +$icode ad_type_enum$$ $pre $$ $cnext Meaning $rnext +$code constant_enum$$ $pre $$ $cnext constant parameter $rnext +$code dynamic_enum$$ $pre $$ $cnext dynamic parameter $rnext +$code variable_enum$$ $pre $$ $cnext variable +$tend +$$ +In addition, +$code constant_enum < dynamic_enum < variable_enum$$. + +$head Virtual Functions$$ +The $cref/callback functions/atomic_three/Syntax/Class Member Callbacks/$$ +are implemented by defining the virtual functions in the +$icode atomic_user$$ class. +These functions compute derivatives, +sparsity patterns, and dependency relations. +Each virtual function has a default implementation +that returns $icode%ok% == false%$$. +The $cref/for_type/atomic_three_for_type/$$ +and $cref/forward/atomic_three_forward/$$ function +(for the case $icode%order_up% == 0%$$) must be implemented. +Otherwise, only those functions and orders +required by the your calculations need to be implemented. +For example, +$icode forward$$ for the case $icode%order_up% == 2%$$ can just return +$icode%ok% == false%$$ unless you require +forward mode calculation of second derivatives. + +$head Base$$ +This is the type of the elements of +$cref/ax/atomic_three_afun/ax/$$ and $cref/ay/atomic_three_afun/ay/$$ +in the corresponding $icode%afun%(%ax%, %ay%)%$$ call. + +$head parameter_x$$ +All the virtual functions include this argument which has prototype +$codei% + const CppAD::vector<%Base%> %parameter_x% +%$$ +Its size is equal to $icode%n% = %ax%.size()%$$ +in corresponding $icode%afun%(%ax%, %ay%)%$$ call. + +$subhead Constant$$ +For $icode%j% =0,%...%,%n%-1%$$, +if $icode%ax%[%j%]%$$ is a $cref/constant/con_dyn_var/Constant/$$ parameter, +$codei% + %parameter_x%[%j%] == %ax%[%j%] +%$$ + +$subhead Dynamic$$ +If $icode%ax%[%j%]%$$ is a $cref/dynamic/con_dyn_var/Dynamic/$$ parameter, +$icode%parameter_x%[%j%]%$$ value of $icode%ax%[%j%]%$$ corresponding to the +previous call to $cref new_dynamic$$ for the corresponding function object. + +$subhead Variable$$ +If $icode%ax%[%j%]%$$ is a variable, +the value of $icode%parameter_x%[%j%]%$$ is not specified. +See the +$cref/atomic_three_mat_mul.hpp/atomic_three_mat_mul.hpp/Purpose/parameter_x/$$ +for an example using $icode parameter_x$$. + +$head type_x$$ +All the virtual functions include this argument. +Its size is equal to $icode%n% = %ax%.size()%$$ +in corresponding $icode%afun%(%ax%, %ay%)%$$ call. +For $icode%j% =0,%...%,%n%-1%$$, +if $icode%ax%[%j%]%$$ is a constant parameter, +$codei% + %type_x%[%j%] == CppAD::constant_enum +%$$ +if $icode%ax%[%j%]%$$ is a dynamic parameter, +$codei% + %type_x%[%j%] == CppAD::dynamic_enum +%$$ +if $icode%ax%[%j%]%$$ is a variable, +$codei% + %type_x%[%j%] == CppAD::variable_enum +%$$ +See the +$cref/atomic_three_mat_mul.hpp/atomic_three_mat_mul.hpp/Purpose/type_x/$$ +for an example using $icode type_x$$. + + +$childtable%include/cppad/core/atomic/three_ctor.hpp + %include/cppad/core/atomic/three_afun.hpp + %include/cppad/core/atomic/three_for_type.hpp + %include/cppad/core/atomic/three_forward.hpp + %include/cppad/core/atomic/three_reverse.hpp + %include/cppad/core/atomic/three_jac_sparsity.hpp + %include/cppad/core/atomic/three_hes_sparsity.hpp + %include/cppad/core/atomic/three_rev_depend.hpp +%$$ + +$end +------------------------------------------------------------------------------- +$begin atomic_three_example$$ + +$section Example Defining Atomic Functions: Third Generation$$ + +$childtable%example/atomic_three/get_started.cpp + %example/atomic_three/norm_sq.cpp + %example/atomic_three/tangent.cpp + %example/atomic_three/base2ad.cpp + %example/atomic_three/reciprocal.cpp + %example/atomic_three/mat_mul.cpp +%$$ + +$end +------------------------------------------------------------------------------- +*/ + +# include +# include +# include + +// needed before one can use in_parallel +# include + +namespace CppAD { // BEGIN_CPPAD_NAMESPACE +/*! +\file atomic_three.hpp +Base class for atomic function operations. +*/ + +template +class atomic_three { +// =================================================================== +private: + // ------------------------------------------------------ + // constants + // + /// index of this object in lcal::atomic_index + /// (set by constructor and not changed; i.e., effectively const) + size_t index_; + // + // ----------------------------------------------------- + // + /// temporary work space used by member functions, declared here to avoid + // memory allocation/deallocation for each usage + struct work_struct { + vector type_x; + vector type_y; + // + vector taylor_x; + vector taylor_y; + // + vector< AD > ataylor_x; + vector< AD > ataylor_y; + // + sparse_rc< vector > pattern; + }; + // Use pointers, to avoid false sharing between threads. + // Not using: vector work_; + // so that deprecated atomic examples do not result in a memory leak. + work_struct* work_[CPPAD_MAX_NUM_THREADS]; + // ----------------------------------------------------- +public: + // ===================================================================== + // In User API + // ===================================================================== + // + // --------------------------------------------------------------------- + // ctor: doxygen in atomic/three_ctor.hpp + atomic_three(void); + atomic_three(const std::string& name); + + // ------------------------------------------------------------------------ + // operator(): see doxygen in atomic_three/afun.hpp + template + void operator()( + const ADVector& ax , + ADVector& ay + ); + // ------------------------------------------------------------------------ + // type: doxygen in atomic/three_for_type.hpp + virtual bool for_type( + const vector& parameter_x , + const vector& type_x , + vector& type_y + ); + // ------------------------------------------------------------------------ + // type: doxygen in atomic/three_rev_depend.hpp + virtual bool rev_depend( + const vector& parameter_x , + const vector& type_x , + vector& depend_x , + const vector& depend_y + ); + // ------------------------------------------------------------------------ + // forward: see docygen in atomic/three_forward.hpp + virtual bool forward( + const vector& parameter_x , + const vector& type_x , + size_t need_y , + size_t order_low , + size_t order_up , + const vector& taylor_x , + vector& taylor_y + ); + virtual bool forward( + const vector< AD >& aparameter_x , + const vector& type_x , + size_t need_y , + size_t order_low , + size_t order_up , + const vector< AD >& ataylor_x , + vector< AD >& ataylor_y + ); + // ------------------------------------------------------------------------ + // reverse: see docygen in atomic/three_reverse.hpp + virtual bool reverse( + const vector& parameter_x , + const vector& type_x , + size_t order_up , + const vector& taylor_x , + const vector& taylor_y , + vector& partial_x , + const vector& partial_y + ); + virtual bool reverse( + const vector< AD >& aparameter_x , + const vector& type_x , + size_t order_up , + const vector< AD >& ataylor_x , + const vector< AD >& ataylor_y , + vector< AD >& apartial_x , + const vector< AD >& apartial_y + ); + // ------------------------------------------------------------ + // jac_sparsity: see doxygen in atomic/three_jac_sparsity.hpp + virtual bool jac_sparsity( + const vector& parameter_x , + const vector& type_x , + bool dependency , + const vector& select_x , + const vector& select_y , + sparse_rc< vector >& pattern_out + ); + template + bool for_jac_sparsity( + bool dependency , + const vector& parameter_x , + const vector& type_x , + const local::pod_vector& x_index , + const local::pod_vector& y_index , + InternalSparsity& var_sparsity + ); + template + bool rev_jac_sparsity( + bool dependency , + const vector& parameter_x , + const vector& type_x , + const local::pod_vector& x_index , + const local::pod_vector& y_index , + InternalSparsity& var_sparsity + ); + // ------------------------------------------------------------ + // hes_sparsity: see doxygen in atomic/three_jac_sparsity.hpp + virtual bool hes_sparsity( + const vector& parameter_x , + const vector& type_x , + const vector& select_x , + const vector& select_y , + sparse_rc< vector >& pattern_out + ); + template + bool for_hes_sparsity( + const vector& parameter_x , + const vector& type_x , + const local::pod_vector& x_index , + const local::pod_vector& y_index , + size_t np1 , + size_t numvar , + const InternalSparsity& rev_jac_sparsity , + InternalSparsity& for_sparsity + ); + template + bool rev_hes_sparsity( + const vector& parameter_x , + const vector& type_x , + const local::pod_vector& x_index , + const local::pod_vector& y_index , + const InternalSparsity& for_jac_pattern , + bool* rev_jac_flag , + InternalSparsity& hes_sparsity + ); + + // ===================================================================== + // Not in User API + // ===================================================================== + + /// Name corresponding to a atomic_three object + const std::string atomic_name(void) const + { bool set_null = false; + size_t type = 0; // set to avoid warning + std::string name; + void* v_ptr = nullptr; // set to avoid warning + local::atomic_index(set_null, index_, type, &name, v_ptr); + CPPAD_ASSERT_UNKNOWN( type == 3 ); + return name; + } + /// destructor informs CppAD that this atomic function with this index + /// has dropped out of scope by setting its pointer to null + virtual ~atomic_three(void) + { // change object pointer to null, but leave name for error reporting + bool set_null = true; + size_t type = 0; // set to avoid warning + std::string* name = nullptr; + void* v_ptr = nullptr; // set to avoid warning + local::atomic_index(set_null, index_, type, name, v_ptr); + CPPAD_ASSERT_UNKNOWN( type == 3 ); + // + // free temporary work memory + for(size_t thread = 0; thread < CPPAD_MAX_NUM_THREADS; thread++) + free_work(thread); + } + /// allocates work_ for a specified thread + void allocate_work(size_t thread) + { if( work_[thread] == nullptr ) + { // allocate the raw memory + size_t min_bytes = sizeof(work_struct); + size_t num_bytes; + void* v_ptr = thread_alloc::get_memory(min_bytes, num_bytes); + // save in work_ + work_[thread] = reinterpret_cast( v_ptr ); + // call constructor + new( work_[thread] ) work_struct; + } + return; + } + /// frees work_ for a specified thread + void free_work(size_t thread) + { if( work_[thread] != nullptr ) + { // call destructor + work_[thread]->~work_struct(); + // return memory to avialable pool for this thread + thread_alloc::return_memory( + reinterpret_cast(work_[thread]) + ); + // mark this thread as not allocated + work_[thread] = nullptr; + } + return; + } + /// atomic_three function object corresponding to a certain index + static atomic_three* class_object(size_t index) + { bool set_null = false; + size_t type = 0; // set to avoid warning + std::string* name = nullptr; + void* v_ptr = nullptr; // set to avoid warning + local::atomic_index(set_null, index, type, name, v_ptr); + CPPAD_ASSERT_UNKNOWN( type == 3 ); + return reinterpret_cast( v_ptr ); + } + /// atomic_three function name corresponding to a certain index + static const std::string class_name(size_t index) + { bool set_null = false; + size_t type = 0; // set to avoid warning + std::string name; + void* v_ptr = nullptr; // set to avoid warning + local::atomic_index(set_null, index, type, &name, v_ptr); + CPPAD_ASSERT_UNKNOWN( type == 3 ); + return name; + } + + /*! + Set value of id (used by deprecated atomic_one class) + + This function is called just before calling any of the virtual function + and has the corresponding id of the corresponding virtual call. + */ + virtual void set_old(size_t id) + { } +// --------------------------------------------------------------------------- +}; +} // END_CPPAD_NAMESPACE + +// member functions +# include +# include +# include +# include +# include +# include +# include +# include + +# endif diff --git a/build-config/cppad/include/cppad/core/atomic/atomic_two.hpp b/build-config/cppad/include/cppad/core/atomic/atomic_two.hpp new file mode 100644 index 00000000..13418999 --- /dev/null +++ b/build-config/cppad/include/cppad/core/atomic/atomic_two.hpp @@ -0,0 +1,613 @@ +# ifndef CPPAD_CORE_ATOMIC_ATOMIC_TWO_HPP +# define CPPAD_CORE_ATOMIC_ATOMIC_TWO_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ +/* +$begin atomic_two$$ +$spell + ctor + afun + arg + vx + vy + tx + ty + px + py + jac + hes + CppAD + checkpointing +$$ + +$section Defining Atomic Functions: Second Generation$$ + +$head Deprecated 2019-01-01$$ +Using the $code atomic_base$$ class has been deprecated. +Use $cref atomic_three$$ instead. + + +$head Syntax$$ + +$codei% +%atomic_user% %afun%(%ctor_arg_list%) +%afun%(%ax%, %ay%) +%ok% = %afun%.forward(%p%, %q%, %vx%, %vy%, %tx%, %ty%) +%ok% = %afun%.reverse(%q%, %tx%, %ty%, %px%, %py%) +%ok% = %afun%.for_sparse_jac(%q%, %r%, %s%, %x%) +%ok% = %afun%.rev_sparse_jac(%q%, %r%, %s%, %x%) +%ok% = %afun%.for_sparse_hes(%vx%, %r%, %s%, %h%, %x%) +%ok% = %afun%.rev_sparse_hes(%vx%, %s%, %t%, %q%, %r%, %u%, %v%, %x%) +atomic_base<%Base%>::clear()%$$ + +$head See Also$$ +$cref/checkpoint/chkpoint_one/$$ + +$head Purpose$$ + +$subhead Speed$$ +In some cases, the user knows how to compute derivatives of a function +$latex \[ + y = f(x) \; {\rm where} \; f : \B{R}^n \rightarrow \B{R}^m +\] $$ +more efficiently than by coding it using $codei%AD<%Base%>%$$ +$cref/atomic_base/glossary/Operation/Atomic/$$ operations +and letting CppAD do the rest. +In this case $codei%atomic_base%<%Base%>%$$ can use +the user code for $latex f(x)$$, and its derivatives, +as $codei%AD<%Base%>%$$ atomic operations. + +$subhead Reduce Memory$$ +If the function $latex f(x)$$ is used often, +using an atomic version of $latex f(x)$$ remove the need for repeated +copies of the corresponding $codei%AD<%Base%>%$$ operations. + +$head Virtual Functions$$ +User defined derivatives are implemented by defining the +following virtual functions in the $icode atomic_base$$ class: +$cref/forward/atomic_two_forward/$$, +$cref/reverse/atomic_two_reverse/$$, +$cref/for_sparse_jac/atomic_two_for_sparse_jac/$$, +$cref/rev_sparse_jac/atomic_two_rev_sparse_jac/$$, and +$cref/rev_sparse_hes/atomic_two_rev_sparse_hes/$$. +These virtual functions have a default implementation +that returns $icode%ok% == false%$$. +The $code forward$$ function, +for the case $icode%q% == 0%$$, must be implemented. +Otherwise, only those functions +required by the your calculations need to be implemented. +For example, +$icode forward$$ for the case $icode%q% == 2%$$ can just return +$icode%ok% == false%$$ unless you require +forward mode calculation of second derivatives. + +$head Examples$$ +See $cref atomic_two_example$$. + +$childtable% + include/cppad/core/atomic/two_ctor.hpp% + include/cppad/core/atomic/two_option.hpp% + include/cppad/core/atomic/two_afun.hpp% + include/cppad/core/atomic/two_forward.hpp% + include/cppad/core/atomic/two_reverse.hpp% + include/cppad/core/atomic/two_for_sparse_jac.hpp% + include/cppad/core/atomic/two_rev_sparse_jac.hpp% + include/cppad/core/atomic/two_for_sparse_hes.hpp% + include/cppad/core/atomic/two_rev_sparse_hes.hpp% + include/cppad/core/atomic/two_clear.hpp +%$$ + +$end +------------------------------------------------------------------------------- +$begin atomic_two_example$$ + +$section Example Defining Atomic Functions: Second Generation$$ + +$head Getting Started$$ +that shows the minimal amount of information required to create +a user defined atomic operation. + +$head Scalar Function$$ +where the user provides the code for computing derivatives. +This example is simple because the domain and range are scalars. + +$head Vector Range$$ +where the user provides the code for computing derivatives. +This example is more complex because the range has two components. + +$head Hessian Sparsity Patterns$$ +where the user provides the code for computing Hessian sparsity patterns. + +$childtable% + example/atomic_two/eigen_mat_mul.cpp% + example/atomic_two/eigen_mat_inv.cpp% + example/atomic_two/eigen_cholesky.cpp +%$$ + +$end +------------------------------------------------------------------------------- +*/ + +# include +# include +# include +# include + +// needed before one can use in_parallel +# include + +namespace CppAD { // BEGIN_CPPAD_NAMESPACE +/*! +\file atomic_two.hpp +Base class for atomic function operations. +*/ + +template +class atomic_base { +// =================================================================== +public: + enum option_enum { + pack_sparsity_enum , + bool_sparsity_enum , + set_sparsity_enum + }; +private: + // ------------------------------------------------------ + // constants + // + /// index of this object in local::atomic_index + /// (set by constructor and not changed; i.e., effectively const) + size_t index_; + // + // ----------------------------------------------------- + // variables + // + /// sparsity pattern this object is currently using + /// (set by constructor and option member functions) + option_enum sparsity_; + // + /// temporary work space used by member functions, declared here to avoid + // memory allocation/deallocation for each usage + struct work_struct { + vector vx; + vector vy; + // + vector tx; + vector ty; + // + vector< AD > atx; + vector< AD > aty; + // + vector bool_t; + // + vectorBool pack_h; + vectorBool pack_r; + vectorBool pack_s; + vectorBool pack_u; + // + vector bool_h; + vector bool_r; + vector bool_s; + vector bool_u; + // + vector< std::set > set_h; + vector< std::set > set_r; + vector< std::set > set_s; + vector< std::set > set_u; + }; + // Use pointers, to avoid false sharing between threads. + // Not using: vector work_; + // so that deprecated atomic examples do not result in a memory leak. + work_struct* work_[CPPAD_MAX_NUM_THREADS]; +public: + // ===================================================================== + // In User API + // ===================================================================== + // + // --------------------------------------------------------------------- + // ctor: doxygen in atomic_base/ctor.hpp + atomic_base(void); + atomic_base( + const std::string& name, + option_enum sparsity = bool_sparsity_enum + ); + + // option: see doxygen in atomic_base/option.hpp + void option(enum option_enum option_value); + + // operator(): see doxygen in atomic_base/afun.hpp + template + void operator()( + const ADVector& ax , + ADVector& ay , + size_t id = 0 + ); + + // ------------------------------------------------------------------------ + // base_two version of forward + virtual bool forward( + size_t p , + size_t q , + const vector& vx , + vector& vy , + const vector& tx , + vector& ty + ); + virtual bool forward( + size_t p , + size_t q , + const vector& vx , + vector& vy , + const vector< AD >& atx , + vector< AD >& aty + ); + // base_three version of forward + bool forward( + size_t order_low , + size_t order_up , + const vector& type_x , + vector& type_y , + const vector& taylor_x , + vector& taylor_y + ); + bool forward( + size_t order_low , + size_t order_up , + const vector& type_x , + vector& type_y , + const vector< AD >& ataylor_x , + vector< AD >& ataylor_y + ); + // ------------------------------------------------------------------------ + // reverse: see doxygen in atomic_base/reverse.hpp + virtual bool reverse( + size_t q , + const vector& tx , + const vector& ty , + vector& px , + const vector& py + ); + virtual bool reverse( + size_t q , + const vector< AD >& atx , + const vector< AD >& aty , + vector< AD >& apx , + const vector< AD >& apy + ); + + // ------------------------------------------------------------ + // for_sparse_jac: see doxygen in atomic_base/for_sparse_jac.hpp + virtual bool for_sparse_jac( + size_t q , + const vector< std::set >& r , + vector< std::set >& s , + const vector& x + ); + virtual bool for_sparse_jac( + size_t q , + const vector& r , + vector& s , + const vector& x + ); + virtual bool for_sparse_jac( + size_t q , + const vectorBool& r , + vectorBool& s , + const vector& x + ); + template + bool for_sparse_jac( + const vector& x , + const local::pod_vector& x_index , + const local::pod_vector& y_index , + InternalSparsity& var_sparsity + ); + // deprecated versions + virtual bool for_sparse_jac( + size_t q , + const vector< std::set >& r , + vector< std::set >& s + ); + virtual bool for_sparse_jac( + size_t q , + const vector& r , + vector& s + ); + virtual bool for_sparse_jac( + size_t q , + const vectorBool& r , + vectorBool& s + ); + // ------------------------------------------------------------ + // rev_sparse_jac: see doxygen in atomic_base/rev_sparse_jac.hpp + virtual bool rev_sparse_jac( + size_t q , + const vector< std::set >& rt , + vector< std::set >& st , + const vector& x + ); + virtual bool rev_sparse_jac( + size_t q , + const vector& rt , + vector& st , + const vector& x + ); + virtual bool rev_sparse_jac( + size_t q , + const vectorBool& rt , + vectorBool& st , + const vector& x + ); + template + bool rev_sparse_jac( + const vector& x , + const local::pod_vector& x_index , + const local::pod_vector& y_index , + InternalSparsity& var_sparsity + ); + // deprecated versions + virtual bool rev_sparse_jac( + size_t q , + const vector< std::set >& rt , + vector< std::set >& st + ); + virtual bool rev_sparse_jac( + size_t q , + const vector& rt , + vector& st + ); + virtual bool rev_sparse_jac( + size_t q , + const vectorBool& rt , + vectorBool& st + ); + // ------------------------------------------------------------ + // for_sparse_hes: see doxygen in atomic_base/for_sparse_hes.hpp + virtual bool for_sparse_hes( + const vector& vx , + const vector& r , + const vector& s , + vector< std::set >& h , + const vector& x + ); + virtual bool for_sparse_hes( + const vector& vx , + const vector& r , + const vector& s , + vector& h , + const vector& x + ); + virtual bool for_sparse_hes( + const vector& vx , + const vector& r , + const vector& s , + vectorBool& h , + const vector& x + ); + template + bool for_sparse_hes( + const vector& x , + const local::pod_vector& x_index , + const local::pod_vector& y_index , + size_t np1 , + size_t numvar , + const InternalSparsity& rev_jac_sparsity , + InternalSparsity& for_sparsity + ); + // deprecated versions + virtual bool for_sparse_hes( + const vector& vx , + const vector& r , + const vector& s , + vector< std::set >& h + ); + virtual bool for_sparse_hes( + const vector& vx , + const vector& r , + const vector& s , + vector& h + ); + virtual bool for_sparse_hes( + const vector& vx , + const vector& r , + const vector& s , + vectorBool& h + ); + // ------------------------------------------------------------ + // rev_sparse_hes: see doxygen in atomic_base/rev_sparse_hes.hpp + virtual bool rev_sparse_hes( + const vector& vx , + const vector& s , + vector& t , + size_t q , + const vector< std::set >& r , + const vector< std::set >& u , + vector< std::set >& v , + const vector& x + ); + virtual bool rev_sparse_hes( + const vector& vx , + const vector& s , + vector& t , + size_t q , + const vector& r , + const vector& u , + vector& v , + const vector& x + ); + virtual bool rev_sparse_hes( + const vector& vx , + const vector& s , + vector& t , + size_t q , + const vectorBool& r , + const vectorBool& u , + vectorBool& v , + const vector& x + ); + template + bool rev_sparse_hes( + const vector& x , + const local::pod_vector& x_index , + const local::pod_vector& y_index , + const InternalSparsity& for_jac_sparsity , + bool* rev_jac_flag , + InternalSparsity& rev_hes_sparsity + ); + // deprecated + virtual bool rev_sparse_hes( + const vector& vx , + const vector& s , + vector& t , + size_t q , + const vector< std::set >& r , + const vector< std::set >& u , + vector< std::set >& v + ); + virtual bool rev_sparse_hes( + const vector& vx , + const vector& s , + vector& t , + size_t q , + const vector& r , + const vector& u , + vector& v + ); + virtual bool rev_sparse_hes( + const vector& vx , + const vector& s , + vector& t , + size_t q , + const vectorBool& r , + const vectorBool& u , + vectorBool& v + ); + // ------------------------------------------------------------ + // atomic_three like interface for reverse dependency analysis + bool rev_depend( + const vector& parameter_x , + const vector& type_x , + vector& depend_x , + const vector& depend_y + ); + // ------------------------------------------------------------ + // clear: see doxygen in atomic_base/clear.hpp + static void clear(void); + + // ===================================================================== + // Not in User API + // ===================================================================== + + /// current sparsity setting + option_enum sparsity(void) const + { return sparsity_; } + + /// Name corresponding to a atomic_base object + const std::string atomic_name(void) const + { bool set_null = false; + size_t type = 0; // set to avoid warning + std::string name; + void* v_ptr = nullptr; // set to avoid warning + local::atomic_index(set_null, index_, type, &name, v_ptr); + CPPAD_ASSERT_UNKNOWN( type == 2 ); + return name; + } + /// destructor informs CppAD that this atomic function with this index + /// has dropped out of scope by setting its pointer to null + virtual ~atomic_base(void) + { // change object pointer to null, but leave name for error reporting + bool set_null = true; + size_t type = 0; // set to avoid warning + std::string* name = nullptr; + void* v_ptr = nullptr; // set to avoid warning + local::atomic_index(set_null, index_, type, name, v_ptr); + CPPAD_ASSERT_UNKNOWN( type == 2 ); + // + // free temporary work memory + for(size_t thread = 0; thread < CPPAD_MAX_NUM_THREADS; thread++) + free_work(thread); + } + /// allocates work_ for a specified thread + void allocate_work(size_t thread) + { if( work_[thread] == nullptr ) + { // allocate the raw memory + size_t min_bytes = sizeof(work_struct); + size_t num_bytes; + void* v_ptr = thread_alloc::get_memory(min_bytes, num_bytes); + // save in work_ + work_[thread] = reinterpret_cast( v_ptr ); + // call constructor + new( work_[thread] ) work_struct; + } + return; + } + /// frees work_ for a specified thread + void free_work(size_t thread) + { if( work_[thread] != nullptr ) + { // call destructor + work_[thread]->~work_struct(); + // return memory to avialable pool for this thread + thread_alloc::return_memory( + reinterpret_cast(work_[thread]) + ); + // mark this thread as not allocated + work_[thread] = nullptr; + } + return; + } + /// atomic_base function object corresponding to a certain index + static atomic_base* class_object(size_t index) + { bool set_null = false; + size_t type = 0; // set to avoid warning + std::string* name = nullptr; + void* v_ptr = nullptr; // set to avoid warning + local::atomic_index(set_null, index, type, name, v_ptr); + CPPAD_ASSERT_UNKNOWN( type == 2 ); + return reinterpret_cast( v_ptr ); + } + /// atomic_base function name corresponding to a certain index + static const std::string class_name(size_t index) + { bool set_null = false; + size_t type = 0; // set to avoid warning + std::string name; + void* v_ptr = nullptr; // set to avoid warning + local::atomic_index(set_null, index, type, &name, v_ptr); + CPPAD_ASSERT_UNKNOWN( type == 2 ); + return name; + } + + /*! + Set value of id (used by deprecated atomic_one class) + + This function is called just before calling any of the virtual function + and has the corresponding id of the corresponding virtual call. + */ + virtual void set_old(size_t id) + { } +// --------------------------------------------------------------------------- +}; +} // END_CPPAD_NAMESPACE + +// functitons implemented in cppad/core/atomic_base files +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include + +# endif diff --git a/build-config/cppad/include/cppad/core/atomic/three_afun.hpp b/build-config/cppad/include/cppad/core/atomic/three_afun.hpp new file mode 100644 index 00000000..2e468105 --- /dev/null +++ b/build-config/cppad/include/cppad/core/atomic/three_afun.hpp @@ -0,0 +1,248 @@ +# ifndef CPPAD_CORE_ATOMIC_THREE_AFUN_HPP +# define CPPAD_CORE_ATOMIC_THREE_AFUN_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ +/* +$begin atomic_three_afun$$ + +$spell + sq + mul + afun + const + CppAD + mat_mul.cpp +$$ + +$section Using AD Version of an Atomic Function$$ + +$head Syntax$$ +$icode%afun%(%ax%, %ay%)%$$ + +$head Prototype$$ +$srcthisfile% + 0%// BEGIN_PROTOTYPE%// END_PROTOTYPE%1 +%$$ + +$head Purpose$$ +Given $icode ax$$, this call computes the corresponding value of $icode ay$$. +If $codei%AD<%Base%>%$$ operations are being recorded, +it enters the computation as an atomic operation in the recording; +see $cref/start recording/Independent/Start Recording/$$. + +$head Base$$ +This is the $icode Base$$ type of the elements of $icode ax$$ and $icode ay$$ +in the call to the $icode afun$$ atomic operation. +To be specific, the elements of $icode ax$$ and $icode ay$$ have type +$codei%AD%<%Base%>%$$. + +$head ADVector$$ +The type $icode ADVector$$ must be a +$cref/simple vector class/SimpleVector/$$ with elements of type +$codei%AD<%Base%>%$$. + +$head afun$$ +is a $cref/atomic_user/atomic_three_ctor/atomic_user/$$ object +and this $icode afun$$ function call is implemented by the +$cref/atomic_three/atomic_three_ctor/atomic_three/$$ class. + +$head ax$$ +This argument has prototype +$codei% + const %ADVector%& %ax% +%$$ +and size must be equal to $icode n$$. +It specifies vector $latex x \in \B{R}^n$$ +at which an $codei%AD<%Base%>%$$ version of +$latex y = g(x)$$ is to be evaluated; see +$cref/Base/atomic_three_ctor/atomic_three/Base/$$. + +$head ay$$ +This argument has prototype +$codei% + %ADVector%& %ay% +%$$ +and size must be equal to $icode m$$. +The input values of its elements +are not specified (must not matter). +Upon return, it is an $codei%AD<%Base%>%$$ version of +$latex y = g(x)$$. + +$end +----------------------------------------------------------------------------- +*/ + +namespace CppAD { // BEGIN_CPPAD_NAMESPACE +/*! +\file atomic/three_afun.hpp +Implement user call to an atomic_three function. +*/ + +/*! +Implement the user call to afun(ax, ay) + +\tparam ADVector +A simple vector class with elements of type AD. + +\param ax +is the argument vector for this call, +ax.size() determines the number of arguments. + +\param ay +is the result vector for this call, +ay.size() determines the number of results. +*/ +// BEGIN_PROTOTYPE +template +template +void atomic_three::operator()( + const ADVector& ax , + ADVector& ay ) +// END_PROTOTYPE +{ + + size_t n = ax.size(); + size_t m = ay.size(); +# ifndef NDEBUG + bool ok = true; + std::string msg = "atomic_three: " + atomic_name() + ".eval: "; + if( (n == 0) | (m == 0) ) + { msg += "ax.size() or ay.size() is zero"; + CPPAD_ASSERT_KNOWN(false, msg.c_str() ); + } +# endif + size_t thread = thread_alloc::thread_num(); + allocate_work(thread); + vector& taylor_x = work_[thread]->taylor_x; + vector& taylor_y = work_[thread]->taylor_y; + vector& type_x = work_[thread]->type_x; + vector& type_y = work_[thread]->type_y; + // + type_x.resize(n); + taylor_x.resize(n); + // + type_y.resize(m); + taylor_y.resize(m); + // + // Determine tape corresponding to variables in ax + tape_id_t tape_id = 0; + local::ADTape* tape = nullptr; + for(size_t j = 0; j < n; j++) + { taylor_x[j] = ax[j].value_; + if( Constant( ax[j] ) ) + type_x[j] = constant_enum; + else + { type_x[j] = ax[j].ad_type_; + if( tape_id == 0 ) + { tape = ax[j].tape_this(); + tape_id = ax[j].tape_id_; + CPPAD_ASSERT_UNKNOWN( tape != nullptr ); + } +# ifndef NDEBUG + if( Dynamic( ax[j] ) ) + { CPPAD_ASSERT_UNKNOWN( type_x[j] == dynamic_enum ); + } + else + { CPPAD_ASSERT_UNKNOWN( Variable( ax[j] ) ); + CPPAD_ASSERT_UNKNOWN( type_x[j] == variable_enum ); + } + if( tape_id != ax[j].tape_id_ ) + { msg += atomic_name() + + ": ax contains non-constant values from different threads."; + CPPAD_ASSERT_KNOWN(false, msg.c_str()); + } +# endif + } + } + // Use zero order forward mode to compute all the components of y + size_t need_y = size_t(variable_enum) + 1; + size_t order_low = 0; + size_t order_up = 0; + CPPAD_ASSERT_UNKNOWN( need_y > size_t(variable_enum) ); +# ifdef NDEBUG + forward(taylor_x, type_x, need_y, order_low, order_up, taylor_x, taylor_y); + for(size_t j = 0; j < n; ++j) + if( type_x[j] == variable_enum ) + taylor_x[j] = CppAD::numeric_limits::quiet_NaN(); + for_type(taylor_x, type_x, type_y); +# else + ok &= forward( + taylor_x, type_x, need_y, order_low, order_up, taylor_x, taylor_y + ); + for(size_t j = 0; j < n; ++j) + if( type_x[j] == variable_enum ) + taylor_x[j] = CppAD::numeric_limits::quiet_NaN(); + ok &= for_type(taylor_x, type_x, type_y); + if( ! ok ) + { msg += atomic_name() + ": ok is false for " + "type or zero order forward mode calculation."; + CPPAD_ASSERT_KNOWN(false, msg.c_str()); + } +# endif + bool record_dynamic = false; + bool record_variable = false; + // + // set ay to be vector of constant parameters with correct value + for(size_t i = 0; i < m; i++) + { // pass back values + ay[i].value_ = taylor_y[i]; + + // initialize entire vector as constants + ay[i].tape_id_ = 0; + ay[i].taddr_ = 0; + + // we need to record this operation if + // any of the elemnts of ay are dynamics or variables, + record_dynamic |= type_y[i] == dynamic_enum; + record_variable |= type_y[i] == variable_enum; + } +# ifndef NDEBUG + if( (record_dynamic || record_variable) && tape == nullptr ) + { msg += + "all elements of x are constants but y contains a non-constant"; + CPPAD_ASSERT_KNOWN(false, msg.c_str() ); + } +# endif + if( record_dynamic) + { tape->Rec_.put_dyn_atomic(tape_id, index_, type_x, type_y, ax, ay); + } + // case where result contains a variable + if( record_variable ) + { tape->Rec_.put_var_atomic(tape_id, index_, type_x, type_y, ax, ay); + } +# ifndef NDEBUG + for(size_t i = 0; i < m; ++i) switch( type_y[i] ) + { // + case constant_enum: + CPPAD_ASSERT_UNKNOWN( Constant( ay[i] ) ); + break; + // + case dynamic_enum: + CPPAD_ASSERT_UNKNOWN( Dynamic( ay[i] ) ); + break; + // + case variable_enum: + CPPAD_ASSERT_UNKNOWN( Variable( ay[i] ) ); + break; + // + default: + CPPAD_ASSERT_KNOWN( false, + "atomic_three: for_type: type_y[i]: is not a valid type" + ); + break; + } +# endif + return; +} + +} // END_CPPAD_NAMESPACE +# endif diff --git a/build-config/cppad/include/cppad/core/atomic/three_ctor.hpp b/build-config/cppad/include/cppad/core/atomic/three_ctor.hpp new file mode 100644 index 00000000..46672063 --- /dev/null +++ b/build-config/cppad/include/cppad/core/atomic/three_ctor.hpp @@ -0,0 +1,165 @@ +# ifndef CPPAD_CORE_ATOMIC_THREE_CTOR_HPP +# define CPPAD_CORE_ATOMIC_THREE_CTOR_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ +/* +$begin atomic_three_ctor$$ +$spell + enum + sq + std + afun + arg + CppAD + bool + ctor + const + mat_mul_xam.cpp + hpp +$$ + +$section Atomic Function Constructor$$ + +$head Syntax$$ +$codei%class %atomic_user% : public CppAD::atomic_three<%Base%> { +public: + %atomic_user%(%ctor_arg_list%) : CppAD::atomic_three<%Base%>(%name%) + %...% +}; +%$$ +$icode%atomic_user afun%(%ctor_arg_list%) +%$$ + +$head Prototype$$ +$srcthisfile% + 0%// BEGIN_PROTOTYPE%// END_PROTOTYPE%1 +%$$ + +$head atomic_user$$ + +$subhead ctor_arg_list$$ +Is a list of arguments for the $icode atomic_user$$ constructor. + +$subhead afun$$ +The object $icode afun$$ must stay in scope for as long +as the corresponding atomic function is used. +This includes use by any $cref/ADFun/ADFun/$$ that +has this $icode atomic_user$$ operation in its +$cref/operation sequence/glossary/Operation/Sequence/$$. + +$subhead Implementation$$ +The user defined $icode atomic_user$$ class is a publicly derived class of +$codei%atomic_three<%Base%>%$$. +It should be declared as follows: +$codei% + class %atomic_user% : public CppAD::atomic_three<%Base%> { + public: + %atomic_user%(%ctor_arg_list%) : atomic_three<%Base%>(%name%) + %...% + }; +%$$ +where $icode ...$$ +denotes the rest of the implementation of the derived class. +This includes completing the constructor and +all the virtual functions that have their +$code atomic_three$$ implementations replaced by +$icode atomic_user$$ implementations. + +$head atomic_three$$ + +$subhead Restrictions$$ +The $code atomic_three$$ constructor and destructor cannot be called in +$cref/parallel/ta_in_parallel/$$ mode. + +$subhead Base$$ +The template parameter determines the +$cref/Base/atomic_three_afun/Base/$$ +type for this $codei%AD<%Base%>%$$ atomic operation. + +$subhead name$$ +This $code atomic_three$$ constructor argument has the following prototype +$codei% + const std::string& %name% +%$$ +It is the name for this atomic function and is used for error reporting. +The suggested value for $icode name$$ is $icode afun$$ or $icode atomic_user$$, +i.e., the name of the corresponding atomic object or class. + +$head Example$$ + +$subhead Define Constructor$$ +The following is an example of a atomic function constructor definition: +$cref%get_started.cpp%atomic_three_get_started.cpp%Constructor%$$. + +$subhead Use Constructor$$ +The following is an example using a atomic function constructor: +$cref%get_started.cpp + %atomic_three_get_started.cpp + %Use Atomic Function%Constructor +%$$. + +$end +------------------------------------------------------------------------------- +*/ + +namespace CppAD { // BEGIN_CPPAD_NAMESPACE +/*! +\file atomic/three_ctor.hpp +Constructors for atomic_three class. +*/ + +/*! +Base class for atomic_atomic functions. + +\tparam Base +This class is used for defining an AD atomic operation y = g(x). + +\par +make sure user does not invoke the default constructor +*/ +template +atomic_three::atomic_three(void) +{ CPPAD_ASSERT_KNOWN(false, + "Attempt to use the atomic_three default constructor" + ); +} +/*! +Constructor + +\param name +name used for error reporting +*/ +// BEGIN_PROTOTYPE +template +atomic_three::atomic_three(const std::string& name ) +// END_PROTOTYPE +{ CPPAD_ASSERT_KNOWN( + ! thread_alloc::in_parallel() , + "atomic_three: constructor cannot be called in parallel mode." + ); + // + // atomic_index + bool set_null = false; + size_t index = 0; + size_t type = 3; + std::string copy_name = name; + void* copy_this = reinterpret_cast( this ); + index_ = local::atomic_index( + set_null, index, type, ©_name, copy_this + ); + // initialize work pointers as null; + for(size_t thread = 0; thread < CPPAD_MAX_NUM_THREADS; thread++) + work_[thread] = nullptr; +} + +} // END_CPPAD_NAMESPACE +# endif diff --git a/build-config/cppad/include/cppad/core/atomic/three_for_type.hpp b/build-config/cppad/include/cppad/core/atomic/three_for_type.hpp new file mode 100644 index 00000000..cb1cc31e --- /dev/null +++ b/build-config/cppad/include/cppad/core/atomic/three_for_type.hpp @@ -0,0 +1,117 @@ +# ifndef CPPAD_CORE_ATOMIC_THREE_FOR_TYPE_HPP +# define CPPAD_CORE_ATOMIC_THREE_FOR_TYPE_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ +/* +$begin atomic_three_for_type$$ +$spell + afun + enum + cpp +$$ + +$section Atomic Function Forward Type Calculation$$ + +$head Syntax$$ +$icode%ok% = %afun%.for_type(%parameter_x%, %type_x%, %type_y%)%$$ + +$subhead Prototype$$ +$srcthisfile%0%// BEGIN_PROTOTYPE%// END_PROTOTYPE%1 +%$$ + +$head Dependency Analysis$$ +This calculation is sometimes referred to as a forward dependency analysis. + +$head Usage$$ +This syntax and prototype are used by +$codei% + %afun%(%ax%, %ay%) +%$$ +where $cref/afun/atomic_three_ctor/atomic_user/afun/$$ +is a user defined atomic function. + +$head Implementation$$ +This virtual function must be defined by the +$cref/atomic_user/atomic_three_ctor/atomic_user/$$ class. + +$head Base$$ +See $cref/Base/atomic_three/Base/$$. + +$head parameter_x$$ +See $cref/parameter_x/atomic_three/parameter_x/$$. + +$head type_x$$ +See $cref/type_x/atomic_three/type_x/$$. + +$head type_y$$ +This vector has size equal to the number of results for this atomic function; +i.e. $icode%m%=%ay%.size()%$$. +The input values of the elements of $icode type_y$$ +are not specified (must not matter). +Upon return, for $latex i = 0 , \ldots , m-1$$, +$icode%type_y%[%i%]%$$ is set to one of the following values: +$list number$$ +It is $code constant_enum$$ if $icode%ay%[%i%]%$$ only depends on +the arguments that are constants. +$lnext +It is $code dynamic_enum$$ if $icode%ay%[%i%]%$$ depends on +a dynamic parameter and does not depend on any variables. +$lnext +It is $code variable_enum$$ if $icode%ay%[%i%]%$$ depends on +a variable. +$lend + +$head ok$$ +If this calculation succeeded, $icode ok$$ is true. +Otherwise, it is false. + +$head Example$$ +The following is an example of a atomic function $code for_type$$ definition: +$cref%get_started.cpp%atomic_three_get_started.cpp%for_type%$$. + + +$end +----------------------------------------------------------------------------- +*/ + +namespace CppAD { // BEGIN_CPPAD_NAMESPACE +/*! +\file atomic/three_for_type.hpp +Third generation atomic type computation. +*/ +/*! +Link from atomic_three to type calculation + +\param parameter_x [in] +is the value of the parameters in the corresponding function call +afun(ax, ay). + +\param type_x [in] +specifies which components of x are +constants, dynamics, and variables + +\param type_y [out] +specifies which components of y are +constants, dynamics, and variables +*/ +// BEGIN_PROTOTYPE +template +bool atomic_three::for_type( + const vector& parameter_x , + const vector& type_x , + vector& type_y ) +// END_PROTOTYPE +{ return false; } + +} // END_CPPAD_NAMESPACE + +# endif diff --git a/build-config/cppad/include/cppad/core/atomic/three_forward.hpp b/build-config/cppad/include/cppad/core/atomic/three_forward.hpp new file mode 100644 index 00000000..f35654bb --- /dev/null +++ b/build-config/cppad/include/cppad/core/atomic/three_forward.hpp @@ -0,0 +1,346 @@ +# ifndef CPPAD_CORE_ATOMIC_THREE_FORWARD_HPP +# define CPPAD_CORE_ATOMIC_THREE_FORWARD_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ +/* +$begin atomic_three_forward$$ +$spell + taylor + ataylor + af + afun + enum + CppAD + aparameter +$$ + +$section Atomic Function Forward Mode$$ + +$head Base$$ +This syntax and prototype are used by +$cref/afun(ax, ay)/atomic_three_afun/$$; see +$cref/Base/atomic_three_afun/Base/$$. +They are also used by +$icode%f%.Forward%$$ and $icode%f%.new_dynamic%$$ +where $icode f$$ has prototype +$codei% + ADFun<%Base%> %f% +%$$ +and $icode afun$$ is used during the recording of $icode f$$. + +$subhead Syntax$$ +$icode%ok% = %afun%.forward( + %parameter_x%, %type_x%, + %need_y%, %order_low%, %order_up%, %type_x%, %taylor_x%, %taylor_y% +)%$$ + +$subhead Prototype$$ +$srcthisfile%0%// BEGIN_PROTOTYPE_BASE%// END_PROTOTYPE_BASE%1 +%$$ + +$head AD$$ +This syntax and prototype are used by +$icode%af%.Forward%$$ and $icode%af%.new_dynamic%$$ +where $icode af$$ has prototype +$codei% + ADFun< AD<%Base%> , %Base% > %af% +%$$ +and $icode afun$$ is used in $icode af$$ (see $cref base2ad$$). + +$subhead Syntax$$ +$icode%ok% = %afun%.forward( + %parameter_x%, %type_x%, + %need_y%, %order_low%, %order_up%, %type_x%, %ataylor_x%, %ataylor_y% +)%$$ + +$subhead Prototype$$ +$srcthisfile%0%// BEGIN_PROTOTYPE_AD_BASE%// END_PROTOTYPE_AD_BASE%1 +%$$ + +$head Implementation$$ +The $icode taylor_x$$, $icode taylor_y$$ version of this function +must be defined by the +$cref/atomic_user/atomic_three_ctor/atomic_user/$$ class. +It can just return $icode%ok% == false%$$ +(and not compute anything) for values +of $icode%order_up%$$ that are greater than those used by your +$cref/forward/Forward/$$ mode calculations +(order zero must be implemented). + +$head parameter_x$$ +See $cref/parameter_x/atomic_three/parameter_x/$$. + +$head aparameter_x$$ +The specifications for $icode aparameter_x$$ +is the same as for $cref/parameter_x/atomic_three/parameter_x/$$ +(only the type of $icode ataylor_x$$ is different). + +$head type_x$$ +See $cref/type_x/atomic_three/type_x/$$. + +$head need_y$$ +One can ignore this argument and compute all the $icode taylor_y$$ +Taylor coefficient. +Often, this is not necessary and $icode need_y$$ is used to specify this. +The value $cref/type_y/atomic_three_for_type/type_y/$$ is used +to determine which coefficients are necessary as follows: + +$subhead Constant Parameters$$ +If $icode%need_y% == size_t(constant_enum)%$$, +then only the taylor coefficients +for $latex Y_i (t)$$ where $icode%type_y%[%i%] == constant_enum%$$ +are necessary. +This is the case during a $cref from_json$$ operation. + +$subhead Dynamic Parameters$$ +If $icode%need_y% == size_t(dynamic_enum)%$$, +then only the taylor coefficients +for $latex Y_i (t)$$ where $icode%type_y%[%i%] == dynamic_enum%$$ +are necessary. +This is the case during an $cref new_dynamic$$ operation. + +$subhead Variables$$ +If $icode%need_y% == size_t(variable_enum)%$$, +If $codei%ad_type_enum(%need_y%)% == variable_enum%$$, +then only the taylor coefficients +for $latex Y_i (t)$$ where $icode%type_y%[%i%] == variable_enum%$$ +are necessary. +This is the case during a $cref/f.Forward/Forward/$$ operation. +T + +$subhead All$$ +If $icode%need_y > size_t(variable_enum)%$$, +then the taylor coefficients for all $latex Y_i (t)$$ are necessary. +This is the case during an $icode%afun%(%ax%, %ay%)%$$ operation. + + +$head order_low$$ +This argument +specifies the lowest order Taylor coefficient that we are computing. + +$subhead p$$ +We sometimes use the notation $icode%p% = %order_low%$$ below. + +$head order_up$$ +This argument +specifies the highest order Taylor coefficient that we are computing +($icode%order_low% <= %order_up%$$). + +$subhead q$$ +We sometimes use the notation $icode%q% = %order_up%$$ below. + +$head taylor_x$$ +The size of $icode taylor_x$$ is $codei%(%q%+1)*%n%$$. +For $latex j = 0 , \ldots , n-1$$ and $latex k = 0 , \ldots , q$$, +we use the Taylor coefficient notation +$latex \[ +\begin{array}{rcl} + x_j^k & = & \R{taylor\_x} [ j * ( q + 1 ) + k ] + \\ + X_j (t) & = & x_j^0 + x_j^1 t^1 + \cdots + x_j^q t^q +\end{array} +\] $$ +Note that superscripts represent an index for $latex x_j^k$$ +and an exponent for $latex t^k$$. +Also note that the Taylor coefficients for $latex X(t)$$ correspond +to the derivatives of $latex X(t)$$ at $latex t = 0$$ in the following way: +$latex \[ + x_j^k = \frac{1}{ k ! } X_j^{(k)} (0) +\] $$ + +$subhead parameters$$ +If the $th j$$ component of $icode x$$ corresponds to a parameter, +$codei% + %type_x%[%j%] < CppAD::variable_enum +%$$ +In this case, +the $th j$$ component of $icode parameter_x$$ is equal to $latex x_j^0$$; +i.e., +$codei% + %parameter_x%[%j%] == %taylor_x%[ %j% * ( %q% + 1 ) + 0 ] +%$$ +Furthermore, for $icode%k% > 0%$$, +$codei% + %taylor_x%[ %j% * ( %q% + 1 ) + %k% ] == 0 +%$$ + +$head ataylor_x$$ +The specifications for $icode ataylor_x$$ is the same as for $icode taylor_x$$ +(only the type of $icode ataylor_x$$ is different). + +$head taylor_y$$ +The size of $icode taylor_y$$ is $codei%(%q%+1)*%m%$$. +Upon return, +For $latex i = 0 , \ldots , m-1$$ and $latex k = 0 , \ldots , q$$, +$latex \[ +\begin{array}{rcl} + Y_i (t) & = & g_i [ X(t) ] + \\ + Y_i (t) & = & y_i^0 + y_i^1 t^1 + \cdots + y_i^q t^q + o ( t^q ) + \\ + \R{taylor\_y} [ i * ( q + 1 ) + k ] & = & y_i^k +\end{array} +\] $$ +where $latex o( t^q ) / t^q \rightarrow 0$$ as $latex t \rightarrow 0$$. +Note that superscripts represent an index for $latex y_j^k$$ +and an exponent for $latex t^k$$. +Also note that the Taylor coefficients for $latex Y(t)$$ correspond +to the derivatives of $latex Y(t)$$ at $latex t = 0$$ in the following way: +$latex \[ + y_j^k = \frac{1}{ k ! } Y_j^{(k)} (0) +\] $$ +If $latex p > 0$$, +for $latex i = 0 , \ldots , m-1$$ and $latex k = 0 , \ldots , p-1$$, +the input of $icode taylor_y$$ satisfies +$latex \[ + \R{taylor\_y} [ i * ( q + 1 ) + k ] = y_i^k +\]$$ +These values do not need to be recalculated +and can be used during the computation of the higher order coefficients. + +$head ataylor_y$$ +The specifications for $icode ataylor_y$$ is the same as for $icode taylor_y$$ +(only the type of $icode ataylor_y$$ is different). + +$head ok$$ +If this calculation succeeded, $icode ok$$ is true. +Otherwise, it is false. + +$head Discussion$$ +For example, suppose that $icode%order_up% == 2%$$, +and you know how to compute the function $latex g(x)$$, +its first derivative $latex f^{(1)} (x)$$, +and it component wise Hessian $latex g_i^{(2)} (x)$$. +Then you can compute $icode taylor_x$$ using the following formulas: +$latex \[ +\begin{array}{rcl} +y_i^0 & = & Y(0) + = g_i ( x^0 ) +\\ +y_i^1 & = & Y^{(1)} ( 0 ) + = g_i^{(1)} ( x^0 ) X^{(1)} ( 0 ) + = g_i^{(1)} ( x^0 ) x^1 +\\ +y_i^2 +& = & \frac{1}{2 !} Y^{(2)} (0) +\\ +& = & \frac{1}{2} X^{(1)} (0)^\R{T} g_i^{(2)} ( x^0 ) X^{(1)} ( 0 ) + + \frac{1}{2} g_i^{(1)} ( x^0 ) X^{(2)} ( 0 ) +\\ +& = & \frac{1}{2} (x^1)^\R{T} g_i^{(2)} ( x^0 ) x^1 + + g_i^{(1)} ( x^0 ) x^2 +\end{array} +\] $$ +For $latex i = 0 , \ldots , m-1$$, and $latex k = 0 , 1 , 2$$, +$latex \[ + \R{taylor\_y} [ i * (q + 1) + k ] = y_i^k +\] $$ + +$children% + example/atomic_three/forward.cpp% + example/atomic_three/dynamic.cpp +%$$ +$head Examples$$ +The files +$cref atomic_three_forward.cpp$$ and $cref atomic_three_dynamic.cpp$$ +contain examples and tests that uses this routine. + +$end +----------------------------------------------------------------------------- +*/ + +namespace CppAD { // BEGIN_CPPAD_NAMESPACE +/*! +\file atomic/three_forward.hpp +Third generation atomic forward mode. +*/ +/*! +Link from atomic_three to forward mode + +\param parameter_x [in] +contains the values, in afun(ax, ay), for arguments that are parameters. + +\param type_x [in] +what is the type, in afun(ax, ay), for each component of x. + +\param need_y [in] +specifies which components of taylor_y are needed, + +\param order_low [in] +lowerest order for this forward mode calculation. + +\param order_up [in] +highest order for this forward mode calculation. + +\param taylor_x [in] +Taylor coefficients corresponding to x for this calculation. + +\param taylor_y [out] +Taylor coefficient corresponding to y for this calculation + +See the forward mode in user's documentation for atomic_three +*/ +// BEGIN_PROTOTYPE_BASE +template +bool atomic_three::forward( + const vector& parameter_x , + const vector& type_x , + size_t need_y , + size_t order_low , + size_t order_up , + const vector& taylor_x , + vector& taylor_y ) +// END_PROTOTYPE_BASE +{ return false; } + +/*! +Link from atomic_three to forward mode + +\param aparameter_x [in] +contains the values, in afun(ax, ay), for arguments that are parameters. + +\param type_x [in] +what is the type, in afun(ax, ay), for each component of x. + +\param need_y [in] +specifies which components of taylor_y are needed, + +\param order_low [in] +lowerest order for this forward mode calculation. + +\param order_up [in] +highest order for this forward mode calculation. + +\param ataylor_x [in] +Taylor coefficients corresponding to x for this calculation. + +\param ataylor_y [out] +Taylor coefficient corresponding to y for this calculation + +See the forward mode in user's documentation for base_three +*/ +// BEGIN_PROTOTYPE_AD_BASE +template +bool atomic_three::forward( + const vector< AD >& aparameter_x , + const vector& type_x , + size_t need_y , + size_t order_low , + size_t order_up , + const vector< AD >& ataylor_x , + vector< AD >& ataylor_y ) +// END_PROTOTYPE_AD_BASE +{ return false; } + + +} // END_CPPAD_NAMESPACE +# endif diff --git a/build-config/cppad/include/cppad/core/atomic/three_hes_sparsity.hpp b/build-config/cppad/include/cppad/core/atomic/three_hes_sparsity.hpp new file mode 100644 index 00000000..03445cbe --- /dev/null +++ b/build-config/cppad/include/cppad/core/atomic/three_hes_sparsity.hpp @@ -0,0 +1,412 @@ +# ifndef CPPAD_CORE_ATOMIC_THREE_HES_SPARSITY_HPP +# define CPPAD_CORE_ATOMIC_THREE_HES_SPARSITY_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ +/* +$begin atomic_three_hes_sparsity$$ +$spell + Hessian + afun + hes +$$ + +$section Atomic Function Hessian Sparsity Patterns$$ + +$head Syntax$$ +$icode%ok% = %afun%.hes_sparsity( + %parameter_x%, %type_x%, %select_x%, %select_y%, %pattern_out% +)%$$ + +$head Prototype$$ +$srcthisfile%0%// BEGIN_PROTOTYPE%// END_PROTOTYPE%1 +%$$ + +$head Implementation$$ +This function must be defined if +$cref/afun/atomic_three_ctor/atomic_user/afun/$$ is +used to define an $cref ADFun$$ object $icode f$$, +and Hessian sparsity patterns are computed for $icode f$$. + +$head Base$$ +See $cref/Base/atomic_three_afun/Base/$$. + +$head parameter_x$$ +See $cref/parameter_x/atomic_three/parameter_x/$$. + +$head type_x$$ +See $cref/type_x/atomic_three/type_x/$$. + +$head select_x$$ +This argument has size equal to the number of arguments to this +atomic function; i.e. the size of $icode ax$$. +It specifies which domain components are included in +the calculation of $icode pattern_out$$. +If $icode%select_x%[%j%]%$$ is false, then there will be no indices +$icode k$$ such that either of the following hold: +$codei% + %pattern_out%.row()[%k%] == %j% + %pattern_out%.col()[%k%] == %j% +%$$. + +$head select_y$$ +This argument has size equal to the number of results to this +atomic function; i.e. the size of $icode ay$$. +It specifies which range component functions $latex g_i (x)$$ are included in +of $icode pattern_out$$. + +$head pattern_out$$ +This input value of $icode pattern_out$$ does not matter. +Upon return it is the union, +with respect to $icode i$$ such that $icode%select_y%[%i%]%$$ is true, +of the sparsity pattern for Hessian of $latex g_i (x)$$. +To be specific, there are non-negative indices +$icode i$$, $icode r$$, $icode c$$, and $icode k$$ such that +$codei% + %pattern_out%.row()[%k%] == %r% + %pattern_out%.col()[%k%] == %c% +%$$ +if and only if +$icode%select_y%[%i%]%$$ is true, +$icode%select_x%[%r%]%$$ is true, +$icode%select_x%[%c%]%$$ is true, +and +$latex \[ + \partial_{x(r)} \partial_{x(c)} g_i(x) +\] $$ +is possibly non-zero. +Note that the sparsity pattern should be symmetric. + +$head ok$$ +If this calculation succeeded, $icode ok$$ is true. +Otherwise it is false. + +$children% + example/atomic_three/hes_sparsity.cpp +%$$ +$head Examples$$ +The file $cref atomic_three_hes_sparsity.cpp$$ contains an example and test +that uses this routine. +$end +----------------------------------------------------------------------------- +*/ +namespace CppAD { // BEGIN_CPPAD_NAMESPACE +/*! +\file atomic/three_hes_sparsity.hpp +Third generation atomic Hessian dependency and sparsity patterns. +*/ +/*! +atomic_three to Hessian dependency and sparsity calculations. + +\param parameter_x [in] +contains the values for arguments that are parameters. + +\param type_x [in] +what is the type, in afun(ax, ay), for each component of x. + +\param select_x [in] +which domain components to include in the dependency or sparsity pattern. + +\param select_y [in] +which range components to include in the dependency or sparsity pattern. + +\param pattern_out [out] +is the sparsity pattern for Hessian. +*/ +// BEGIN_PROTOTYPE +template +bool atomic_three::hes_sparsity( + const vector& parameter_x , + const vector& type_x , + const vector& select_x , + const vector& select_y , + sparse_rc< vector >& pattern_out ) +// END_PROTOTYPE +{ return false; } +/*! +Link from forward Hessian sweep to atomic_three. +2DO: move this functiton outside this file so can change +developer documentation to omhelp formating. + +\tparam InternalSparsity +Is the used internaly for sparsity calculations; i.e., +sparse_pack or sparse_list. + +\param parameter_x +is parameter arguments to the function, other components are nan. + +\param type_x [in] +what is the type, in afun(ax, ay), for each component of x. + +\param x_index +is the variable index, on the tape, for the arguments to this function. +This size of x_index is n, the number of arguments to this function. +The index zero is used for parameters. + +\param y_index +is the variable index, on the tape, for the results for this function. +This size of y_index is m, the number of results for this function. +The index zero is used for parameters. + +\param for_jac_sparsity +On input, for j = 0, ... , n-1, the sparsity pattern with index x_index[j], +is the forward Jacobian sparsity for the j-th argument to this atomic function. + +\param rev_jac_pattern +On input, for i = 0, ... , m-1, the sparsity pattern with index y_index[i], +is the reverse Jacobian sparsity for the i-th result to this atomic function. +This shows which components of the result affect the function we are +computing the Hessian of. + +\param hes_sparsity_for +This is the sparsity pattern for the Hessian. On input, the non-linear +terms in the atomic fuction have not been included. Upon return, they +have been included. +*/ +template +template +bool atomic_three::for_hes_sparsity( + const vector& parameter_x , + const vector& type_x , + const local::pod_vector& x_index , + const local::pod_vector& y_index , + size_t np1 , + size_t numvar , + const InternalSparsity& rev_jac_pattern , + InternalSparsity& for_sparsity ) +{ typedef typename InternalSparsity::const_iterator const_iterator; + // + CPPAD_ASSERT_UNKNOWN( rev_jac_pattern.end() == 1 ); + CPPAD_ASSERT_UNKNOWN( for_sparsity.end() == np1 ); + CPPAD_ASSERT_UNKNOWN( for_sparsity.n_set() == np1 + numvar ); + size_t n = x_index.size(); + size_t m = y_index.size(); + // + // select_x + vector select_x(n); + for(size_t j = 0; j < n; j++) + { // check if should compute pattern w.r.t x[j] + select_x[j] = for_sparsity.number_elements(np1 + x_index[j]) > 0; + } + // + // bool select_y + vector select_y(m); + for(size_t i = 0; i < m; i++) + { // check if we should include y[i] + select_y[i] = rev_jac_pattern.number_elements(y_index[i]) > 0; + } + // ------------------------------------------------------------------------ + // call user's version of atomic function for Jacobian + sparse_rc< vector > pattern_out; + bool dependency = false; + bool ok = jac_sparsity( + parameter_x, type_x, dependency, select_x, select_y, pattern_out + ); + if( ! ok ) + return false; + // + // transfer sparsity patterns from pattern_out to var_sparsity + size_t nnz = pattern_out.nnz(); + const vector& row( pattern_out.row() ); + const vector& col( pattern_out.col() ); + for(size_t k = 0; k < nnz; ++k) + { size_t i = row[k]; + size_t j = col[k]; + CPPAD_ASSERT_KNOWN( + select_y[i] & select_x[j], + "atomic: jac_sparsity: pattern_out not in " + "select_x or select_y range" + ); + const_iterator itr(for_sparsity, np1 + x_index[j]); + size_t ell = *itr; + while( ell < np1 ) + { for_sparsity.post_element(np1 + y_index[i], ell ); + ell = *(++itr); + } + } + for(size_t i = 0; i < m; ++i) + for_sparsity.process_post( np1 + y_index[i] ); + // ------------------------------------------------------------------------ + // call user's version of atomic function for Hessian + ok = hes_sparsity( + parameter_x, type_x, select_x, select_y, pattern_out + ); + if( ! ok ) + return ok; + // + // add new elements to Hessian sparisty in calling routine + nnz = pattern_out.nnz(); + for(size_t k = 0; k < nnz; ++k) + { size_t r = row[k]; + size_t c = col[k]; + CPPAD_ASSERT_KNOWN( + select_x[r] & select_x[c], + "atomic: hes_sparsity: pattern_out not in select_x range" + ); + const_iterator itr_1(for_sparsity, np1 + x_index[r]); + size_t v1 = *itr_1; + while( v1 < np1 ) + { for_sparsity.binary_union( + v1, v1, np1 + x_index[c], for_sparsity + ); + v1 = *(++itr_1); + } + // no need to add same elements twice + if( c != r ) + { const_iterator itr_2(for_sparsity, np1 + x_index[c]); + size_t v2 = *itr_2; + while( v2 < np1 ) + { for_sparsity.binary_union( + v2, v2, np1 + x_index[r], for_sparsity + ); + v2 = *(++itr_2); + } + } + } + return ok; +} +/*! +Link from for_reverse Hessian sweep to atomic_three. + +\tparam InternalSparsity +Is the used internaly for sparsity calculations; i.e., +sparse_pack or sparse_list. + +\param parameter_x +is parameter arguments to the function, other components are nan. + +\param type_x [in] +what is the type, in afun(ax, ay), for each component of x. + +\param x_index +is the variable index, on the tape, for the arguments to this function. +This size of x_index is n, the number of arguments to this function. +The index zero is used for parameters. + +\param y_index +is the variable index, on the tape, for the results for this function. +This size of y_index is m, the number of results for this function. +The index zero is used for parameters. + +\param for_jac_pattern +On input, for j = 0, ... , n-1, the sparsity pattern with index x_index[j], +is the forward Jacobian pattern for the j-th argument to this atomic function. + +\param rev_jac_flag +On input, for i = 0, ... , m-1, rev_jac_flag[ y_index[i] ] is true +if the function we are computing the Hessian of has possibly non-zero Jacobian +w.r.t varialbe y_index[i]. +On output, for j = 0, ... , n, rev_jac_flag[ x_index[j] ] is set to true +if the varialbe with index x_index[j] has possible non-zero Jacobian +with repect to one of the true y_index[i] cases. +Otherwise, rev_jac_flag [ x_inde[j] ] is not changed. + +\param hes_sparsity_rev +Is the reverse mode sparsity pattern for the Hessian. On input, the non-linear +terms in the atomic fuction have not been included. Upon return, they +have been included. +*/ +template +template +bool atomic_three::rev_hes_sparsity( + const vector& parameter_x , + const vector& type_x , + const local::pod_vector& x_index , + const local::pod_vector& y_index , + const InternalSparsity& for_jac_pattern , + bool* rev_jac_flag , + InternalSparsity& hes_sparsity_rev ) +{ typedef typename InternalSparsity::const_iterator const_iterator; + size_t n = x_index.size(); + size_t m = y_index.size(); + // + // select_x + vector select_x(n); + for(size_t j = 0; j < n; j++) + { // check if should compute pattern w.r.t x[j] + const_iterator itr(for_jac_pattern, x_index[j]); + size_t i = *itr; + select_x[j] = i < for_jac_pattern.end(); + CPPAD_ASSERT_UNKNOWN( x_index[j] > 0 || ! select_x[j] ); + } + // + // bool select_y + vector select_y(m); + for(size_t i = 0; i < m; i++) + { // check if we should include y[i] + select_y[i] = rev_jac_flag[ y_index[i] ]; + CPPAD_ASSERT_UNKNOWN( y_index[i] > 0 || ! select_y[i] ); + } + // + // call atomic function for Jacobain sparsity + bool dependency = false; + sparse_rc< vector > pattern_jac; + bool ok = jac_sparsity( + parameter_x, type_x, dependency, select_x, select_y, pattern_jac + ); + const vector& row_jac( pattern_jac.row() ); + const vector& col_jac( pattern_jac.col() ); + size_t nnz_jac = pattern_jac.nnz(); + if( ! ok ) + return ok; + // + // call atomic function for Hessian sparsity + sparse_rc< vector > pattern_hes; + ok = hes_sparsity(parameter_x, type_x, select_x, select_y, pattern_hes); + const vector& row_hes( pattern_hes.row() ); + const vector& col_hes( pattern_hes.col() ); + size_t nnz_hes = pattern_hes.nnz(); + if( ! ok ) + return ok; + // + // propagate Hessian sparsity through the Jacobian + for(size_t k = 0; k < nnz_jac; ++k) + { size_t i = row_jac[k]; + size_t j = col_jac[k]; + CPPAD_ASSERT_KNOWN( + select_y[i] & select_x[j] , + "atomic: jac_sparsity: pattern_out not in " + "select_x or select_y range" + ); + // from y_index[i] to x_index[j] + hes_sparsity_rev.binary_union( + x_index[j], x_index[j], y_index[i], hes_sparsity_rev + ); + } + // + // propagate rev_jac_flag through the Jacobian + // (seems OK to exclude variables with zero forward jacobian) + for(size_t k = 0; k < nnz_jac; ++k) + { size_t j = col_jac[k]; + rev_jac_flag[ x_index[j] ] = true; + } + // + // new hessian sparsity terms between y and x + for(size_t k = 0; k < nnz_hes; ++k) + { size_t r = row_hes[k]; + size_t c = col_hes[k]; + CPPAD_ASSERT_KNOWN( + select_x[r] & select_x[c] , + "atomic: hes_sparsity: pattern_out not in select_x range" + ); + hes_sparsity_rev.binary_union( + x_index[r], x_index[r], x_index[c], for_jac_pattern + ); + hes_sparsity_rev.binary_union( + x_index[c], x_index[c], x_index[r], for_jac_pattern + ); + } + return ok; +} + +} // END_CPPAD_NAMESPACE + +# endif diff --git a/build-config/cppad/include/cppad/core/atomic/three_jac_sparsity.hpp b/build-config/cppad/include/cppad/core/atomic/three_jac_sparsity.hpp new file mode 100644 index 00000000..234a3d67 --- /dev/null +++ b/build-config/cppad/include/cppad/core/atomic/three_jac_sparsity.hpp @@ -0,0 +1,355 @@ +# ifndef CPPAD_CORE_ATOMIC_THREE_JAC_SPARSITY_HPP +# define CPPAD_CORE_ATOMIC_THREE_JAC_SPARSITY_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ +/* +$begin atomic_three_jac_sparsity$$ +$spell + Jacobian + afun + jac +$$ + +$section Atomic Function Jacobian Sparsity Patterns$$ + +$head Syntax$$ +$icode%ok% = %afun%.jac_sparsity( + %parameter_x%, %type_x%, %dependency%, %select_x%, %select_y%, %pattern_out% +)%$$ + +$head Prototype$$ +$srcthisfile%0%// BEGIN_PROTOTYPE%// END_PROTOTYPE%1 +%$$ + +$head Implementation$$ +This function must be defined if +$cref/afun/atomic_three_ctor/atomic_user/afun/$$ is +used to define an $cref ADFun$$ object $icode f$$, +and Jacobian sparsity patterns are computed for $icode f$$. +(Computing Hessian sparsity patterns and optimizing +requires Jacobian sparsity patterns.) + +$head Base$$ +See $cref/Base/atomic_three_afun/Base/$$. + +$head parameter_x$$ +See $cref/parameter_x/atomic_three/parameter_x/$$. + +$head type_x$$ +See $cref/type_x/atomic_three/type_x/$$. + +$head dependency$$ +If $icode dependency$$ is true, +then $icode pattern_out$$ is a +$cref/dependency pattern/dependency.cpp/Dependency Pattern/$$ +for this atomic function. +Otherwise it is a +$cref/sparsity pattern/glossary/Sparsity Pattern/$$ for the +derivative of the atomic function. + +$head select_x$$ +This argument has size equal to the number of arguments to this +atomic function; i.e. the size of $icode ax$$. +It specifies which domain components are included in +the calculation of $icode pattern_out$$. +If $icode%select_x%[%j%]%$$ is false, then there will be no indices +$icode k$$ such that +$codei% + %pattern_out%.col()[%k%] == %j% +%$$. + +$head select_y$$ +This argument has size equal to the number of results to this +atomic function; i.e. the size of $icode ay$$. +It specifies which range components are included in +the calculation of $icode pattern_out$$. +If $icode%select_y%[%i%]%$$ is false, then there will be no indices +$icode k$$ such that +$codei% + %pattern_out%.row()[%k%] == %i% +%$$. + +$head pattern_out$$ +This input value of $icode pattern_out$$ does not matter. +Upon return it is a +dependency or sparsity pattern for the Jacobian of $latex g(x)$$, +the function corresponding to +$cref/afun/atomic_three_ctor/atomic_user/afun/$$; +$icode dependency$$ above. +To be specific, there are non-negative indices +$icode i$$, $icode j$$, $icode k$$ such that +$codei% + %pattern_out%.row()[%k%] == %i% + %pattern_out%.col()[%k%] == %j% +%$$ +if and only if +$icode%select_x%[%j%]%$$ is true, +$icode%select_y%[%j%]%$$ is true, +and $latex g_i(x)$$ depends on the value of $latex x_j$$ +(and the partial of $latex g_i(x)$$ with respect to +$latex x_j$$ is possibly non-zero). + +$head ok$$ +If this calculation succeeded, $icode ok$$ is true. +Otherwise it is false. + + +$children% + example/atomic_three/jac_sparsity.cpp +%$$ +$head Examples$$ +The file $cref atomic_three_jac_sparsity.cpp$$ contains an example and test +that uses this routine. +$end +----------------------------------------------------------------------------- +*/ + +namespace CppAD { // BEGIN_CPPAD_NAMESPACE +/*! +\file atomic/three_jac_sparsity.hpp +Third generation atomic Jacobian dependency and sparsity patterns. +*/ +/*! +atomic_three to Jacobian dependency and sparsity calculations. + +\param parameter_x [in] +contains the values for arguments that are parameters. + +\param type_x [in] +what is the type, in afun(ax, ay), for each component of x. + +\param dependency [in] +if true, calculate dependency pattern, +otherwise calcuate sparsity pattern. + +\param select_x [in] +which domain components to include in the dependency or sparsity pattern. +The index zero is used for parameters. + +\param select_y [in] +which range components to include in the dependency or sparsity pattern. +The index zero is used for parameters. + +\param pattern_out [out] +is the dependency or sparsity pattern. +*/ +// BEGIN_PROTOTYPE +template +bool atomic_three::jac_sparsity( + const vector& parameter_x , + const vector& type_x , + bool dependency , + const vector& select_x , + const vector& select_y , + sparse_rc< vector >& pattern_out ) +// END_PROTOTYPE +{ return false; } +/*! +Link from forward Jacobian sparsity calcuations to atomic_three + +\tparam InternalSparsity +Is the type used for internal sparsity calculations; i.e., +sparse_pack or sparse_list. + +\param dependency +if true, calcuate dependency pattern, +otherwise calcuate sparsity pattern. + +\param parameter_x +is parameter arguments to the function, other components are nan. + +\param type_x [in] +what is the type, in afun(ax, ay), for each component of x. + +\param x_index +is the variable index, on the tape, for the arguments to this atomic function. +This size of x_index is n, the number of arguments to this atomic function. +The index zero is used for parameters. + +\param y_index +is the variable index, on the tape, for the results for this atomic function. +This size of y_index is m, the number of results for this atomic function. +The index zero is used for parameters. + +\param var_sparsity +On input, for j = 0, ... , n-1, the sparsity pattern with index x_index[j], +is the sparsity for the j-th argument to this atomic function. +On output, for i = 0, ... , m-1, the sparsity pattern with index y_index[i], +is the sparsity for the i-th result for this atomic function. + +\return +is true if the computation succeeds. +*/ +template +template +bool atomic_three::for_jac_sparsity( + bool dependency , + const vector& parameter_x , + const vector& type_x , + const local::pod_vector& x_index , + const local::pod_vector& y_index , + InternalSparsity& var_sparsity ) +{ typedef typename InternalSparsity::const_iterator iterator; + + // number of arguments and resutls for this atomic function + size_t n = x_index.size(); + size_t m = y_index.size(); + + // select_y + vector select_y(m); + for(size_t i = 0; i < m; ++i) + select_y[i] = y_index[i] != 0; + + // determine select_x + vector select_x(n); + for(size_t j = 0; j < n; ++j) + { // check if x_j depends on any previous variable + iterator itr(var_sparsity, x_index[j]); + size_t ell = *itr; + select_x[j] = ell < var_sparsity.end(); + CPPAD_ASSERT_UNKNOWN( x_index[j] > 0 || ! select_x[j] ); + } + sparse_rc< vector > pattern_out; + bool ok = jac_sparsity( + parameter_x, type_x, dependency, select_x, select_y, pattern_out + ); + if( ! ok ) + return false; + // + // transfer sparsity patterns from pattern_out to var_sparsity + size_t nnz = pattern_out.nnz(); + const vector& row( pattern_out.row() ); + const vector& col( pattern_out.col() ); + for(size_t k = 0; k < nnz; ++k) + { size_t i = row[k]; + size_t j = col[k]; + CPPAD_ASSERT_KNOWN( + select_y[i] & select_x[j], + "atomic: jac_sparsity: pattern_out not in " + "select_x or select_y range" + ); + iterator itr(var_sparsity, x_index[j]); + size_t ell = *itr; + while( ell < var_sparsity.end() ) + { var_sparsity.post_element( y_index[i], ell ); + ell = *(++itr); + } + } + for(size_t i = 0; i < m; ++i) + var_sparsity.process_post( y_index[i] ); + // + return true; +} +/*! +Link from reverse Jacobian sparsity calcuations to atomic_three + +\tparam InternalSparsity +Is the type used for internal sparsity calculations; i.e., +sparse_pack or sparse_list. + +\param dependency +if true, calcuate dependency pattern, +otherwise calcuate sparsity pattern. + +\param parameter_x +is parameter arguments to the function, other components are nan. + +\param type_x [in] +what is the type, in afun(ax, ay), for each component of x. + +\param x_index +is the variable index, on the tape, for the arguments to this atomic function. +This size of x_index is n, the number of arguments to this atomic function. + +\param y_index +is the variable index, on the tape, for the results for this atomic function. +This size of y_index is m, the number of results for this atomic function. + +\param var_sparsity +On input, for i = 0, ... , m-1, the sparsity pattern with index y_index[i], +is the sparsity of the outter function with respect to the i-th +result for this atomic function. +On input, for j = 0, ... , n-1, the sparsity pattern with index x_index[j], +is the sparsity for the outter function with repsect to the j-th +argument to this atomic function. +On output, for j = 0, ... , n-1, the sparsity pattern with index x_index[j], +is the sparsity for the outter function with repsect to the j-th +argument to this atomic function with the atomic function results +removed as arguments to the outter function. + +\return +is true if the computation succeeds. +*/ +template +template +bool atomic_three::rev_jac_sparsity( + bool dependency , + const vector& parameter_x , + const vector& type_x , + const local::pod_vector& x_index , + const local::pod_vector& y_index , + InternalSparsity& var_sparsity ) +{ typedef typename InternalSparsity::const_iterator iterator; + + // number of arguments and resutls for this atomic function + size_t n = x_index.size(); + size_t m = y_index.size(); + + // selection vectors + vector select_x(n), select_y(m); + + // 2DO: perhaps we could use for_type(type_x, type_y) + // to reduce the true components in select_x + for(size_t j = 0; j < n; ++j) + select_x[j] = true; + + // determine select_y + for(size_t i = 0; i < m; ++i) + { // check if y_i has sparsity is non-empty + iterator itr(var_sparsity, y_index[i]); + size_t ell = *itr; + select_y[i] = ell < var_sparsity.end(); + } + sparse_rc< vector > pattern_out; + bool ok = jac_sparsity( + parameter_x, type_x, dependency, select_x, select_y, pattern_out + ); + if( ! ok ) + return false; + // + // transfer sparsity patterns from pattern_out to var_sparsity + size_t nnz = pattern_out.nnz(); + const vector& row( pattern_out.row() ); + const vector& col( pattern_out.col() ); + for(size_t k = 0; k < nnz; ++k) + { size_t i = row[k]; + size_t j = col[k]; + CPPAD_ASSERT_KNOWN( + select_y[i] & select_x[j], + "atomic: jac_sparsity: pattern_out not in " + "select_x or select_y range" + ); + iterator itr(var_sparsity, y_index[i]); + size_t ell = *itr; + while( ell < var_sparsity.end() ) + { var_sparsity.post_element( x_index[j], ell ); + ell = *(++itr); + } + } + for(size_t j = 0; j < n; ++j) + var_sparsity.process_post( x_index[j] ); + // + return true; +} + +} // END_CPPAD_NAMESPACE +# endif diff --git a/build-config/cppad/include/cppad/core/atomic/three_rev_depend.hpp b/build-config/cppad/include/cppad/core/atomic/three_rev_depend.hpp new file mode 100644 index 00000000..d05e91a1 --- /dev/null +++ b/build-config/cppad/include/cppad/core/atomic/three_rev_depend.hpp @@ -0,0 +1,125 @@ +# ifndef CPPAD_CORE_ATOMIC_THREE_REV_DEPEND_HPP +# define CPPAD_CORE_ATOMIC_THREE_REV_DEPEND_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ +/* +$begin atomic_three_rev_depend$$ +$spell + afun + enum + cpp + taylor.hpp +$$ + +$section Atomic Function Reverse Dependency Calculation$$ + +$head Syntax$$ +$icode%ok% = %afun%.rev_depend( + %parameter_x%, %type_x%, %depend_x%, %depend_y% +)%$$ + +$subhead Prototype$$ +$srcthisfile%0%// BEGIN_PROTOTYPE%// END_PROTOTYPE%1 +%$$ + +$head Dependency Analysis$$ +This calculation is sometimes referred to as a reverse dependency analysis. + +$head Implementation$$ +This function must be defined if +$cref/afun/atomic_three_ctor/atomic_user/afun/$$ is +used to define an $cref ADFun$$ object $icode f$$, +and $cref/f.optimize()/optimize/$$ is used. + +$head Base$$ +See $cref/Base/atomic_three_afun/Base/$$. + +$head parameter_x$$ +See $cref/parameter_x/atomic_three/parameter_x/$$. + +$head type_x$$ +See $cref/type_x/atomic_three/type_x/$$. + +$head depend_x$$ +This vector has size equal to the number of arguments for this atomic function; +i.e. $icode%n%=%ax%.size()%$$. +The input values of the elements of $icode depend_x$$ +are not specified (must not matter). +Upon return, for $latex j = 0 , \ldots , n-1$$, +$icode%depend_x%[%j%]%$$ is true if the values of interest depend +on the value of $cref/ax[j]/atomic_three_afun/ax/$$ in the corresponding +$icode%afun%(%ax%, %ay%)%$$ call. +Note that parameters and variables, +that the values of interest do not depend on, +may get removed by $cref/optimization/optimize/$$. +The corresponding values in $cref/parameter_x/atomic_three/parameter_x/$$, +and $cref/taylor_x/atomic_three_forward/taylor_x/$$ +(after optimization has removed them) are not specified. + +$head depend_y$$ +This vector has size equal to the number of results for this atomic function; +i.e. $icode%m%=%ay%.size()%$$. +For $latex i = 0 , \ldots , m-1$$, +$icode%depend_y%[%i%]%$$ is true if the values of interest depend +on the value of $cref/ay[i]/atomic_three_afun/ay/$$ in the corresponding +$icode%afun%(%ax%, %ay%)%$$ call. + +$head ok$$ +If this calculation succeeded, $icode ok$$ is true. +Otherwise, it is false. + +$childtable% + example/atomic_three/rev_depend.cpp +%$$ +$head Example$$ +The following is an example of a atomic function $code rev_depend$$ definition: +$cref atomic_three_rev_depend.cpp$$. + + +$end +----------------------------------------------------------------------------- +*/ + +namespace CppAD { // BEGIN_CPPAD_NAMESPACE +/*! +\file atomic/three_rev_depend.hpp +Third generation atomic type computation. +*/ +/*! +Link from atomic_three to reverse dependency calculation + +\param parameter_x [in] +is the value of the parameters in the corresponding function call +afun(ax, ay). + +\param type_x [in] +is the value for each of the components of x. + +\param depend_x [out] +specifies which components of x affect values of interest. + +\param depend_y [in] +specifies which components of y affect values of interest. +*/ +// BEGIN_PROTOTYPE +template +bool atomic_three::rev_depend( + const vector& parameter_x , + const vector& type_x , + vector& depend_x , + const vector& depend_y ) +// END_PROTOTYPE +{ return false; } + +} // END_CPPAD_NAMESPACE + +# endif diff --git a/build-config/cppad/include/cppad/core/atomic/three_reverse.hpp b/build-config/cppad/include/cppad/core/atomic/three_reverse.hpp new file mode 100644 index 00000000..99dd6091 --- /dev/null +++ b/build-config/cppad/include/cppad/core/atomic/three_reverse.hpp @@ -0,0 +1,354 @@ +# ifndef CPPAD_CORE_ATOMIC_THREE_REVERSE_HPP +# define CPPAD_CORE_ATOMIC_THREE_REVERSE_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ +/* +$begin atomic_three_reverse$$ +$spell + sq + mul.hpp + afun + ty + px + py + Taylor + const + CppAD + atx + aty + apx + apy + af + aparameter + enum +$$ + +$section Atomic Function Reverse Mode$$ +$spell + ataylor + apartial +$$ + +$head Base$$ +This syntax is used by $icode%f%.Reverse%$$ where $icode f$$ has prototype +$codei% + ADFun<%Base%> %f% +%$$ +and $icode afun$$ is used in $icode f$$; +see $cref/Base/atomic_three_afun/Base/$$. + +$subhead Syntax$$ +$icode%ok% = %afun%.reverse( + %parameter_x%, %type_x%, + %order_up%, %taylor_x%, %taylor_y%, %partial_x%, %partial_y% +) +%$$ + +$subhead Prototype$$ +$srcthisfile%0%// BEGIN_PROTOTYPE_BASE%// END_PROTOTYPE_BASE%1 +%$$ + +$head AD$$ +This syntax is used by $icode%af%.Reverse%$$ where $icode af$$ has prototype +$codei% + ADFun< AD<%Base%> , %Base% > %af% +%$$ +and $icode afun$$ is used in $icode af$$ (see $cref base2ad$$). + +$subhead Syntax$$ +$icode%ok% = %afun%.reverse( + %aparameter_x%, %type_x%, + %order_up%, %ataylor_x%, %ataylor_y%, %apartial_x%, %apartial_y% +) +%$$ + +$subhead Prototype$$ +$srcthisfile%0%// BEGIN_PROTOTYPE_AD_BASE%// END_PROTOTYPE_AD_BASE%1 +%$$ + +$head Implementation$$ +This function must be defined if +$cref/afun/atomic_three_ctor/atomic_user/afun/$$ is +used to define an $cref ADFun$$ object $icode f$$, +and reverse mode derivatives are computed for $icode f$$. +It can return $icode%ok% == false%$$ +(and not compute anything) for values +of $icode order_up$$ that are greater than those used by your +$cref/reverse/Reverse/$$ mode calculations. + +$head parameter_x$$ +See $cref/parameter_x/atomic_three/parameter_x/$$. + +$head aparameter_x$$ +The specifications for $icode aparameter_x$$ +is the same as for $cref/parameter_x/atomic_three/parameter_x/$$ +(only the type of $icode ataylor_x$$ is different). + +$head type_x$$ +See $cref/type_x/atomic_three/type_x/$$. + +$head order_up$$ +This argument specifies the highest order Taylor coefficient that +computing the derivative of. + +$head taylor_x$$ +The size of $icode taylor_x$$ is $codei%(%q%+1)*%n%$$. +For $latex j = 0 , \ldots , n-1$$ and $latex k = 0 , \ldots , q$$, +we use the Taylor coefficient notation +$latex \[ +\begin{array}{rcl} + x_j^k & = & \R{taylor\_x} [ j * ( q + 1 ) + k ] + \\ + X_j (t) & = & x_j^0 + x_j^1 t^1 + \cdots + x_j^q t^q +\end{array} +\] $$ +Note that superscripts represent an index for $latex x_j^k$$ +and an exponent for $latex t^k$$. +Also note that the Taylor coefficients for $latex X(t)$$ correspond +to the derivatives of $latex X(t)$$ at $latex t = 0$$ in the following way: +$latex \[ + x_j^k = \frac{1}{ k ! } X_j^{(k)} (0) +\] $$ + +$subhead parameters$$ +If the $th j$$ component of $icode x$$ corresponds to a parameter, +$codei% + %type_x%[%j%] < CppAD::variable_enum +%$$ +In this case, +the $th j$$ component of $icode parameter_x$$ is equal to $latex x_j^0$$; +i.e., +$codei% + %parameter_x%[%j%] == %taylor_x%[ %j% * ( %q% + 1 ) + 0 ] +%$$ +Furthermore, for $icode%k% > 0%$$, +$codei% + %taylor_x%[ %j% * ( %q% + 1 ) + %k% ] == 0 +%$$ + +$head ataylor_x$$ +The specifications for $icode ataylor_x$$ is the same as for $icode taylor_x$$ +(only the type of $icode ataylor_x$$ is different). + +$head taylor_y$$ +The size of $icode taylor_y$$ is $codei%(%q%+1)*%m%$$. +Upon return, +For $latex i = 0 , \ldots , m-1$$ and $latex k = 0 , \ldots , q$$, +we use the Taylor coefficient notation +$latex \[ +\begin{array}{rcl} + Y_i (t) & = & g_i [ X(t) ] + \\ + Y_i (t) & = & y_i^0 + y_i^1 t^1 + \cdots + y_i^q t^q + o ( t^q ) + \\ + y_i^k & = & \R{taylor\_y} [ i * ( q + 1 ) + k ] +\end{array} +\] $$ +where $latex o( t^q ) / t^q \rightarrow 0$$ as $latex t \rightarrow 0$$. +Note that superscripts represent an index for $latex y_j^k$$ +and an exponent for $latex t^k$$. +Also note that the Taylor coefficients for $latex Y(t)$$ correspond +to the derivatives of $latex Y(t)$$ at $latex t = 0$$ in the following way: +$latex \[ + y_j^k = \frac{1}{ k ! } Y_j^{(k)} (0) +\] $$ + +$head ataylor_y$$ +The specifications for $icode ataylor_y$$ is the same as for $icode taylor_y$$ +(only the type of $icode ataylor_y$$ is different). + +$head F$$ +We use the notation $latex \{ x_j^k \} \in \B{R}^{n \times (q+1)}$$ for +$latex \[ + \{ x_j^k \W{:} j = 0 , \ldots , n-1, k = 0 , \ldots , q \} +\]$$ +We use the notation $latex \{ y_i^k \} \in \B{R}^{m \times (q+1)}$$ for +$latex \[ + \{ y_i^k \W{:} i = 0 , \ldots , m-1, k = 0 , \ldots , q \} +\]$$ +We define the function +$latex F : \B{R}^{n \times (q+1)} \rightarrow \B{R}^{m \times (q+1)}$$ by +$latex \[ + y_i^k = F_i^k [ \{ x_j^k \} ] +\] $$ +Note that +$latex \[ + F_i^0 ( \{ x_j^k \} ) = g_i ( X(0) ) = g_i ( x^0 ) +\] $$ +We also note that +$latex F_i^\ell ( \{ x_j^k \} )$$ is a function of +$latex x^0 , \ldots , x^\ell$$ +and is determined by the derivatives of $latex g_i (x)$$ +up to order $latex \ell$$. + +$head G, H$$ +We use $latex G : \B{R}^{m \times (q+1)} \rightarrow \B{R}$$ +to denote an arbitrary scalar valued function of $latex \{ y_i^k \}$$. +We use $latex H : \B{R}^{n \times (q+1)} \rightarrow \B{R}$$ +defined by +$latex \[ + H ( \{ x_j^k \} ) = G[ F( \{ x_j^k \} ) ] +\] $$ + +$head partial_y$$ +The size of $icode partial_y$$ is $codei%(%q%+1)*%m%%$$. +For $latex i = 0 , \ldots , m-1$$, $latex k = 0 , \ldots , q$$, +$latex \[ + \R{partial\_y} [ i * (q + 1 ) + k ] = \partial G / \partial y_i^k +\] $$ + +$head apartial_y$$ +The specifications for $icode apartial_y$$ is the same as for +$icode partial_y$$ (only the type of $icode apartial_y$$ is different). + +$head partial_x$$ +The size of $icode partial_x$$ is $codei%(%q%+1)*%n%%$$. +The input values of the elements of $icode partial_x$$ +are not specified (must not matter). +Upon return, +for $latex j = 0 , \ldots , n-1$$ and $latex \ell = 0 , \ldots , q$$, +$latex \[ +\begin{array}{rcl} +\R{partial\_x} [ j * (q + 1) + \ell ] & = & \partial H / \partial x_j^\ell +\\ +& = & +( \partial G / \partial \{ y_i^k \} ) \cdot + ( \partial \{ y_i^k \} / \partial x_j^\ell ) +\\ +& = & +\sum_{k=0}^q +\sum_{i=0}^{m-1} +( \partial G / \partial y_i^k ) ( \partial y_i^k / \partial x_j^\ell ) +\\ +& = & +\sum_{k=\ell}^q +\sum_{i=0}^{m-1} +\R{partial\_y}[ i * (q + 1 ) + k ] ( \partial F_i^k / \partial x_j^\ell ) +\end{array} +\] $$ +Note that we have used the fact that for $latex k < \ell$$, +$latex \partial F_i^k / \partial x_j^\ell = 0$$. + +$subhead Short Circuit Operations$$ +Note that if +$codei%IdenticalZero(%partial_y%[%i%*(%q%+1)+%k%])%$$ is true, +one does not need to compute $latex ( \partial F_i^k / \partial x_j^\ell )$$; +see $cref base_identical$$. +This can be used, +in a similar way to $cref/need_y/atomic_three_forward/need_y/$$, +to avoid unnecessary operations. + +$head apartial_x$$ +The specifications for $icode apartial_x$$ is the same as for +$icode partial_x$$ (only the type of $icode apartial_x$$ is different). + +$head ok$$ +If this calculation succeeded, $icode ok$$ is true. +Otherwise it is false. + +$children% + example/atomic_three/reverse.cpp +%$$ +$head Examples$$ +The file $cref atomic_three_reverse.cpp$$ contains an example and test +that uses this routine. + +$end +----------------------------------------------------------------------------- +*/ + +namespace CppAD { // BEGIN_CPPAD_NAMESPACE +/*! +\file atomic/three_reverse.hpp +Third Generation Atomic reverse mode. +*/ +/*! +Link from reverse mode sweep to users routine. + +\param parameter_x [in] +contains the values, in afun(ax, ay), for arguments that are parameters. + +\param type_x [in] +what is the type, in afun(ax, ay), for each component of x. + +\param order_up [in] +highest order for this reverse mode calculation. + +\param taylor_x [in] +Taylor coefficients corresponding to x for this calculation. + +\param taylor_y [in] +Taylor coefficient corresponding to y for this calculation + +\param partial_x [out] +Partials w.r.t. the x Taylor coefficients. + +\param partial_y [in] +Partials w.r.t. the y Taylor coefficients. + +See atomic_three_reverse mode use documentation +*/ +// BEGIN_PROTOTYPE_BASE +template +bool atomic_three::reverse( + const vector& parameter_x , + const vector& type_x , + size_t order_up , + const vector& taylor_x , + const vector& taylor_y , + vector& partial_x , + const vector& partial_y ) +// END_PROTOTYPE_BASE +{ return false; } + +/*! +Link from reverse mode sweep to users routine. + +\param aparameter_x [in] +contains the values, in afun(ax, ay), for arguments that are parameters. + +\param type_x [in] +what is the type, in afun(ax, ay), for each component of x. + + +\param order_up [in] +highest order for this reverse mode calculation. + +\param ataylor_x [in] +Taylor coefficients corresponding to x for this calculation. + +\param ataylor_y [in] +Taylor coefficient corresponding to y for this calculation + +\param apartial_x [out] +Partials w.r.t. the x Taylor coefficients. + +\param apartial_y [in] +Partials w.r.t. the y Taylor coefficients. + +See atomic_three_reverse mode use documentation +*/ +// BEGIN_PROTOTYPE_AD_BASE +template +bool atomic_three::reverse( + const vector< AD >& aparameter_x , + const vector& type_x , + size_t order_up , + const vector< AD >& ataylor_x , + const vector< AD >& ataylor_y , + vector< AD >& apartial_x , + const vector< AD >& apartial_y ) +// END_PROTOTYPE_AD_BASE +{ return false; } + +} // END_CPPAD_NAMESPACE +# endif diff --git a/build-config/cppad/include/cppad/core/atomic/two_afun.hpp b/build-config/cppad/include/cppad/core/atomic/two_afun.hpp new file mode 100644 index 00000000..8aba0f37 --- /dev/null +++ b/build-config/cppad/include/cppad/core/atomic/two_afun.hpp @@ -0,0 +1,258 @@ +# ifndef CPPAD_CORE_ATOMIC_TWO_AFUN_HPP +# define CPPAD_CORE_ATOMIC_TWO_AFUN_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ +/* +$begin atomic_two_afun$$ + +$spell + sq + mul + afun + const + CppAD + mat_mul.cpp +$$ + +$section Using AD Version of Atomic Function$$ + +$head Syntax$$ +$icode%afun%(%ax%, %ay%)%$$ + +$head Purpose$$ +Given $icode ax$$, +this call computes the corresponding value of $icode ay$$. +If $codei%AD<%Base%>%$$ operations are being recorded, +it enters the computation as an atomic operation in the recording; +see $cref/start recording/Independent/Start Recording/$$. + +$head ADVector$$ +The type $icode ADVector$$ must be a +$cref/simple vector class/SimpleVector/$$ with elements of type +$codei%AD<%Base%>%$$; see $cref/Base/atomic_two_ctor/atomic_base/Base/$$. + +$head afun$$ +is a $cref/atomic_user/atomic_two_ctor/atomic_user/$$ object +and this $icode afun$$ function call is implemented by the +$cref/atomic/atomic_two_ctor/atomic_base/$$ class. + +$head ax$$ +This argument has prototype +$codei% + const %ADVector%& %ax% +%$$ +and size must be equal to $icode n$$. +It specifies vector $latex x \in \B{R}^n$$ +at which an $codei%AD<%Base%>%$$ version of +$latex y = f(x)$$ is to be evaluated; see +$cref/Base/atomic_two_ctor/atomic_base/Base/$$. + +$head ay$$ +This argument has prototype +$codei% + %ADVector%& %ay% +%$$ +and size must be equal to $icode m$$. +The input values of its elements +are not specified (must not matter). +Upon return, it is an $codei%AD<%Base%>%$$ version of +$latex y = f(x)$$. + +$end +----------------------------------------------------------------------------- +*/ + +namespace CppAD { // BEGIN_CPPAD_NAMESPACE +/*! +\file atomic/two_afun.hpp +Implement user call to an atomic_two function. +*/ + +/*! +Implement the user call to afun(ax, ay) and atomic_one call to +afun(ax, ay, id). + +\tparam ADVector +A simple vector class with elements of type AD. + +\param id +optional extra information vector that is just passed through by CppAD, +and used by atomic_one derived class (not other derived classes). +This is an extra parameter to the virtual callbacks for atomic_one; +see the set_old member function. + +\param ax +is the argument vector for this call, +ax.size() determines the number of arguments. + +\param ay +is the result vector for this call, +ay.size() determines the number of results. +*/ +template +template +void atomic_base::operator()( + const ADVector& ax , + ADVector& ay , + size_t id ) +{ size_t i, j; + size_t n = ax.size(); + size_t m = ay.size(); +# ifndef NDEBUG + bool ok; + std::string msg = "atomic_base: " + atomic_name() + ".eval: "; + if( (n == 0) | (m == 0) ) + { msg += "ax.size() or ay.size() is zero"; + CPPAD_ASSERT_KNOWN(false, msg.c_str() ); + } +# endif + size_t thread = thread_alloc::thread_num(); + allocate_work(thread); + vector & tx = work_[thread]->tx; + vector & ty = work_[thread]->ty; + vector & vx = work_[thread]->vx; + vector & vy = work_[thread]->vy; + // + if( vx.size() != n ) + { vx.resize(n); + tx.resize(n); + } + if( vy.size() != m ) + { vy.resize(m); + ty.resize(m); + } + // + // Determine tape corresponding to variables in ax + tape_id_t tape_id = 0; + local::ADTape* tape = nullptr; + for(j = 0; j < n; j++) + { tx[j] = ax[j].value_; + vx[j] = ! Constant( ax[j] ); + if( vx[j] ) + { + if( tape_id == 0 ) + { tape = ax[j].tape_this(); + tape_id = ax[j].tape_id_; + CPPAD_ASSERT_UNKNOWN( tape != nullptr ); + } +# ifndef NDEBUG + if( tape_id != ax[j].tape_id_ ) + { msg += atomic_name() + + ": ax contains variables from different threads."; + CPPAD_ASSERT_KNOWN(false, msg.c_str()); + } +# endif + } + } + // Use zero order forward mode to compute values + size_t p = 0, q = 0; + set_old(id); +# ifdef NDEBUG + forward(p, q, vx, vy, tx, ty); +# else + ok = forward(p, q, vx, vy, tx, ty); + if( ! ok ) + { msg += atomic_name() + ": ok is false for " + "zero order forward mode calculation."; + CPPAD_ASSERT_KNOWN(false, msg.c_str()); + } +# endif + bool record_operation = false; + for(i = 0; i < m; i++) + { + // pass back values + ay[i].value_ = ty[i]; + + // initialize entire vector parameters (not in tape) + ay[i].tape_id_ = 0; + ay[i].taddr_ = 0; + + // we need to record this operation if + // any of the elemnts of ay are variables, + record_operation |= vy[i]; + } +# ifndef NDEBUG + if( record_operation & (tape == nullptr) ) + { msg += + "all elements of vx are false but vy contains a true element"; + CPPAD_ASSERT_KNOWN(false, msg.c_str() ); + } +# endif + // if tape is not null, ay is on the tape + if( record_operation ) + { + // Operator that marks beginning of this atomic operation + CPPAD_ASSERT_UNKNOWN( local::NumRes(local::AFunOp) == 0 ); + CPPAD_ASSERT_UNKNOWN( local::NumArg(local::AFunOp) == 4 ); + CPPAD_ASSERT_KNOWN( + size_t( std::numeric_limits::max() ) >= + std::max( std::max( std::max(index_, id), n), m ), + "atomic_base: cppad_tape_addr_type maximum not large enough" + ); + tape->Rec_.PutArg(addr_t(index_), addr_t(id), addr_t(n), addr_t(m)); + tape->Rec_.PutOp(local::AFunOp); + + // Now put n operators, one for each element of argument vector + CPPAD_ASSERT_UNKNOWN( local::NumRes(local::FunavOp) == 0 ); + CPPAD_ASSERT_UNKNOWN( local::NumRes(local::FunapOp) == 0 ); + CPPAD_ASSERT_UNKNOWN( local::NumArg(local::FunavOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( local::NumArg(local::FunapOp) == 1 ); + for(j = 0; j < n; j++) + { if( Variable(ax[j]) ) + { // information for an argument that is a variable + tape->Rec_.PutArg(ax[j].taddr_); + tape->Rec_.PutOp(local::FunavOp); + } + else + { // information for an argument that is parameter + addr_t par = ax[j].taddr_; + if( ! Dynamic( ax[j] ) ) + par = tape->Rec_.put_con_par(ax[j].value_); + tape->Rec_.PutArg(par); + tape->Rec_.PutOp(local::FunapOp); + } + } + + // Now put m operators, one for each element of result vector + CPPAD_ASSERT_UNKNOWN( local::NumArg(local::FunrpOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( local::NumRes(local::FunrpOp) == 0 ); + CPPAD_ASSERT_UNKNOWN( local::NumArg(local::FunrvOp) == 0 ); + CPPAD_ASSERT_UNKNOWN( local::NumRes(local::FunrvOp) == 1 ); + for(i = 0; i < m; i++) + { if( vy[i] ) + { ay[i].taddr_ = tape->Rec_.PutOp(local::FunrvOp); + ay[i].tape_id_ = tape_id; + ay[i].ad_type_ = variable_enum; + } + else + { CPPAD_ASSERT_UNKNOWN( ! Dynamic( ay[i] ) ); + addr_t par = tape->Rec_.put_con_par(ay[i].value_); + tape->Rec_.PutArg(par); + tape->Rec_.PutOp(local::FunrpOp); + } + } + + // Put a duplicate AFunOp at end of AFunOp sequence + CPPAD_ASSERT_KNOWN( + size_t( std::numeric_limits::max() ) >= + std::max( std::max( std::max(index_, id), n), m ), + "atomic_base: cppad_tape_addr_type maximum not large enough" + ); + tape->Rec_.PutArg(addr_t(index_), addr_t(id), addr_t(n), addr_t(m)); + tape->Rec_.PutOp(local::AFunOp); + } + return; +} + + +} // END_CPPAD_NAMESPACE +# endif diff --git a/build-config/cppad/include/cppad/core/atomic/two_clear.hpp b/build-config/cppad/include/cppad/core/atomic/two_clear.hpp new file mode 100644 index 00000000..0223be73 --- /dev/null +++ b/build-config/cppad/include/cppad/core/atomic/two_clear.hpp @@ -0,0 +1,91 @@ +# ifndef CPPAD_CORE_ATOMIC_TWO_CLEAR_HPP +# define CPPAD_CORE_ATOMIC_TWO_CLEAR_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ +/* +$begin atomic_two_clear$$ +$spell + sq + alloc +$$ + +$section Free Static Variables$$ + +$head Syntax$$ +$codei%atomic_base<%Base%>::clear()%$$ + +$head Purpose$$ +Each $code atomic_base$$ objects holds onto work space in order to +avoid repeated memory allocation calls and thereby increase speed +(until it is deleted). +If an the $code atomic_base$$ object is global or static because, +the it does not get deleted. +This is a problem when using +$code thread_alloc$$ $cref/free_all/ta_free_all/$$ +to check that all allocated memory has been freed. +Calling this $code clear$$ function will free all the +memory currently being held onto by the +$codei%atomic_base<%Base%>%$$ class. + +$head Future Use$$ +If there is future use of an $code atomic_base$$ object, +after a call to $code clear$$, +the work space will be reallocated and held onto. + +$head Restriction$$ +This routine cannot be called +while in $cref/parallel/ta_in_parallel/$$ execution mode. + +$end +------------------------------------------------------------------------------ +*/ + +namespace CppAD { // BEGIN_CPPAD_NAMESPACE +/*! +\file atomic/two_clear.hpp +Free static variables in atomic_base class. +*/ +/*! +Free all thread_alloc static memory held by atomic_base (avoids reallocations). +(This does not include class_object() which is an std::vector.) +*/ +template +void atomic_base::clear(void) +{ CPPAD_ASSERT_KNOWN( + ! thread_alloc::in_parallel() , + "cannot use atomic_base clear during parallel execution" + ); + bool set_null = true; + size_t index = 0; + size_t type = 0; // set to avoid warning + std::string* name = nullptr; + void* v_ptr = nullptr; // set to avoid warning + size_t n_atomic = local::atomic_index( + set_null, index, type, name, v_ptr + ); + // + set_null = false; + for(index = 1; index <= n_atomic; ++index) + { local::atomic_index(set_null, index, type, name, v_ptr); + if( type == 2 ) + { atomic_base* op = reinterpret_cast(v_ptr); + if( op != nullptr ) + { for(size_t thread = 0; thread < CPPAD_MAX_NUM_THREADS; thread++) + op->free_work(thread); + } + } + } + return; +} + +} // END_CPPAD_NAMESPACE +# endif diff --git a/build-config/cppad/include/cppad/core/atomic/two_ctor.hpp b/build-config/cppad/include/cppad/core/atomic/two_ctor.hpp new file mode 100644 index 00000000..c8f24801 --- /dev/null +++ b/build-config/cppad/include/cppad/core/atomic/two_ctor.hpp @@ -0,0 +1,173 @@ +# ifndef CPPAD_CORE_ATOMIC_TWO_CTOR_HPP +# define CPPAD_CORE_ATOMIC_TWO_CTOR_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ +/* +$begin atomic_two_ctor$$ +$spell + enum + sq + std + afun + arg + CppAD + bool + ctor + const + mat_mul_xam.cpp + hpp +$$ + +$section Atomic Function Constructor$$ + +$head Syntax$$ +$icode%atomic_user afun%(%ctor_arg_list%) +%$$ +$codei%atomic_base<%Base%>(%name%, %sparsity%) +%$$ + +$head atomic_user$$ + +$subhead ctor_arg_list$$ +Is a list of arguments for the $icode atomic_user$$ constructor. + +$subhead afun$$ +The object $icode afun$$ must stay in scope for as long +as the corresponding atomic function is used. +This includes use by any $cref/ADFun/ADFun/$$ that +has this $icode atomic_user$$ operation in its +$cref/operation sequence/glossary/Operation/Sequence/$$. + +$subhead Implementation$$ +The user defined $icode atomic_user$$ class is a publicly derived class of +$codei%atomic_base<%Base%>%$$. +It should be declared as follows: +$codei% + class %atomic_user% : public CppAD::atomic_base<%Base%> { + public: + %atomic_user%(%ctor_arg_list%) : atomic_base<%Base%>(%name%, %sparsity%) + %...% + }; +%$$ +where $icode ...$$ +denotes the rest of the implementation of the derived class. +This includes completing the constructor and +all the virtual functions that have their +$code atomic_base$$ implementations replaced by +$icode atomic_user$$ implementations. + +$head atomic_base$$ + +$subhead Restrictions$$ +The $code atomic_base$$ constructor and destructor cannot be called in +$cref/parallel/ta_in_parallel/$$ mode. + +$subhead Base$$ +The template parameter determines the +$icode Base$$ type for this $codei%AD<%Base%>%$$ atomic operation. + +$subhead name$$ +This $code atomic_base$$ constructor argument has the following prototype +$codei% + const std::string& %name% +%$$ +It is the name for this atomic function and is used for error reporting. +The suggested value for $icode name$$ is $icode afun$$ or $icode atomic_user$$, +i.e., the name of the corresponding atomic object or class. + +$subhead sparsity$$ +This $code atomic_base$$ constructor argument has prototype +$codei% + atomic_base<%Base%>::option_enum %sparsity% +%$$ +The current $icode sparsity$$ for an $code atomic_base$$ object +determines which type of sparsity patterns it uses +and its value is one of the following: +$table +$icode sparsity$$ $cnext sparsity patterns $rnext +$codei%atomic_base<%Base%>::pack_sparsity_enum%$$ $pre $$ $cnext + $cref/vectorBool/CppAD_vector/vectorBool/$$ +$rnext +$codei%atomic_base<%Base%>::bool_sparsity_enum%$$ $pre $$ $cnext + $cref/vector/CppAD_vector/$$$code $$ +$rnext +$codei%atomic_base<%Base%>::set_sparsity_enum%$$ $pre $$ $cnext + $cref/vector/CppAD_vector/$$$code >$$ +$tend +There is a default value for $icode sparsity$$ if it is not +included in the constructor (which may be either the bool or set option). + +$end +------------------------------------------------------------------------------- +*/ + +namespace CppAD { // BEGIN_CPPAD_NAMESPACE +/*! +\file atomic/two_ctor.hpp +Constructors for atomic_base class. +*/ + +/*! +Base class for atomic_atomic functions. + +\tparam Base +This class is used for defining an AD atomic operation y = f(x). + +\par +make sure user does not invoke the default constructor +*/ +template +atomic_base::atomic_base(void) +{ CPPAD_ASSERT_KNOWN(false, + "Attempt to use the atomic_base default constructor" + ); +} +/*! +Constructor + +\param name +name used for error reporting + +\param sparsity [in] +what type of sparsity patterns are computed by this function, +bool_sparsity_enum or set_sparsity_enum. Default value is +bool sparsity patterns. +*/ +template +atomic_base::atomic_base( + const std::string& name, + option_enum sparsity +) : +sparsity_( sparsity ) +{ CPPAD_ASSERT_KNOWN( + ! thread_alloc::in_parallel() , + "atomic_base: constructor cannot be called in parallel mode." + ); + CPPAD_ASSERT_UNKNOWN( constant_enum < dynamic_enum ); + CPPAD_ASSERT_UNKNOWN( dynamic_enum < variable_enum ); + // + // atomic_index + bool set_null = false; + size_t index = 0; + size_t type = 2; + std::string copy_name = name; + void* copy_this = reinterpret_cast( this ); + index_ = local::atomic_index( + set_null, index, type, ©_name, copy_this + ); + // initialize work pointers as null; + for(size_t thread = 0; thread < CPPAD_MAX_NUM_THREADS; thread++) + work_[thread] = nullptr; +} + +} // END_CPPAD_NAMESPACE +# endif diff --git a/build-config/cppad/include/cppad/core/atomic/two_for_sparse_hes.hpp b/build-config/cppad/include/cppad/core/atomic/two_for_sparse_hes.hpp new file mode 100644 index 00000000..e0f1ed40 --- /dev/null +++ b/build-config/cppad/include/cppad/core/atomic/two_for_sparse_hes.hpp @@ -0,0 +1,356 @@ +# ifndef CPPAD_CORE_ATOMIC_TWO_FOR_SPARSE_HES_HPP +# define CPPAD_CORE_ATOMIC_TWO_FOR_SPARSE_HES_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ +/* +$begin atomic_two_for_sparse_hes$$ +$spell + sq + mul.hpp + vx + afun + Jacobian + jac + CppAD + std + bool + hes + const +$$ + +$section Atomic Forward Hessian Sparsity Patterns$$ + +$head Syntax$$ +$icode%ok% = %afun%.for_sparse_hes(%vx%, %r%, %s%, %h%, %x%)%$$ + +$head Deprecated 2016-06-27$$ +$icode%ok% = %afun%.for_sparse_hes(%vx%, %r%, %s%, %h%)%$$ + +$head Purpose$$ +This function is used by $cref ForSparseHes$$ to compute +Hessian sparsity patterns. +If you are using $cref ForSparseHes$$, +one of the versions of this +virtual function must be defined by the +$cref/atomic_user/atomic_two_ctor/atomic_user/$$ class. +$pre + +$$ +Given a $cref/sparsity pattern/glossary/Sparsity Pattern/$$ for +a diagonal matrix $latex R \in \B{R}^{n \times n}$$, and +a row vector $latex S \in \B{R}^{1 \times m}$$, +this routine computes the sparsity pattern for +$latex \[ + H(x) = R^\R{T} \cdot (S \cdot f)^{(2)}( x ) \cdot R +\] $$ + +$head Implementation$$ +If you are using and $cref ForSparseHes$$, +this virtual function must be defined by the +$cref/atomic_user/atomic_two_ctor/atomic_user/$$ class. + +$subhead vx$$ +The argument $icode vx$$ has prototype +$codei% + const CppAD:vector& %vx% +%$$ +$icode%vx%.size() == %n%$$, and +for $latex j = 0 , \ldots , n-1$$, +$icode%vx%[%j%]%$$ is true if and only if +$icode%ax%[%j%]%$$ is a $cref/variable/glossary/Variable/$$ +or $cref/dynamic parameter/glossary/Parameter/Dynamic/$$ +in the corresponding call to +$codei% + %afun%(%ax%, %ay%) +%$$ + +$subhead r$$ +This argument has prototype +$codei% + const CppAD:vector& %r% +%$$ +and is a $cref/atomic_sparsity/atomic_two_option/atomic_sparsity/$$ pattern for +the diagonal of $latex R \in \B{R}^{n \times n}$$. + +$subhead s$$ +The argument $icode s$$ has prototype +$codei% + const CppAD:vector& %s% +%$$ +and its size is $icode m$$. +It is a sparsity pattern for $latex S \in \B{R}^{1 \times m}$$. + +$subhead h$$ +This argument has prototype +$codei% + %atomic_sparsity%& %h% +%$$ +The input value of its elements +are not specified (must not matter). +Upon return, $icode h$$ is a +$cref/atomic_sparsity/atomic_two_option/atomic_sparsity/$$ pattern for +$latex H(x) \in \B{R}^{n \times n}$$ which is defined above. + +$subhead x$$ +$index deprecated$$ +The argument has prototype +$codei% + const CppAD::vector<%Base%>& %x% +%$$ +and size is equal to the $icode n$$. +This is the $cref Value$$ value corresponding to the parameters in the +vector $cref/ax/atomic_two_afun/ax/$$ (when the atomic function was called). +To be specific, if +$codei% + if( Parameter(%ax%[%i%]) == true ) + %x%[%i%] = Value( %ax%[%i%] ); + else + %x%[%i%] = CppAD::numeric_limits<%Base%>::quiet_NaN(); +%$$ +The version of this function with out the $icode x$$ argument is deprecated; +i.e., you should include the argument even if you do not use it. + +$end +----------------------------------------------------------------------------- +*/ + +namespace CppAD { // BEGIN_CPPAD_NAMESPACE +/*! +\file atomic/two_for_sparse_hes.hpp +Atomic forward mode Hessian sparsity patterns. +*/ +/*! +Link, after case split, from for_hes_sweep to atomic_base. + +\param vx [in] +which componens of x are variables. + +\param r [in] +is the forward Jacobian sparsity pattern w.r.t the argument vector x. + +\param s [in] +is the reverse Jacobian sparsity pattern w.r.t the result vector y. + +\param h [out] +is the Hessian sparsity pattern w.r.t the argument vector x. + +\param x +is the integer value of the x arguments that are parameters. +*/ +template +bool atomic_base::for_sparse_hes( + const vector& vx , + const vector& r , + const vector& s , + vector< std::set >& h , + const vector& x ) +{ return false; } +template +bool atomic_base::for_sparse_hes( + const vector& vx , + const vector& r , + const vector& s , + vector& h , + const vector& x ) +{ return false; } +template +bool atomic_base::for_sparse_hes( + const vector& vx , + const vector& r , + const vector& s , + vectorBool& h , + const vector& x ) +// deprecated versions +{ return false; } +template +bool atomic_base::for_sparse_hes( + const vector& vx , + const vector& r , + const vector& s , + vector< std::set >& h ) +{ return false; } +template +bool atomic_base::for_sparse_hes( + const vector& vx , + const vector& r , + const vector& s , + vector& h ) +{ return false; } +template +bool atomic_base::for_sparse_hes( + const vector& vx , + const vector& r , + const vector& s , + vectorBool& h ) +{ return false; } +/*! +Link, before case split, from for_hes_sweep to atomic_base. +2DO: move this functiton outside this file so can change +developer documentation to omhelp formating. + +\tparam InternalSparsity +Is the used internaly for sparsity calculations; i.e., +sparse_pack or sparse_list. + +\param x +is parameter arguments to the function, other components are nan. + +\param x_index +is the variable index, on the tape, for the arguments to this function. +This size of x_index is n, the number of arguments to this function. + +\param y_index +is the variable index, on the tape, for the results for this function. +This size of y_index is m, the number of results for this function. + +\param for_jac_sparsity +On input, for j = 0, ... , n-1, the sparsity pattern with index x_index[j], +is the forward Jacobian sparsity for the j-th argument to this atomic function. + +\param rev_jac_sparsity +On input, for i = 0, ... , m-1, the sparsity pattern with index y_index[i], +is the reverse Jacobian sparsity for the i-th result to this atomic function. +This shows which components of the result affect the function we are +computing the Hessian of. + +\param for_hes_sparsity +This is the sparsity pattern for the Hessian. On input, the non-linear +terms in the atomic fuction have not been included. Upon return, they +have been included. +*/ +template +template +bool atomic_base::for_sparse_hes( + const vector& x , + const local::pod_vector& x_index , + const local::pod_vector& y_index , + size_t np1 , + size_t numvar , + const InternalSparsity& rev_jac_sparsity , + InternalSparsity& for_sparsity ) +{ typedef typename InternalSparsity::const_iterator const_iterator; + CPPAD_ASSERT_UNKNOWN( rev_jac_sparsity.end() == 1 ); + CPPAD_ASSERT_UNKNOWN( for_sparsity.end() == np1 ); + CPPAD_ASSERT_UNKNOWN( for_sparsity.n_set() == np1 + numvar ); + size_t n = x_index.size(); + size_t m = y_index.size(); + bool ok = false; + size_t thread = thread_alloc::thread_num(); + allocate_work(thread); + // + // vx + vector vx(n); + for(size_t j = 0; j < n; j++) + vx[j] = x_index[j] != 0; + // + // bool_r + vector& bool_r( work_[thread]->bool_r ); + bool_r.resize(n); + for(size_t j = 0; j < n; j++) + { // check if we must compute row and column j of h + const_iterator itr(for_sparsity, np1 + x_index[j]); + size_t i = *itr; + bool_r[j] = i < np1; + } + // + // bool s + vector& bool_s( work_[thread]->bool_s ); + bool_s.resize(m); + for(size_t i = 0; i < m; i++) + { // check if row i of result is included in h + bool_s[i] = rev_jac_sparsity.is_element(y_index[i], 0); + } + // + // h + vectorBool& pack_h( work_[thread]->pack_h ); + vector& bool_h( work_[thread]->bool_h ); + vector< std::set >& set_h( work_[thread]->set_h ); + // + // call user's version of atomic function + std::string msg = ": atomic_base.for_sparse_hes: returned false"; + if( sparsity_ == pack_sparsity_enum ) + { pack_h.resize(n * n); + ok = for_sparse_hes(vx, bool_r, bool_s, pack_h, x); + if( ! ok ) + ok = for_sparse_hes(vx, bool_r, bool_s, pack_h); + if( ! ok ) + { msg = atomic_name() + msg + " sparsity = pack_sparsity_enum"; + CPPAD_ASSERT_KNOWN(false, msg.c_str()); + } + } + else if( sparsity_ == bool_sparsity_enum ) + { bool_h.resize(n * n); + ok = for_sparse_hes(vx, bool_r, bool_s, bool_h, x); + if( ! ok ) + ok = for_sparse_hes(vx, bool_r, bool_s, bool_h); + if( ! ok ) + { msg = atomic_name() + msg + " sparsity = bool_sparsity_enum"; + CPPAD_ASSERT_KNOWN(false, msg.c_str()); + } + } + else + { CPPAD_ASSERT_UNKNOWN( sparsity_ == set_sparsity_enum ) + set_h.resize(n); + ok = for_sparse_hes(vx, bool_r, bool_s, set_h, x); + if( ! ok ) + ok = for_sparse_hes(vx, bool_r, bool_s, set_h); + if( ! ok ) + { msg = atomic_name() + msg + " sparsity = set_sparsity_enum"; + CPPAD_ASSERT_KNOWN(false, msg.c_str()); + } + } + CPPAD_ASSERT_UNKNOWN( ok ); + // + // modify hessian in calling routine + for(size_t i = 0; i < n; i++) + { for(size_t j = 0; j < n; j++) + { if( (x_index[i] > 0) & (x_index[j] > 0) ) + { bool flag = false; + switch( sparsity_ ) + { case pack_sparsity_enum: + flag = pack_h[i * n + j]; + break; + // + case bool_sparsity_enum: + flag = bool_h[i * n + j]; + break; + // + case set_sparsity_enum: + flag = set_h[i].find(j) != set_h[i].end(); + break; + } + if( flag ) + { const_iterator itr_i(for_sparsity, np1 + x_index[i]); + size_t i_x = *itr_i; + while( i_x < np1 ) + { for_sparsity.binary_union( + i_x, i_x, np1 + x_index[j], for_sparsity + ); + i_x = *(++itr_i); + } + const_iterator itr_j(for_sparsity, np1 + x_index[j]); + size_t j_x = *itr_j; + while( j_x < np1 ) + { for_sparsity.binary_union( + j_x, j_x, np1 + x_index[i], for_sparsity + ); + j_x = *(++itr_j); + } + } + } + } + } + return ok; +} + +} // END_CPPAD_NAMESPACE +# endif diff --git a/build-config/cppad/include/cppad/core/atomic/two_for_sparse_jac.hpp b/build-config/cppad/include/cppad/core/atomic/two_for_sparse_jac.hpp new file mode 100644 index 00000000..62fa426f --- /dev/null +++ b/build-config/cppad/include/cppad/core/atomic/two_for_sparse_jac.hpp @@ -0,0 +1,283 @@ +# ifndef CPPAD_CORE_ATOMIC_TWO_FOR_SPARSE_JAC_HPP +# define CPPAD_CORE_ATOMIC_TWO_FOR_SPARSE_JAC_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ +/* +$begin atomic_two_for_sparse_jac$$ +$spell + sq + mul.hpp + afun + Jacobian + jac + const + CppAD + std + bool + std +$$ + +$section Atomic Forward Jacobian Sparsity Patterns$$ + +$head Syntax$$ +$icode%ok% = %afun%.for_sparse_jac(%q%, %r%, %s%, %x%) +%$$ + +$head Deprecated 2016-06-27$$ +$icode%ok% = %afun%.for_sparse_jac(%q%, %r%, %s%) +%$$ + +$head Purpose$$ +This function is used by $cref ForSparseJac$$ to compute +Jacobian sparsity patterns. +For a fixed matrix $latex R \in \B{R}^{n \times q}$$, +the Jacobian of $latex f( x + R * u)$$ with respect to $latex u \in \B{R}^q$$ is +$latex \[ + S(x) = f^{(1)} (x) * R +\] $$ +Given a $cref/sparsity pattern/glossary/Sparsity Pattern/$$ for $latex R$$, +$code for_sparse_jac$$ computes a sparsity pattern for $latex S(x)$$. + +$head Implementation$$ +If you are using +$cref ForSparseJac$$, +$cref ForSparseHes$$, or +$cref RevSparseHes$$, +one of the versions of this +virtual function must be defined by the +$cref/atomic_user/atomic_two_ctor/atomic_user/$$ class. + +$subhead q$$ +The argument $icode q$$ has prototype +$codei% + size_t %q% +%$$ +It specifies the number of columns in +$latex R \in \B{R}^{n \times q}$$ and the Jacobian +$latex S(x) \in \B{R}^{m \times q}$$. + +$subhead r$$ +This argument has prototype +$codei% + const %atomic_sparsity%& %r% +%$$ +and is a $cref/atomic_sparsity/atomic_two_option/atomic_sparsity/$$ pattern for +$latex R \in \B{R}^{n \times q}$$. + +$subhead s$$ +This argument has prototype +$codei% + %atomic_sparsity%& %s% +%$$ +The input values of its elements +are not specified (must not matter). +Upon return, $icode s$$ is a +$cref/atomic_sparsity/atomic_two_option/atomic_sparsity/$$ pattern for +$latex S(x) \in \B{R}^{m \times q}$$. + +$subhead x$$ +$index deprecated$$ +The argument has prototype +$codei% + const CppAD::vector<%Base%>& %x% +%$$ +and size is equal to the $icode n$$. +This is the $cref Value$$ value corresponding to the parameters in the +vector $cref/ax/atomic_two_afun/ax/$$ (when the atomic function was called). +To be specific, if +$codei% + if( Parameter(%ax%[%i%]) == true ) + %x%[%i%] = Value( %ax%[%i%] ); + else + %x%[%i%] = CppAD::numeric_limits<%Base%>::quiet_NaN(); +%$$ +The version of this function with out the $icode x$$ argument is deprecated; +i.e., you should include the argument even if you do not use it. + +$head ok$$ +The return value $icode ok$$ has prototype +$codei% + bool %ok% +%$$ +If it is $code true$$, the corresponding evaluation succeeded, +otherwise it failed. + +$end +----------------------------------------------------------------------------- +*/ + +namespace CppAD { // BEGIN_CPPAD_NAMESPACE +/*! +\file atomic/two_for_sparse_jac.hpp +Atomic forward Jacobian sparsity pattern. +*/ +/*! +Link, after case split, from for_jac_sweep to atomic_base. + +\param q +is the column dimension for the Jacobian sparsity partterns. + +\param r +is the Jacobian sparsity pattern for the argument vector x + +\param s +is the Jacobian sparsity pattern for the result vector y + +\param x +is the integer value for x arguments that are parameters. +*/ +template +bool atomic_base::for_sparse_jac( + size_t q , + const vector< std::set >& r , + vector< std::set >& s , + const vector& x ) +{ return false; } +template +bool atomic_base::for_sparse_jac( + size_t q , + const vector& r , + vector& s , + const vector& x ) +{ return false; } +template +bool atomic_base::for_sparse_jac( + size_t q , + const vectorBool& r , + vectorBool& s , + const vector& x ) +{ return false; } +// deprecated versions +template +bool atomic_base::for_sparse_jac( + size_t q , + const vector< std::set >& r , + vector< std::set >& s ) +{ return false; } +template +bool atomic_base::for_sparse_jac( + size_t q , + const vector& r , + vector& s ) +{ return false; } +template +bool atomic_base::for_sparse_jac( + size_t q , + const vectorBool& r , + vectorBool& s ) +{ return false; } + +/*! +Link, before case split, from for_jac_sweep to atomic_base. + +\tparam InternalSparsity +Is the type used for internal sparsity calculations; i.e., +sparse_pack or sparse_list. + +\param x +is parameter arguments to the function, other components are nan. + +\param x_index +is the variable index, on the tape, for the arguments to this function. +This size of x_index is n, the number of arguments to this function. + +\param y_index +is the variable index, on the tape, for the results for this function. +This size of y_index is m, the number of results for this function. + +\param var_sparsity +On input, for j = 0, ... , n-1, the sparsity pattern with index x_index[j], +is the sparsity for the j-th argument to this atomic function. +On output, for i = 0, ... , m-1, the sparsity pattern with index y_index[i], +is the sparsity for the i-th result for this atomic function. +*/ +template +template +bool atomic_base::for_sparse_jac( + const vector& x , + const local::pod_vector& x_index , + const local::pod_vector& y_index , + InternalSparsity& var_sparsity ) +{ + // intial results are empty during forward mode + size_t q = var_sparsity.end(); + bool input_empty = true; + bool zero_empty = true; + bool transpose = false; + size_t m = y_index.size(); + bool ok = false; + size_t thread = thread_alloc::thread_num(); + allocate_work(thread); + // + std::string msg = ": atomic_base.for_sparse_jac: returned false"; + if( sparsity_ == pack_sparsity_enum ) + { vectorBool& pack_r ( work_[thread]->pack_r ); + vectorBool& pack_s ( work_[thread]->pack_s ); + local::sparse::get_internal_pattern( + transpose, x_index, var_sparsity, pack_r + ); + // + pack_s.resize(m * q ); + ok = for_sparse_jac(q, pack_r, pack_s, x); + if( ! ok ) + ok = for_sparse_jac(q, pack_r, pack_s); + if( ! ok ) + { msg = atomic_name() + msg + " sparsity = pack_sparsity_enum"; + CPPAD_ASSERT_KNOWN(false, msg.c_str()); + } + local::sparse::set_internal_pattern(zero_empty, input_empty, + transpose, y_index, var_sparsity, pack_s + ); + } + else if( sparsity_ == bool_sparsity_enum ) + { vector& bool_r ( work_[thread]->bool_r ); + vector& bool_s ( work_[thread]->bool_s ); + local::sparse::get_internal_pattern( + transpose, x_index, var_sparsity, bool_r + ); + bool_s.resize(m * q ); + ok = for_sparse_jac(q, bool_r, bool_s, x); + if( ! ok ) + ok = for_sparse_jac(q, bool_r, bool_s); + if( ! ok ) + { msg = atomic_name() + msg + " sparsity = bool_sparsity_enum"; + CPPAD_ASSERT_KNOWN(false, msg.c_str()); + } + local::sparse::set_internal_pattern(zero_empty, input_empty, + transpose, y_index, var_sparsity, bool_s + ); + } + else + { CPPAD_ASSERT_UNKNOWN( sparsity_ == set_sparsity_enum ); + vector< std::set >& set_r ( work_[thread]->set_r ); + vector< std::set >& set_s ( work_[thread]->set_s ); + local::sparse::get_internal_pattern( + transpose, x_index, var_sparsity, set_r + ); + // + set_s.resize(m); + ok = for_sparse_jac(q, set_r, set_s, x); + if( ! ok ) + ok = for_sparse_jac(q, set_r, set_s); + if( ! ok ) + { msg = atomic_name() + msg + " sparsity = set_sparsity_enum"; + CPPAD_ASSERT_KNOWN(false, msg.c_str()); + } + local::sparse::set_internal_pattern(zero_empty, input_empty, + transpose, y_index, var_sparsity, set_s + ); + } + return ok; +} + +} // END_CPPAD_NAMESPACE +# endif diff --git a/build-config/cppad/include/cppad/core/atomic/two_forward.hpp b/build-config/cppad/include/cppad/core/atomic/two_forward.hpp new file mode 100644 index 00000000..0b4ed9c2 --- /dev/null +++ b/build-config/cppad/include/cppad/core/atomic/two_forward.hpp @@ -0,0 +1,402 @@ +# ifndef CPPAD_CORE_ATOMIC_TWO_FORWARD_HPP +# define CPPAD_CORE_ATOMIC_TWO_FORWARD_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-18 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ +/* +$begin atomic_two_forward$$ +$spell + sq + mul.hpp + hes + afun + vx + vy + ty + Taylor + const + CppAD + bool + atx + aty + af +$$ + +$section Atomic Forward Mode$$ + + +$head Syntax$$ + +$subhead Base$$ +$icode%ok% = %afun%.forward(%p%, %q%, %vx%, %vy%, %tx%, %ty%) +%$$ +This syntax is used by $icode%f%.Forward%$$ where $icode f$$ has prototype +$codei% + ADFun<%Base%> %f% +%$$ +and $icode afun$$ is used in $icode f$$. + +$subhead AD$$ +$icode%ok% = %afun%.forward(%p%, %q%, %vx%, %vy%, %atx%, %aty%) +%$$ +This syntax is used by $icode%af%.Forward%$$ where $icode af$$ has prototype +$codei% + ADFun< AD<%Base%> , %Base% > %af% +%$$ +and $icode afun$$ is used in $icode af$$ (see $cref base2ad$$). + +$head Purpose$$ +This virtual function is used by $cref atomic_two_afun$$ +to evaluate function values. +It is also used buy +$cref/f.Forward/Forward/$$ (and $icode%af%.Forward%$$) +to compute function vales and derivatives. + +$head Implementation$$ +This virtual function must be defined by the +$cref/atomic_user/atomic_two_ctor/atomic_user/$$ class. +It can just return $icode%ok% == false%$$ +(and not compute anything) for values +of $icode%q% > 0%$$ that are greater than those used by your +$cref/forward/Forward/$$ mode calculations. + +$head p$$ +The argument $icode p$$ has prototype +$codei% + size_t %p% +%$$ +It specifies the lowest order Taylor coefficient that we are evaluating. +During calls to $cref atomic_two_afun$$, $icode%p% == 0%$$. + +$head q$$ +The argument $icode q$$ has prototype +$codei% + size_t %q% +%$$ +It specifies the highest order Taylor coefficient that we are evaluating. +During calls to $cref atomic_two_afun$$, $icode%q% == 0%$$. + +$head vx$$ +The $code forward$$ argument $icode vx$$ has prototype +$codei% + const CppAD::vector& %vx% +%$$ +The case $icode%vx%.size() > 0%$$ only occurs while evaluating a call to +$cref atomic_two_afun$$. +In this case, +$icode%p% == %q% == 0%$$, +$icode%vx%.size() == %n%$$, and +for $latex j = 0 , \ldots , n-1$$, +$icode%vx%[%j%]%$$ is true if and only if +$icode%ax%[%j%]%$$ is a $cref/variable/glossary/Variable/$$ +or $cref/dynamic parameter/glossary/Parameter/Dynamic/$$ +in the corresponding call to +$codei% + %afun%(%ax%, %ay%) +%$$ +If $icode%vx%.size() == 0%$$, +then $icode%vy%.size() == 0%$$ and neither of these vectors +should be used. + +$head vy$$ +The $code forward$$ argument $icode vy$$ has prototype +$codei% + CppAD::vector& %vy% +%$$ +If $icode%vy%.size() == 0%$$, it should not be used. +Otherwise, +$icode%q% == 0%$$ and $icode%vy%.size() == %m%$$. +The input values of the elements of $icode vy$$ +are not specified (must not matter). +Upon return, for $latex j = 0 , \ldots , m-1$$, +$icode%vy%[%i%]%$$ is true if and only if +$icode%ay%[%i%]%$$ is a variable +or dynamic parameter +(CppAD uses $icode vy$$ to reduce the necessary computations). + +$head tx$$ +The argument $icode tx$$ has prototype +$codei% + const CppAD::vector<%Base%>& %tx% +%$$ +and $icode%tx%.size() == (%q%+1)*%n%$$. +It is used by $icode%f%.Forward%$$ where $icode f$$ has type +$codei%ADFun<%Base%> %f%$$ and $icode afun$$ is used in $icode f$$. +For $latex j = 0 , \ldots , n-1$$ and $latex k = 0 , \ldots , q$$, +we use the Taylor coefficient notation +$latex \[ +\begin{array}{rcl} + x_j^k & = & tx [ j * ( q + 1 ) + k ] + \\ + X_j (t) & = & x_j^0 + x_j^1 t^1 + \cdots + x_j^q t^q +\end{array} +\] $$ +Note that superscripts represent an index for $latex x_j^k$$ +and an exponent for $latex t^k$$. +Also note that the Taylor coefficients for $latex X(t)$$ correspond +to the derivatives of $latex X(t)$$ at $latex t = 0$$ in the following way: +$latex \[ + x_j^k = \frac{1}{ k ! } X_j^{(k)} (0) +\] $$ + +$head atx$$ +The argument $icode atx$$ has prototype +$codei% + const CppAD::vector< AD<%Base%> >& %atx% +%$$ +Otherwise, $icode atx$$ specifications are the same as for $icode tx$$. + +$head ty$$ +The argument $icode ty$$ has prototype +$codei% + CppAD::vector<%Base%>& %ty% +%$$ +and $icode%tx%.size() == (%q%+1)*%m%$$. +It is set by $icode%f%.Forward%$$ where $icode f$$ has type +$codei%ADFun<%Base%> %f%$$ and $icode afun$$ is used in $icode f$$. +Upon return, +For $latex i = 0 , \ldots , m-1$$ and $latex k = 0 , \ldots , q$$, +$latex \[ +\begin{array}{rcl} + Y_i (t) & = & f_i [ X(t) ] + \\ + Y_i (t) & = & y_i^0 + y_i^1 t^1 + \cdots + y_i^q t^q + o ( t^q ) + \\ + ty [ i * ( q + 1 ) + k ] & = & y_i^k +\end{array} +\] $$ +where $latex o( t^q ) / t^q \rightarrow 0$$ as $latex t \rightarrow 0$$. +Note that superscripts represent an index for $latex y_j^k$$ +and an exponent for $latex t^k$$. +Also note that the Taylor coefficients for $latex Y(t)$$ correspond +to the derivatives of $latex Y(t)$$ at $latex t = 0$$ in the following way: +$latex \[ + y_j^k = \frac{1}{ k ! } Y_j^{(k)} (0) +\] $$ +If $latex p > 0$$, +for $latex i = 0 , \ldots , m-1$$ and $latex k = 0 , \ldots , p-1$$, +the input of $icode ty$$ satisfies +$latex \[ + ty [ i * ( q + 1 ) + k ] = y_i^k +\]$$ +and hence the corresponding elements need not be recalculated. + +$head aty$$ +The argument $icode aty$$ has prototype +$codei% + const CppAD::vector< AD<%Base%> >& %aty% +%$$ +Otherwise, $icode aty$$ specifications are the same as for $icode ty$$. + +$head ok$$ +If the required results are calculated, $icode ok$$ should be true. +Otherwise, it should be false. + +$head Discussion$$ +For example, suppose that $icode%q% == 2%$$, +and you know how to compute the function $latex f(x)$$, +its first derivative $latex f^{(1)} (x)$$, +and it component wise Hessian $latex f_i^{(2)} (x)$$. +Then you can compute $icode ty$$ using the following formulas: +$latex \[ +\begin{array}{rcl} +y_i^0 & = & Y(0) + = f_i ( x^0 ) +\\ +y_i^1 & = & Y^{(1)} ( 0 ) + = f_i^{(1)} ( x^0 ) X^{(1)} ( 0 ) + = f_i^{(1)} ( x^0 ) x^1 +\\ +y_i^2 +& = & \frac{1}{2 !} Y^{(2)} (0) +\\ +& = & \frac{1}{2} X^{(1)} (0)^\R{T} f_i^{(2)} ( x^0 ) X^{(1)} ( 0 ) + + \frac{1}{2} f_i^{(1)} ( x^0 ) X^{(2)} ( 0 ) +\\ +& = & \frac{1}{2} (x^1)^\R{T} f_i^{(2)} ( x^0 ) x^1 + + f_i^{(1)} ( x^0 ) x^2 +\end{array} +\] $$ +For $latex i = 0 , \ldots , m-1$$, and $latex k = 0 , 1 , 2$$, +$latex \[ + ty [ i * (q + 1) + k ] = y_i^k +\] $$ + +$end +----------------------------------------------------------------------------- +*/ + +namespace CppAD { // BEGIN_CPPAD_NAMESPACE +/*! +\file atomic/two_forward.hpp +Atomic forward mode +*/ +/*! +Link from atomic_base to forward mode (for replacement by derived class) + +\param p [in] +lowerest order for this forward mode calculation. + +\param q [in] +highest order for this forward mode calculation. + +\param vx [in] +if size not zero, which components of x are variables + +\param vy [out] +if size not zero, which components of y are variables + +\param tx [in] +Taylor coefficients corresponding to x for this calculation. + +\param ty [out] +Taylor coefficient corresponding to y for this calculation + +See the forward mode in user's documentation for atomic_two +*/ +template +bool atomic_base::forward( + size_t p , + size_t q , + const vector& vx , + vector& vy , + const vector& tx , + vector& ty ) +{ return false; } +/*! +Link from atomic_base to forward mode (for replacement by derived class) + +\param p [in] +lowerest order for this forward mode calculation. + +\param q [in] +highest order for this forward mode calculation. + +\param vx [in] +if size not zero, which components of x are variables + +\param vy [out] +if size not zero, which components of y are variables + +\param atx [in] +Taylor coefficients corresponding to x for this calculation. + +\param aty [out] +Taylor coefficient corresponding to y for this calculation + +See the forward mode in user's documentation for atomic_two +*/ +template +bool atomic_base::forward( + size_t p , + size_t q , + const vector& vx , + vector& vy , + const vector< AD >& atx , + vector< AD >& aty ) +{ return false; } +/*! +Convert atomic_three interface to atomic_two interface + +\param order_low [in] +lowerest order for this forward mode calculation. + +\param order_up [in] +highest order for this forward mode calculation. + +\param type_x [in] +if size not zero, which components of x are variables + +\param type_y [out] +if size not zero, which components of y are variables + +\param taylor_x [in] +Taylor coefficients corresponding to x for this calculation. + +\param taylor_y [out] +Taylor coefficient corresponding to y for this calculation + +See the forward mode in user's documentation for atomic_three +*/ +# define CPPAD_ATOMIC_BASE_MUSTDO 0 +template +bool atomic_base::forward( + size_t order_low , + size_t order_up , + const vector& type_x , + vector& type_y , + const vector& taylor_x , + vector& taylor_y ) +{ // + // atomic_base::afun(ax, ay) calls bool version directly + CPPAD_ASSERT_UNKNOWN( type_x.size() == 0 ); + CPPAD_ASSERT_UNKNOWN( type_y.size() == 0 ); + // +# if CPPAD_ATOMIC_BASE_MUSTDO + size_t thread = thread_alloc::thread_num(); + allocate_work(thread); + vector & vx = work_[thread]->vx; + vector & vy = work_[thread]->vy; + vx.resize(type_x.size()); + vy.resize(type_y.size()); +# else + vector vx, vy; +# endif + // + bool ok = forward(order_low, order_up, vx, vy, taylor_x, taylor_y); + // + return ok; +} +# undef CPPAD_ATOMIC_BASE_MUSTDO +/*! +Convert atomic_three interface to atomic_two interface + +\param order_low [in] +lowerest order for this forward mode calculation. + +\param order_up [in] +highest order for this forward mode calculation. + +\param type_x [in] +if size not zero, which components of x are variables + +\param type_y [out] +if size not zero, which components of y are variables + +\param ataylor_x [in] +Taylor coefficients corresponding to x for this calculation. + +\param ataylor_y [out] +Taylor coefficient corresponding to y for this calculation + +See the forward mode in user's documentation for atomic_three +*/ +template +bool atomic_base::forward( + size_t order_low , + size_t order_up , + const vector& type_x , + vector& type_y , + const vector< AD >& ataylor_x , + vector< AD >& ataylor_y ) +{ // + // atomic_base::afun(ax, ay) calls bool version directly + CPPAD_ASSERT_UNKNOWN( type_x.size() == 0 ); + CPPAD_ASSERT_UNKNOWN( type_y.size() == 0 ); + // + vector vx, vy; + bool ok = forward(order_low, order_up, vx, vy, ataylor_x, ataylor_y); + // + return ok; +} + +} // END_CPPAD_NAMESPACE +# endif diff --git a/build-config/cppad/include/cppad/core/atomic/two_option.hpp b/build-config/cppad/include/cppad/core/atomic/two_option.hpp new file mode 100644 index 00000000..5cb1990f --- /dev/null +++ b/build-config/cppad/include/cppad/core/atomic/two_option.hpp @@ -0,0 +1,113 @@ +# ifndef CPPAD_CORE_ATOMIC_TWO_OPTION_HPP +# define CPPAD_CORE_ATOMIC_TWO_OPTION_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-18 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ +/* +$begin atomic_two_option$$ +$spell + sq + enum + afun + bool + CppAD + std + typedef +$$ + +$section Set Atomic Function Options$$ + +$head Syntax$$ +$icode%afun%.option(%option_value%)%$$ + +$head Scope$$ +These settings do not apply to individual $icode afun$$ calls, +but rather all subsequent uses of the corresponding atomic operation +in an $cref ADFun$$ object. + +$head atomic_sparsity$$ +Note that, if you use $cref optimize$$, these sparsity patterns are used +to determine the $cref/dependency/dependency.cpp/$$ relationship between +argument and result variables. + +$subhead pack_sparsity_enum$$ +If $icode option_value$$ is $codei%atomic_base<%Base%>::pack_sparsity_enum%$$, +then the type used by $icode afun$$ for +$cref/sparsity patterns/glossary/Sparsity Pattern/$$, +(after the option is set) will be +$codei% + typedef CppAD::vectorBool %atomic_sparsity% +%$$ +If $icode r$$ is a sparsity pattern +for a matrix $latex R \in \B{R}^{p \times q}$$: +$icode%r%.size() == %p% * %q%$$. + +$subhead bool_sparsity_enum$$ +If $icode option_value$$ is $codei%atomic_base<%Base%>::bool_sparsity_enum%$$, +then the type used by $icode afun$$ for +$cref/sparsity patterns/glossary/Sparsity Pattern/$$, +(after the option is set) will be +$codei% + typedef CppAD::vector %atomic_sparsity% +%$$ +If $icode r$$ is a sparsity pattern +for a matrix $latex R \in \B{R}^{p \times q}$$: +$icode%r%.size() == %p% * %q%$$. + +$subhead set_sparsity_enum$$ +If $icode option_value$$ is $icode%atomic_base<%Base%>::set_sparsity_enum%$$, +then the type used by $icode afun$$ for +$cref/sparsity patterns/glossary/Sparsity Pattern/$$, +(after the option is set) will be +$codei% + typedef CppAD::vector< std::set > %atomic_sparsity% +%$$ +If $icode r$$ is a sparsity pattern +for a matrix $latex R \in \B{R}^{p \times q}$$: +$icode%r%.size() == %p%$$, and for $latex i = 0 , \ldots , p-1$$, +the elements of $icode%r%[%i%]%$$ are between zero and $latex q-1$$ inclusive. + +$end +------------------------------------------------------------------------------ +*/ + +namespace CppAD { // BEGIN_CPPAD_NAMESPACE +/*! +\file atomic/two_option.hpp +Setting atomic_base options. +*/ + +/*! +Setting atomic_base options. + +\param option_value +new option value. +*/ +template +void atomic_base::option(enum option_enum option_value) +{ switch( option_value ) + { case pack_sparsity_enum: + case bool_sparsity_enum: + case set_sparsity_enum: + sparsity_ = option_value; + break; + + default: + CPPAD_ASSERT_KNOWN( + false, + "atoic_base::option: option_value is not valid" + ); + } + return; +} + +} // END_CPPAD_NAMESPACE +# endif diff --git a/build-config/cppad/include/cppad/core/atomic/two_rev_depend.hpp b/build-config/cppad/include/cppad/core/atomic/two_rev_depend.hpp new file mode 100644 index 00000000..c6b02f2c --- /dev/null +++ b/build-config/cppad/include/cppad/core/atomic/two_rev_depend.hpp @@ -0,0 +1,99 @@ +# ifndef CPPAD_CORE_ATOMIC_TWO_REV_DEPEND_HPP +# define CPPAD_CORE_ATOMIC_TWO_REV_DEPEND_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-18 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ +namespace CppAD { // BEGIN_CPPAD_NAMESPACE +/*! +\file atomic/two_rev_depend.hpp +Third generation atomic type computation. +*/ +/*! +Link from atomic_two to reverse dependency calculation + +\param parameter_x [in] +is the value of the parameters in the corresponding function call +afun(ax, ay). + +\param type_x [in] +is the type for each component of ax in the corresponding function call +afun(ax, ay). + +\param depend_x [out] +specifies which components of x affect values of interest. + +\param depend_y [in] +specifies which components of y affect values of interest. +*/ +// BEGIN_PROTOTYPE +template +bool atomic_base::rev_depend( + const vector& parameter_x , + const vector& type_x , + vector& depend_x , + const vector& depend_y ) +// END_PROTOTYPE +{ bool ok = true; + CPPAD_ASSERT_UNKNOWN( depend_x.size() == parameter_x.size() ); + size_t n = depend_x.size(); + size_t m = depend_y.size(); + // + size_t thread = thread_alloc::thread_num(); + allocate_work(thread); + // + if( sparsity_ == pack_sparsity_enum ) + { vectorBool& rt ( work_[thread]->pack_r ); + vectorBool& st ( work_[thread]->pack_s ); + // + st.resize(n * 1 ); + rt.resize(m * 1 ); + for(size_t i = 0; i < m; ++i) + rt[i] = depend_y[i]; + ok = rev_sparse_jac(1, rt, st, parameter_x); + if( ! ok ) + ok = rev_sparse_jac(1, rt, st); + if( ! ok ) + return false; + for(size_t j = 0; j < n; ++j) + depend_x[j] = st[j]; + } + else if( sparsity_ == bool_sparsity_enum ) + { + ok = rev_sparse_jac(1, depend_y, depend_x, parameter_x); + if( ! ok ) + ok = rev_sparse_jac(m, depend_y, depend_x); + if( ! ok ) + return false; + } + else + { CPPAD_ASSERT_UNKNOWN( sparsity_ == set_sparsity_enum ); + vector< std::set >& rt ( work_[thread]->set_r ); + vector< std::set >& st ( work_[thread]->set_s ); + rt.resize(m); + st.resize(n); + for(size_t i = 0; i < m; ++i) + { if( depend_y[i] ) + rt[i].insert(0); + } + ok = rev_sparse_jac(m, rt, st, parameter_x); + if( ! ok ) + ok = rev_sparse_jac(m, rt, st); + if( ! ok ) + return false; + for(size_t j = 0; j < n; ++j) + depend_x[j] = ! st[j].empty(); + } + return ok; +} + +} // END_CPPAD_NAMESPACE + +# endif diff --git a/build-config/cppad/include/cppad/core/atomic/two_rev_sparse_hes.hpp b/build-config/cppad/include/cppad/core/atomic/two_rev_sparse_hes.hpp new file mode 100644 index 00000000..27ac3804 --- /dev/null +++ b/build-config/cppad/include/cppad/core/atomic/two_rev_sparse_hes.hpp @@ -0,0 +1,451 @@ +# ifndef CPPAD_CORE_ATOMIC_TWO_REV_SPARSE_HES_HPP +# define CPPAD_CORE_ATOMIC_TWO_REV_SPARSE_HES_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ +/* +$begin atomic_two_rev_sparse_hes$$ +$spell + sq + mul.hpp + vx + afun + Jacobian + jac + CppAD + std + bool + hes + const +$$ + +$section Atomic Reverse Hessian Sparsity Patterns$$ + +$head Syntax$$ +$icode%ok% = %afun%.rev_sparse_hes(%vx%, %s%, %t%, %q%, %r%, %u%, %v%, %x%)%$$ + +$head Deprecated 2016-06-27$$ +$icode%ok% = %afun%.rev_sparse_hes(%vx%, %s%, %t%, %q%, %r%, %u%, %v%)%$$ + +$head Purpose$$ +This function is used by $cref RevSparseHes$$ to compute +Hessian sparsity patterns. +If you are using $cref RevSparseHes$$ to compute +one of the versions of this +virtual function muse be defined by the +$cref/atomic_user/atomic_two_ctor/atomic_user/$$ class. +$pre + +$$ +There is an unspecified scalar valued function +$latex g : \B{R}^m \rightarrow \B{R}$$. +Given a $cref/sparsity pattern/glossary/Sparsity Pattern/$$ for +$latex R \in \B{R}^{n \times q}$$, +and information about the function $latex z = g(y)$$, +this routine computes the sparsity pattern for +$latex \[ + V(x) = (g \circ f)^{(2)}( x ) R +\] $$ + +$head Implementation$$ +If you are using and $cref RevSparseHes$$, +this virtual function must be defined by the +$cref/atomic_user/atomic_two_ctor/atomic_user/$$ class. + +$subhead vx$$ +The argument $icode vx$$ has prototype +$codei% + const CppAD:vector& %vx% +%$$ +$icode%vx%.size() == %n%$$, and +for $latex j = 0 , \ldots , n-1$$, +$icode%vx%[%j%]%$$ is true if and only if +$icode%ax%[%j%]%$$ is a $cref/variable/glossary/Variable/$$ +or $cref/dynamic parameter/glossary/Parameter/Dynamic/$$ +in the corresponding call to +$codei% + %afun%(%ax%, %ay%) +%$$ + +$subhead s$$ +The argument $icode s$$ has prototype +$codei% + const CppAD:vector& %s% +%$$ +and its size is $icode m$$. +It is a sparsity pattern for +$latex S(x) = g^{(1)} [ f(x) ] \in \B{R}^{1 \times m}$$. + +$subhead t$$ +This argument has prototype +$codei% + CppAD:vector& %t% +%$$ +and its size is $icode m$$. +The input values of its elements +are not specified (must not matter). +Upon return, $icode t$$ is a +sparsity pattern for +$latex T(x) \in \B{R}^{1 \times n}$$ where +$latex \[ + T(x) = (g \circ f)^{(1)} (x) = S(x) * f^{(1)} (x) +\]$$ + +$subhead q$$ +The argument $icode q$$ has prototype +$codei% + size_t %q% +%$$ +It specifies the number of columns in +$latex R \in \B{R}^{n \times q}$$, +$latex U(x) \in \B{R}^{m \times q}$$, and +$latex V(x) \in \B{R}^{n \times q}$$. + +$subhead r$$ +This argument has prototype +$codei% + const %atomic_sparsity%& %r% +%$$ +and is a $cref/atomic_sparsity/atomic_two_option/atomic_sparsity/$$ pattern for +$latex R \in \B{R}^{n \times q}$$. + +$head u$$ +This argument has prototype +$codei% + const %atomic_sparsity%& %u% +%$$ +and is a $cref/atomic_sparsity/atomic_two_option/atomic_sparsity/$$ pattern for +$latex U(x) \in \B{R}^{m \times q}$$ which is defined by +$latex \[ +\begin{array}{rcl} +U(x) +& = & +\{ \partial_u \{ \partial_y g[ y + f^{(1)} (x) R u ] \}_{y=f(x)} \}_{u=0} +\\ +& = & +\partial_u \{ g^{(1)} [ f(x) + f^{(1)} (x) R u ] \}_{u=0} +\\ +& = & +g^{(2)} [ f(x) ] f^{(1)} (x) R +\end{array} +\] $$ + +$subhead v$$ +This argument has prototype +$codei% + %atomic_sparsity%& %v% +%$$ +The input value of its elements +are not specified (must not matter). +Upon return, $icode v$$ is a +$cref/atomic_sparsity/atomic_two_option/atomic_sparsity/$$ pattern for +$latex V(x) \in \B{R}^{n \times q}$$ which is defined by +$latex \[ +\begin{array}{rcl} +V(x) +& = & +\partial_u [ \partial_x (g \circ f) ( x + R u ) ]_{u=0} +\\ +& = & +\partial_u [ (g \circ f)^{(1)}( x + R u ) ]_{u=0} +\\ +& = & +(g \circ f)^{(2)}( x ) R +\\ +& = & +f^{(1)} (x)^\R{T} g^{(2)} [ f(x) ] f^{(1)} (x) R ++ +\sum_{i=1}^m g_i^{(1)} [ f(x) ] \; f_i^{(2)} (x) R +\\ +& = & +f^{(1)} (x)^\R{T} U(x) ++ +\sum_{i=1}^m S_i (x) \; f_i^{(2)} (x) R +\end{array} +\] $$ + +$subhead x$$ +$index deprecated$$ +The argument has prototype +$codei% + const CppAD::vector<%Base%>& %x% +%$$ +and size is equal to the $icode n$$. +This is the $cref Value$$ value corresponding to the parameters in the +vector $cref/ax/atomic_two_afun/ax/$$ (when the atomic function was called). +To be specific, if +$codei% + if( Parameter(%ax%[%i%]) == true ) + %x%[%i%] = Value( %ax%[%i%] ); + else + %x%[%i%] = CppAD::numeric_limits<%Base%>::quiet_NaN(); +%$$ +The version of this function with out the $icode x$$ argument is deprecated; +i.e., you should include the argument even if you do not use it. + +$end +----------------------------------------------------------------------------- +*/ + +namespace CppAD { // BEGIN_CPPAD_NAMESPACE +/*! +\file atomic/two_rev_sparse_hes.hpp +Atomic reverse mode Hessian sparsity patterns. +*/ +/*! +Link from reverse Hessian sparsity sweep to atomic_base + +\param vx [in] +which componens of x are variables. + +\param s [in] +is the reverse Jacobian sparsity pattern w.r.t the result vector y. + +\param t [out] +is the reverse Jacobian sparsity pattern w.r.t the argument vector x. + +\param q [in] +is the column dimension for the sparsity partterns. + +\param r [in] +is the forward Jacobian sparsity pattern w.r.t the argument vector x + +\param u [in] +is the Hessian sparsity pattern w.r.t the result vector y. + +\param v [out] +is the Hessian sparsity pattern w.r.t the argument vector x. + +\param x [in] +is the integer value of the x arguments that are parameters. +*/ +template +bool atomic_base::rev_sparse_hes( + const vector& vx , + const vector& s , + vector& t , + size_t q , + const vector< std::set >& r , + const vector< std::set >& u , + vector< std::set >& v , + const vector& x ) +{ return false; } +template +bool atomic_base::rev_sparse_hes( + const vector& vx , + const vector& s , + vector& t , + size_t q , + const vector& r , + const vector& u , + vector& v , + const vector& x ) +{ return false; } +template +bool atomic_base::rev_sparse_hes( + const vector& vx , + const vector& s , + vector& t , + size_t q , + const vectorBool& r , + const vectorBool& u , + vectorBool& v , + const vector& x ) +{ return false; } +// deprecated +template +bool atomic_base::rev_sparse_hes( + const vector& vx , + const vector& s , + vector& t , + size_t q , + const vector< std::set >& r , + const vector< std::set >& u , + vector< std::set >& v ) +{ return false; } +template +bool atomic_base::rev_sparse_hes( + const vector& vx , + const vector& s , + vector& t , + size_t q , + const vector& r , + const vector& u , + vector& v ) +{ return false; } +template +bool atomic_base::rev_sparse_hes( + const vector& vx , + const vector& s , + vector& t , + size_t q , + const vectorBool& r , + const vectorBool& u , + vectorBool& v ) +{ return false; } +/*! +Link, before case split, from rev_hes_sweep to atomic_base. + +\tparam InternalSparsity +Is the used internaly for sparsity calculations; i.e., +sparse_pack or sparse_list. + +\param x +is parameter arguments to the function, other components are nan. + +\param x_index +is the variable index, on the tape, for the arguments to this function. +This size of x_index is n, the number of arguments to this function. + +\param y_index +is the variable index, on the tape, for the results for this function. +This size of y_index is m, the number of results for this function. + +\param for_jac_sparsity +On input, for j = 0, ... , n-1, the sparsity pattern with index x_index[j], +is the forward Jacobian sparsity for the j-th argument to this atomic function. + +\param rev_jac_flag +This shows which variables affect the function we are +computing the Hessian of. +On input, for i = 0, ... , m-1, the rev_jac_flag[ y_index[i] ] is true +if the Jacobian of function (we are computing sparsity for) is no-zero. +Upon return, for j = 0, ... , n-1, rev_jac_flag [ x_index[j] ] +as been adjusted to accound removing this atomic function. + +\param rev_hes_sparsity +This is the sparsity pattern for the Hessian. +On input, for i = 0, ... , m-1, row y_index[i] is the reverse Hessian sparsity +with one of the partials with respect to to y_index[i]. +*/ +template +template +bool atomic_base::rev_sparse_hes( + const vector& x , + const local::pod_vector& x_index , + const local::pod_vector& y_index , + const InternalSparsity& for_jac_sparsity , + bool* rev_jac_flag , + InternalSparsity& rev_hes_sparsity ) +{ CPPAD_ASSERT_UNKNOWN( for_jac_sparsity.end() == rev_hes_sparsity.end() ); + size_t q = rev_hes_sparsity.end(); + size_t n = x_index.size(); + size_t m = y_index.size(); + bool ok = false; + size_t thread = thread_alloc::thread_num(); + allocate_work(thread); + bool zero_empty = true; + bool input_empty = false; + bool transpose = false; + // + // vx + vector vx(n); + for(size_t j = 0; j < n; j++) + vx[j] = x_index[j] != 0; + // + // note that s and t are vectors so transpose does not matter for bool case + vector bool_s( work_[thread]->bool_s ); + vector bool_t( work_[thread]->bool_t ); + // + bool_s.resize(m); + bool_t.resize(n); + // + for(size_t i = 0; i < m; i++) + { if( y_index[i] > 0 ) + bool_s[i] = rev_jac_flag[ y_index[i] ]; + } + // + std::string msg = ": atomic_base.rev_sparse_hes: returned false"; + if( sparsity_ == pack_sparsity_enum ) + { vectorBool& pack_r( work_[thread]->pack_r ); + vectorBool& pack_u( work_[thread]->pack_u ); + vectorBool& pack_v( work_[thread]->pack_h ); + // + pack_v.resize(n * q); + // + local::sparse::get_internal_pattern( + transpose, x_index, for_jac_sparsity, pack_r + ); + local::sparse::get_internal_pattern( + transpose, y_index, rev_hes_sparsity, pack_u + ); + // + ok = rev_sparse_hes(vx, bool_s, bool_t, q, pack_r, pack_u, pack_v, x); + if( ! ok ) + ok = rev_sparse_hes(vx, bool_s, bool_t, q, pack_r, pack_u, pack_v); + if( ! ok ) + { msg = atomic_name() + msg + " sparsity = pack_sparsity_enum"; + CPPAD_ASSERT_KNOWN(false, msg.c_str()); + } + local::sparse::set_internal_pattern(zero_empty, input_empty, + transpose, x_index, rev_hes_sparsity, pack_v + ); + } + else if( sparsity_ == bool_sparsity_enum ) + { vector& bool_r( work_[thread]->bool_r ); + vector& bool_u( work_[thread]->bool_u ); + vector& bool_v( work_[thread]->bool_h ); + // + bool_v.resize(n * q); + // + local::sparse::get_internal_pattern( + transpose, x_index, for_jac_sparsity, bool_r + ); + local::sparse::get_internal_pattern( + transpose, y_index, rev_hes_sparsity, bool_u + ); + // + ok = rev_sparse_hes(vx, bool_s, bool_t, q, bool_r, bool_u, bool_v, x); + if( ! ok ) + ok = rev_sparse_hes(vx, bool_s, bool_t, q, bool_r, bool_u, bool_v); + if( ! ok ) + { msg = atomic_name() + msg + " sparsity = bool_sparsity_enum"; + CPPAD_ASSERT_KNOWN(false, msg.c_str()); + } + local::sparse::set_internal_pattern(zero_empty, input_empty, + transpose, x_index, rev_hes_sparsity, bool_v + ); + } + else + { CPPAD_ASSERT_UNKNOWN( sparsity_ == set_sparsity_enum ); + vector< std::set >& set_r( work_[thread]->set_r ); + vector< std::set >& set_u( work_[thread]->set_u ); + vector< std::set >& set_v( work_[thread]->set_h ); + // + set_v.resize(n); + // + local::sparse::get_internal_pattern( + transpose, x_index, for_jac_sparsity, set_r + ); + local::sparse::get_internal_pattern( + transpose, y_index, rev_hes_sparsity, set_u + ); + // + ok = rev_sparse_hes(vx, bool_s, bool_t, q, set_r, set_u, set_v, x); + if( ! ok ) + ok = rev_sparse_hes(vx, bool_s, bool_t, q, set_r, set_u, set_v); + if( ! ok ) + { msg = atomic_name() + msg + " sparsity = set_sparsity_enum"; + CPPAD_ASSERT_KNOWN(false, msg.c_str()); + } + local::sparse::set_internal_pattern(zero_empty, input_empty, + transpose, x_index, rev_hes_sparsity, set_v + ); + } + for(size_t j = 0; j < n; j++) + { if( x_index[j] > 0 ) + rev_jac_flag[ x_index[j] ] |= bool_t[j]; + } + return ok; +} + +} // END_CPPAD_NAMESPACE +# endif diff --git a/build-config/cppad/include/cppad/core/atomic/two_rev_sparse_jac.hpp b/build-config/cppad/include/cppad/core/atomic/two_rev_sparse_jac.hpp new file mode 100644 index 00000000..36d16a40 --- /dev/null +++ b/build-config/cppad/include/cppad/core/atomic/two_rev_sparse_jac.hpp @@ -0,0 +1,289 @@ +# ifndef CPPAD_CORE_ATOMIC_TWO_REV_SPARSE_JAC_HPP +# define CPPAD_CORE_ATOMIC_TWO_REV_SPARSE_JAC_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ +/* +$begin atomic_two_rev_sparse_jac$$ +$spell + sq + mul.hpp + rt + afun + Jacobian + jac + CppAD + std + bool + const + hes +$$ + +$section Atomic Reverse Jacobian Sparsity Patterns$$ + +$head Syntax$$ +$icode%ok% = %afun%.rev_sparse_jac(%q%, %rt%, %st%, %x%) +%$$ + +$head Deprecated 2016-06-27$$ +$icode%ok% = %afun%.rev_sparse_jac(%q%, %rt%, %st%) +%$$ + +$head Purpose$$ +This function is used by +$cref RevSparseJac$$ to compute +Jacobian sparsity patterns. +If you are using $cref RevSparseJac$$, +one of the versions of this +virtual function must be defined by the +$cref/atomic_user/atomic_two_ctor/atomic_user/$$ class. +$pre + +$$ +For a fixed matrix $latex R \in \B{R}^{q \times m}$$, +the Jacobian of $latex R * f( x )$$ with respect to $latex x \in \B{R}^n$$ is +$latex \[ + S(x) = R * f^{(1)} (x) +\] $$ +Given a $cref/sparsity pattern/glossary/Sparsity Pattern/$$ for $latex R$$, +$code rev_sparse_jac$$ computes a sparsity pattern for $latex S(x)$$. + +$head Implementation$$ +If you are using +$cref RevSparseJac$$ or $cref ForSparseHes$$, +this virtual function must be defined by the +$cref/atomic_user/atomic_two_ctor/atomic_user/$$ class. + +$subhead q$$ +The argument $icode q$$ has prototype +$codei% + size_t %q% +%$$ +It specifies the number of rows in +$latex R \in \B{R}^{q \times m}$$ and the Jacobian +$latex S(x) \in \B{R}^{q \times n}$$. + +$subhead rt$$ +This argument has prototype +$codei% + const %atomic_sparsity%& %rt% +%$$ +and is a +$cref/atomic_sparsity/atomic_two_option/atomic_sparsity/$$ pattern for +$latex R^\R{T} \in \B{R}^{m \times q}$$. + +$subhead st$$ +This argument has prototype +$codei% + %atomic_sparsity%& %st% +%$$ +The input value of its elements +are not specified (must not matter). +Upon return, $icode s$$ is a +$cref/atomic_sparsity/atomic_two_option/atomic_sparsity/$$ pattern for +$latex S(x)^\R{T} \in \B{R}^{n \times q}$$. + +$subhead x$$ +$index deprecated$$ +The argument has prototype +$codei% + const CppAD::vector<%Base%>& %x% +%$$ +and size is equal to the $icode n$$. +This is the $cref Value$$ corresponding to the parameters in the +vector $cref/ax/atomic_two_afun/ax/$$ (when the atomic function was called). +To be specific, if +$codei% + if( Parameter(%ax%[%i%]) == true ) + %x%[%i%] = Value( %ax%[%i%] ); + else + %x%[%i%] = CppAD::numeric_limits<%Base%>::quiet_NaN(); +%$$ +The version of this function with out the $icode x$$ argument is deprecated; +i.e., you should include the argument even if you do not use it. + +$head ok$$ +The return value $icode ok$$ has prototype +$codei% + bool %ok% +%$$ +If it is $code true$$, the corresponding evaluation succeeded, +otherwise it failed. + +$end +----------------------------------------------------------------------------- +*/ + +namespace CppAD { // BEGIN_CPPAD_NAMESPACE +/*! +\file atomic/two_rev_sparse_jac.hpp +Atomic reverse mode Jacobian sparsity patterns. +*/ +/*! +Link, after case split, from rev_jac_sweep to atomic_base + +\param q [in] +is the row dimension for the Jacobian sparsity partterns + +\param rt [out] +is the tansposed Jacobian sparsity pattern w.r.t to range variables y + +\param st [in] +is the tansposed Jacobian sparsity pattern for the argument variables x + +\param x +is the integer value for x arguments that are parameters. +*/ +template +bool atomic_base::rev_sparse_jac( + size_t q , + const vector< std::set >& rt , + vector< std::set >& st , + const vector& x ) +{ return false; } +template +bool atomic_base::rev_sparse_jac( + size_t q , + const vector& rt , + vector& st , + const vector& x ) +{ return false; } +template +bool atomic_base::rev_sparse_jac( + size_t q , + const vectorBool& rt , + vectorBool& st , + const vector& x ) +{ return false; } +// deprecated versions +template +bool atomic_base::rev_sparse_jac( + size_t q , + const vector< std::set >& rt , + vector< std::set >& st ) +{ return false; } +template +bool atomic_base::rev_sparse_jac( + size_t q , + const vector& rt , + vector& st ) +{ return false; } +template +bool atomic_base::rev_sparse_jac( + size_t q , + const vectorBool& rt , + vectorBool& st ) +{ return false; } + +/*! +Link, before case split, from rev_jac_sweep to atomic_base. + +\tparam InternalSparsity +Is the used internaly for sparsity calculations; i.e., +sparse_pack or sparse_list. + +\param x +is parameter arguments to the function, other components are nan. + +\param x_index +is the variable index, on the tape, for the arguments to this function. +This size of x_index is n, the number of arguments to this function. + +\param y_index +is the variable index, on the tape, for the results for this function. +This size of y_index is m, the number of results for this function. + +\param var_sparsity +On input, for i = 0, ... , m-1, the sparsity pattern with index y_index[i], +is the sparsity for the i-th argument to this atomic function. +On output, for j = 0, ... , n-1, the sparsity pattern with index x_index[j], +the sparsity has been updated to remove y as a function of x. +*/ +template +template +bool atomic_base::rev_sparse_jac( + const vector& x , + const local::pod_vector& x_index , + const local::pod_vector& y_index , + InternalSparsity& var_sparsity ) +{ + // initial results may be non-empty during reverse mode + size_t q = var_sparsity.end(); + bool input_empty = false; + bool zero_empty = true; + bool transpose = false; + size_t n = x_index.size(); + bool ok = false; + size_t thread = thread_alloc::thread_num(); + allocate_work(thread); + // + std::string msg = ": atomic_base.rev_sparse_jac: returned false"; + if( sparsity_ == pack_sparsity_enum ) + { vectorBool& pack_rt ( work_[thread]->pack_r ); + vectorBool& pack_st ( work_[thread]->pack_s ); + local::sparse::get_internal_pattern( + transpose, y_index, var_sparsity, pack_rt + ); + // + pack_st.resize(n * q ); + ok = rev_sparse_jac(q, pack_rt, pack_st, x); + if( ! ok ) + ok = rev_sparse_jac(q, pack_rt, pack_st); + if( ! ok ) + { msg = atomic_name() + msg + " sparsity = pack_sparsity_enum"; + CPPAD_ASSERT_KNOWN(false, msg.c_str()); + } + local::sparse::set_internal_pattern(zero_empty, input_empty, + transpose, x_index, var_sparsity, pack_st + ); + } + else if( sparsity_ == bool_sparsity_enum ) + { vector& bool_rt ( work_[thread]->bool_r ); + vector& bool_st ( work_[thread]->bool_s ); + local::sparse::get_internal_pattern( + transpose, y_index, var_sparsity, bool_rt + ); + bool_st.resize(n * q ); + ok = rev_sparse_jac(q, bool_rt, bool_st, x); + if( ! ok ) + ok = rev_sparse_jac(q, bool_rt, bool_st); + if( ! ok ) + { msg = atomic_name() + msg + " sparsity = bool_sparsity_enum"; + CPPAD_ASSERT_KNOWN(false, msg.c_str()); + } + local::sparse::set_internal_pattern(zero_empty, input_empty, + transpose, x_index, var_sparsity, bool_st + ); + } + else + { CPPAD_ASSERT_UNKNOWN( sparsity_ == set_sparsity_enum ); + vector< std::set >& set_rt ( work_[thread]->set_r ); + vector< std::set >& set_st ( work_[thread]->set_s ); + local::sparse::get_internal_pattern( + transpose, y_index, var_sparsity, set_rt + ); + set_st.resize(n); + ok = rev_sparse_jac(q, set_rt, set_st, x); + if( ! ok ) + ok = rev_sparse_jac(q, set_rt, set_st); + if( ! ok ) + { msg = atomic_name() + msg + " sparsity = set_sparsity_enum"; + CPPAD_ASSERT_KNOWN(false, msg.c_str()); + } + local::sparse::set_internal_pattern(zero_empty, input_empty, + transpose, x_index, var_sparsity, set_st + ); + } + return ok; +} + +} // END_CPPAD_NAMESPACE +# endif diff --git a/build-config/cppad/include/cppad/core/atomic/two_reverse.hpp b/build-config/cppad/include/cppad/core/atomic/two_reverse.hpp new file mode 100644 index 00000000..43270b17 --- /dev/null +++ b/build-config/cppad/include/cppad/core/atomic/two_reverse.hpp @@ -0,0 +1,291 @@ +# ifndef CPPAD_CORE_ATOMIC_TWO_REVERSE_HPP +# define CPPAD_CORE_ATOMIC_TWO_REVERSE_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-18 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ +/* +$begin atomic_two_reverse$$ +$spell + sq + mul.hpp + afun + ty + px + py + Taylor + const + CppAD + atx + aty + apx + apy + af +$$ + +$section Atomic Reverse Mode$$ +$spell + bool +$$ + +$head Syntax$$ + +$subhead Base$$ +$icode%ok% = %afun%.reverse(%q%, %tx%, %ty%, %px%, %py%) +%$$ +This syntax is used by $icode%f%.Forward%$$ where $icode f$$ has prototype +$codei% + ADFun<%Base%> %f% +%$$ +and $icode afun$$ is used in $icode f$$. + +$subhead AD$$ +$icode%ok% = %afun%.reverse(%q%, %atx%, %aty%, %apx%, %apy%) +%$$ +This syntax is used by $icode%af%.Forward%$$ where $icode af$$ has prototype +$codei% + ADFun< AD<%Base%> , %Base% > %af% +%$$ +and $icode afun$$ is used in $icode af$$ (see $cref base2ad$$). + +$head Purpose$$ +This function is used by $cref/reverse/Reverse/$$ +to compute derivatives. + +$head Implementation$$ +If you are using +$cref/reverse/Reverse/$$ mode, +this virtual function must be defined by the +$cref/atomic_user/atomic_two_ctor/atomic_user/$$ class. +It can just return $icode%ok% == false%$$ +(and not compute anything) for values +of $icode q$$ that are greater than those used by your +$cref/reverse/Reverse/$$ mode calculations. + +$head q$$ +The argument $icode q$$ has prototype +$codei% + size_t %q% +%$$ +It specifies the highest order Taylor coefficient that +computing the derivative of. + +$head tx$$ +The argument $icode tx$$ has prototype +$codei% + const CppAD::vector<%Base%>& %tx% +%$$ +and $icode%tx%.size() == (%q%+1)*%n%$$. +For $latex j = 0 , \ldots , n-1$$ and $latex k = 0 , \ldots , q$$, +we use the Taylor coefficient notation +$latex \[ +\begin{array}{rcl} + x_j^k & = & tx [ j * ( q + 1 ) + k ] + \\ + X_j (t) & = & x_j^0 + x_j^1 t^1 + \cdots + x_j^q t^q +\end{array} +\] $$ +Note that superscripts represent an index for $latex x_j^k$$ +and an exponent for $latex t^k$$. +Also note that the Taylor coefficients for $latex X(t)$$ correspond +to the derivatives of $latex X(t)$$ at $latex t = 0$$ in the following way: +$latex \[ + x_j^k = \frac{1}{ k ! } X_j^{(k)} (0) +\] $$ + +$head atx$$ +The argument $icode atx$$ has prototype +$codei% + const CppAD::vector< AD<%Base%> >& %atx% +%$$ +Otherwise, $icode atx$$ specifications are the same as for $icode tx$$. + +$head ty$$ +The argument $icode ty$$ has prototype +$codei% + const CppAD::vector<%Base%>& %ty% +%$$ +and $icode%tx%.size() == (%q%+1)*%m%$$. +For $latex i = 0 , \ldots , m-1$$ and $latex k = 0 , \ldots , q$$, +we use the Taylor coefficient notation +$latex \[ +\begin{array}{rcl} + Y_i (t) & = & f_i [ X(t) ] + \\ + Y_i (t) & = & y_i^0 + y_i^1 t^1 + \cdots + y_i^q t^q + o ( t^q ) + \\ + y_i^k & = & ty [ i * ( q + 1 ) + k ] +\end{array} +\] $$ +where $latex o( t^q ) / t^q \rightarrow 0$$ as $latex t \rightarrow 0$$. +Note that superscripts represent an index for $latex y_j^k$$ +and an exponent for $latex t^k$$. +Also note that the Taylor coefficients for $latex Y(t)$$ correspond +to the derivatives of $latex Y(t)$$ at $latex t = 0$$ in the following way: +$latex \[ + y_j^k = \frac{1}{ k ! } Y_j^{(k)} (0) +\] $$ + +$head aty$$ +The argument $icode aty$$ has prototype +$codei% + const CppAD::vector< AD<%Base%> >& %aty% +%$$ +Otherwise, $icode aty$$ specifications are the same as for $icode ty$$. + + +$head F$$ +We use the notation $latex \{ x_j^k \} \in \B{R}^{n \times (q+1)}$$ for +$latex \[ + \{ x_j^k \W{:} j = 0 , \ldots , n-1, k = 0 , \ldots , q \} +\]$$ +We use the notation $latex \{ y_i^k \} \in \B{R}^{m \times (q+1)}$$ for +$latex \[ + \{ y_i^k \W{:} i = 0 , \ldots , m-1, k = 0 , \ldots , q \} +\]$$ +We define the function +$latex F : \B{R}^{n \times (q+1)} \rightarrow \B{R}^{m \times (q+1)}$$ by +$latex \[ + y_i^k = F_i^k [ \{ x_j^k \} ] +\] $$ +Note that +$latex \[ + F_i^0 ( \{ x_j^k \} ) = f_i ( X(0) ) = f_i ( x^0 ) +\] $$ +We also note that +$latex F_i^\ell ( \{ x_j^k \} )$$ is a function of +$latex x^0 , \ldots , x^\ell$$ +and is determined by the derivatives of $latex f_i (x)$$ +up to order $latex \ell$$. + + +$head G, H$$ +We use $latex G : \B{R}^{m \times (q+1)} \rightarrow \B{R}$$ +to denote an arbitrary scalar valued function of $latex \{ y_i^k \}$$. +We use $latex H : \B{R}^{n \times (q+1)} \rightarrow \B{R}$$ +defined by +$latex \[ + H ( \{ x_j^k \} ) = G[ F( \{ x_j^k \} ) ] +\] $$ + +$head py$$ +The argument $icode py$$ has prototype +$codei% + const CppAD::vector<%Base%>& %py% +%$$ +and $icode%py%.size() == m * (%q%+1)%$$. +For $latex i = 0 , \ldots , m-1$$, $latex k = 0 , \ldots , q$$, +$latex \[ + py[ i * (q + 1 ) + k ] = \partial G / \partial y_i^k +\] $$ + +$head apy$$ +The argument $icode apy$$ has prototype +$codei% + const CppAD::vector< AD<%Base%> >& %apy% +%$$ +Otherwise, $icode apy$$ specifications are the same as for $icode py$$. + +$subhead px$$ +The $icode px$$ has prototype +$codei% + CppAD::vector<%Base%>& %px% +%$$ +and $icode%px%.size() == n * (%q%+1)%$$. +The input values of the elements of $icode px$$ +are not specified (must not matter). +Upon return, +for $latex j = 0 , \ldots , n-1$$ and $latex \ell = 0 , \ldots , q$$, +$latex \[ +\begin{array}{rcl} +px [ j * (q + 1) + \ell ] & = & \partial H / \partial x_j^\ell +\\ +& = & +( \partial G / \partial \{ y_i^k \} ) \cdot + ( \partial \{ y_i^k \} / \partial x_j^\ell ) +\\ +& = & +\sum_{k=0}^q +\sum_{i=0}^{m-1} +( \partial G / \partial y_i^k ) ( \partial y_i^k / \partial x_j^\ell ) +\\ +& = & +\sum_{k=\ell}^q +\sum_{i=0}^{m-1} +py[ i * (q + 1 ) + k ] ( \partial F_i^k / \partial x_j^\ell ) +\end{array} +\] $$ +Note that we have used the fact that for $latex k < \ell$$, +$latex \partial F_i^k / \partial x_j^\ell = 0$$. + +$head apx$$ +The argument $icode apx$$ has prototype +$codei% + CppAD::vector< AD<%Base%> >& %apx% +%$$ +Otherwise, $icode apx$$ specifications are the same as for $icode px$$. + +$head ok$$ +The return value $icode ok$$ has prototype +$codei% + bool %ok% +%$$ +If it is $code true$$, the corresponding evaluation succeeded, +otherwise it failed. + +$end +----------------------------------------------------------------------------- +*/ + +namespace CppAD { // BEGIN_CPPAD_NAMESPACE +/*! +\file atomic/two_reverse.hpp +Atomic reverse mode. +*/ +/*! +Link from reverse mode sweep to users routine. + +\param q [in] +highest order for this reverse mode calculation. + +\param tx [in] +Taylor coefficients corresponding to x for this calculation. + +\param ty [in] +Taylor coefficient corresponding to y for this calculation + +\param px [out] +Partials w.r.t. the x Taylor coefficients. + +\param py [in] +Partials w.r.t. the y Taylor coefficients. + +See atomic_reverse mode use documentation +*/ +template +bool atomic_base::reverse( + size_t q , + const vector& tx , + const vector& ty , + vector& px , + const vector& py ) +{ return false; } + +template +bool atomic_base::reverse( + size_t q , + const vector< AD >& atx , + const vector< AD >& aty , + vector< AD >& apx , + const vector< AD >& apy ) +{ return false; } + +} // END_CPPAD_NAMESPACE +# endif diff --git a/build-config/cppad/include/cppad/core/azmul.hpp b/build-config/cppad/include/cppad/core/azmul.hpp new file mode 100644 index 00000000..d091b24e --- /dev/null +++ b/build-config/cppad/include/cppad/core/azmul.hpp @@ -0,0 +1,247 @@ +# ifndef CPPAD_CORE_AZMUL_HPP +# define CPPAD_CORE_AZMUL_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ +/* +$begin azmul$$ +$spell + azmul + const + namespace + Vec +$$ + +$section Absolute Zero Multiplication$$ + +$head Syntax$$ +$icode%z% = azmul(%x%, %y%)%$$ + +$head Purpose$$ +Evaluates multiplication with an absolute zero +for any of the possible types listed below. +The result is given by +$latex \[ +z = \left\{ \begin{array}{ll} + 0 & {\rm if} \; x = 0 \\ + x \cdot y & {\rm otherwise} +\end{array} \right. +\] $$ +Note if $icode x$$ is zero and $icode y$$ is infinity, +ieee multiplication would result in not a number whereas +$icode z$$ would be zero. + +$head Base$$ +If $icode Base$$ satisfies the +$cref/base type requirements/base_require/$$ +and arguments $icode x$$, $icode y$$ have prototypes +$codei% + const %Base%& %x% + const %Base%& %y% +%$$ +then the result $icode z$$ has prototype +$codei% + %Base% %z% +%$$ + +$head AD$$ +If the arguments $icode x$$, $icode y$$ have prototype +$codei% + const AD<%Base%>& %x% + const AD<%Base%>& %y% +%$$ +then the result $icode z$$ has prototype +$codei% + AD<%Base%> %z% +%$$ + +$head VecAD$$ +If the arguments $icode x$$, $icode y$$ have prototype +$codei% + const VecAD<%Base%>::reference& %x% + const VecAD<%Base%>::reference& %y% +%$$ +then the result $icode z$$ has prototype +$codei% + AD<%Base%> %z% +%$$ + +$head Example$$ +$children% + example/general/azmul.cpp +%$$ +The file +$cref azmul.cpp$$ +is an examples and tests of this function. + +$end +*/ + +namespace CppAD { // BEGIN_CPPAD_NAMESPACE +// ========================================================================== + +// case where x and y are AD ------------------------------------------- +template AD +azmul(const AD& x, const AD& y) +{ + // compute the Base part + AD result; + result.value_ = azmul(x.value_, y.value_); + + // check if there is a recording in progress + local::ADTape* tape = AD::tape_ptr(); + if( tape == nullptr ) + return result; + tape_id_t tape_id = tape->id_; + // tape_id cannot match the default value for tape_id_; i.e., 0 + CPPAD_ASSERT_UNKNOWN( tape_id > 0 ); + + // check if x and y tapes match + bool match_x = x.tape_id_ == tape_id; + bool match_y = y.tape_id_ == tape_id; + + // check if x and y are dynamic parameters + bool dyn_x = match_x & (x.ad_type_ == dynamic_enum); + bool dyn_y = match_y & (y.ad_type_ == dynamic_enum); + + // check if x and y are variables + bool var_x = match_x & (x.ad_type_ != dynamic_enum); + bool var_y = match_y & (y.ad_type_ != dynamic_enum); + + CPPAD_ASSERT_KNOWN( + x.tape_id_ == y.tape_id_ || ! match_x || ! match_y , + "azmul: AD variables or dynamic parameters on different threads." + ); + if( var_x ) + { if( var_y ) + { // result = azmul(variable, variable) + CPPAD_ASSERT_UNKNOWN( local::NumRes(local::ZmulvvOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( local::NumArg(local::ZmulvvOp) == 2 ); + + // put operand addresses in tape + tape->Rec_.PutArg(x.taddr_, y.taddr_); + + // put operator in the tape + result.taddr_ = tape->Rec_.PutOp(local::ZmulvvOp); + + // make result a variable + result.tape_id_ = tape_id; + result.ad_type_ = variable_enum; + } + else if( ( ! dyn_y ) & IdenticalZero( y.value_ ) ) + { // result = variable * 0 + } + else if( ( ! dyn_y ) & IdenticalOne( y.value_ ) ) + { // result = variable * 1 + result.make_variable(x.tape_id_, x.taddr_); + } + else + { // result = zmul(variable, parameter) + CPPAD_ASSERT_UNKNOWN( local::NumRes(local::ZmulvpOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( local::NumArg(local::ZmulvpOp) == 2 ); + + // put operand addresses in tape + addr_t p = y.taddr_; + if( ! dyn_y ) + p = tape->Rec_.put_con_par(y.value_); + tape->Rec_.PutArg(x.taddr_, p); + + // put operator in the tape + result.taddr_ = tape->Rec_.PutOp(local::ZmulvpOp); + + // make result a variable + result.tape_id_ = tape_id; + result.ad_type_ = variable_enum; + } + } + else if( var_y ) + { if( ( ! dyn_x ) & IdenticalZero(x.value_) ) + { // result = 0 * variable + } + else if( ( ! dyn_x ) & IdenticalOne( x.value_ ) ) + { // result = 1 * variable + result.make_variable(y.tape_id_, y.taddr_); + } + else + { // result = zmul(parameter, variable) + CPPAD_ASSERT_UNKNOWN( local::NumRes(local::ZmulpvOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( local::NumArg(local::ZmulpvOp) == 2 ); + + // put operand addresses in tape + addr_t p = x.taddr_; + if( ! dyn_x ) + p = tape->Rec_.put_con_par(x.value_); + tape->Rec_.PutArg(p, y.taddr_); + + // put operator in the tape + result.taddr_ = tape->Rec_.PutOp(local::ZmulpvOp); + + // make result a variable + result.tape_id_ = tape_id; + result.ad_type_ = variable_enum; + } + } + else if( dyn_x | dyn_y ) + { addr_t arg0 = x.taddr_; + addr_t arg1 = y.taddr_; + if( ! dyn_x ) + arg0 = tape->Rec_.put_con_par(x.value_); + if( ! dyn_y ) + arg1 = tape->Rec_.put_con_par(y.value_); + // + // parameters with a dynamic parameter result + result.taddr_ = tape->Rec_.put_dyn_par( + result.value_, local::zmul_dyn, arg0, arg1 + ); + result.tape_id_ = tape_id; + result.ad_type_ = dynamic_enum; + } + return result; +} +// ========================================================================= +// Fold operations into case above +// ------------------------------------------------------------------------- +// Operations with VecAD_reference and AD only + +template AD +azmul(const AD& x, const VecAD_reference& y) +{ return azmul(x, y.ADBase()); } + +template AD +azmul(const VecAD_reference& x, const VecAD_reference& y) +{ return azmul(x.ADBase(), y.ADBase()); } + +template AD +azmul(const VecAD_reference& x, const AD& y) +{ return azmul(x.ADBase(), y); } +// ------------------------------------------------------------------------- +// Operations with Base + +template AD +azmul(const Base& x, const AD& y) +{ return azmul(AD(x), y); } + +template AD +azmul(const Base& x, const VecAD_reference& y) +{ return azmul(AD(x), y.ADBase()); } + +template AD +azmul(const AD& x, const Base& y) +{ return azmul(x, AD(y)); } + +template AD +azmul(const VecAD_reference& x, const Base& y) +{ return azmul(x.ADBase(), AD(y)); } + +// ========================================================================== +} // END_CPPAD_NAMESPACE + +# endif diff --git a/build-config/cppad/include/cppad/core/base2ad.hpp b/build-config/cppad/include/cppad/core/base2ad.hpp new file mode 100644 index 00000000..bf5106e7 --- /dev/null +++ b/build-config/cppad/include/cppad/core/base2ad.hpp @@ -0,0 +1,117 @@ +# ifndef CPPAD_CORE_BASE2AD_HPP +# define CPPAD_CORE_BASE2AD_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ +/* +$begin base2ad$$ +$spell + af + Taylor +$$ + +$spell +$$ + +$section Create an AD Function From a Base Function$$ + +$head Syntax$$ +$icode%af% = %f%.base2ad()%$$ + +$head See Also$$ +$cref mul_level$$ + +$head Base$$ +This is the base type used to recorded the operation sequence in $icode f$$ +and $icode af$$; i.e., the type $codei%AD<%Base%>%$$ was used to record +the operation sequence. + +$head f$$ +This object has prototype +$codei% + ADFun<%Base%> %f% +%$$ +It does it's derivative calculations using the type $icode Base$$. + +$head af$$ +This object has prototype +$codei% + ADFun< AD<%Base%> , %Base% > %af% +%$$ +It has the same operation sequence as $icode f$$, +but it does it's derivative calculations using the type +$codei%AD<%Base>%$$. +This enables one to record new functions that are defined +using derivatives of the function $icode f$$. +Initially, there are no Taylor coefficients stored in $icode af$$ and +$cref%af.size_order()%size_order%$$ is zero. + +$children% + example/general/base2ad.cpp +%$$ +$head Example$$ +The file $cref base2ad.cpp$$ +contains an example and test of this operation. + +$end +---------------------------------------------------------------------------- +*/ + +namespace CppAD { // BEGIN_CPPAD_NAMESPACE +/*! +\file base2ad.hpp +*/ +/// Create an ADFun< AD, Base > from this ADFun +template +ADFun< AD, RecBase > ADFun::base2ad(void) const +{ ADFun< AD, RecBase > fun; + // + // bool values + fun.has_been_optimized_ = has_been_optimized_; + fun.check_for_nan_ = check_for_nan_; + // + // size_t values + fun.compare_change_count_ = compare_change_count_; + fun.compare_change_number_ = compare_change_number_; + fun.compare_change_op_index_ = compare_change_op_index_; + CPPAD_ASSERT_UNKNOWN( fun.num_order_taylor_ == 0 ) ; + CPPAD_ASSERT_UNKNOWN( fun.cap_order_taylor_ == 0 ); + CPPAD_ASSERT_UNKNOWN( fun.num_direction_taylor_ == 0 ); + fun.num_var_tape_ = num_var_tape_; + // + // pod_vector objects + fun.ind_taddr_ = ind_taddr_; + fun.dep_taddr_ = dep_taddr_; + fun.dep_parameter_ = dep_parameter_; + fun.cskip_op_ = cskip_op_; + fun.load_op2var_ = load_op2var_; + // + // pod_maybe_vector< AD > = pod_maybe_vector + CPPAD_ASSERT_UNKNOWN( fun.taylor_.size() == 0 ); + // + // player + // (uses move semantics) + fun.play_ = play_.base2ad(); + // + // subgraph + fun.subgraph_info_ = subgraph_info_; + // + // sparse_pack + fun.for_jac_sparse_pack_ = for_jac_sparse_pack_; + // + // sparse_list + fun.for_jac_sparse_set_ = for_jac_sparse_set_; + // + return fun; +} + +} // END_CPPAD_NAMESPACE +# endif diff --git a/build-config/cppad/include/cppad/core/base_complex.hpp b/build-config/cppad/include/cppad/core/base_complex.hpp new file mode 100644 index 00000000..57354305 --- /dev/null +++ b/build-config/cppad/include/cppad/core/base_complex.hpp @@ -0,0 +1,384 @@ +# ifndef CPPAD_CORE_BASE_COMPLEX_HPP +# define CPPAD_CORE_BASE_COMPLEX_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ +# include +# include +# include + +// needed before one can use CPPAD_ASSERT_FIRST_CALL_NOT_PARALLEL +# include + +/* +$begin base_complex.hpp$$ +$spell + azmul + expm1 + atanh + acosh + asinh + endif + eps + abs_geq + Rel + Lt Le Eq Ge Gt + imag + gcc + isnan + cppad.hpp + sqrt + exp + cos + std + const + CppAD + Op + inline + enum + undef + acos + asin + atan + erf + erfc + Cond + namespace + bool +$$ + + +$section Enable use of AD where Base is std::complex$$ + +$children%example/general/complex_poly.cpp +%$$ +$head Example$$ +The file $cref complex_poly.cpp$$ contains an example use of +$code std::complex$$ type for a CppAD $icode Base$$ type. + +$head Include Order$$ +This file is included before $code $$ +so it is necessary to define the error handler +in addition to including +$cref/base_require.hpp/base_require/Include Order/$$ +$srccode%cpp% */ +# include +# include +# include +# include + +/* %$$ + +$head CondExpOp$$ +The type $code std::complex$$ does not supports the +$code <$$, $code <=$$, $code ==$$, $code >=$$, and $code >$$ operators; see +$cref/not ordered/base_cond_exp/CondExpTemplate/Not Ordered/$$. +Hence its $code CondExpOp$$ function is defined by +$srccode%cpp% */ +namespace CppAD { + inline std::complex CondExpOp( + enum CppAD::CompareOp cop , + const std::complex &left , + const std::complex &right , + const std::complex &trueCase , + const std::complex &falseCase ) + { CppAD::ErrorHandler::Call( + true , __LINE__ , __FILE__ , + "std::complex CondExpOp(...)", + "Error: cannot use CondExp with a complex type" + ); + return std::complex(0); + } +} +/* %$$ + +$head CondExpRel$$ +The $cref/CPPAD_COND_EXP_REL/base_cond_exp/CondExpRel/$$ macro invocation +$srccode%cpp% */ +namespace CppAD { + CPPAD_COND_EXP_REL( std::complex ) +} +/* %$$ +used $code CondExpOp$$ above to +define $codei%CondExp%Rel%$$ for $code std::complex$$ arguments +and $icode%Rel%$$ equal to +$code Lt$$, $code Le$$, $code Eq$$, $code Ge$$, and $code Gt$$. + +$head EqualOpSeq$$ +Complex numbers do not carry operation sequence information. +Thus they are equal in this sense if and only if there values are equal. +$srccode%cpp% */ +namespace CppAD { + inline bool EqualOpSeq( + const std::complex &x , + const std::complex &y ) + { return x == y; + } +} +/* %$$ + +$head Identical$$ +Complex numbers do not carry operation sequence information. +Thus they are all parameters so the identical functions just check values. +$srccode%cpp% */ +namespace CppAD { + inline bool IdenticalCon(const std::complex &x) + { return true; } + inline bool IdenticalZero(const std::complex &x) + { return (x == std::complex(0., 0.) ); } + inline bool IdenticalOne(const std::complex &x) + { return (x == std::complex(1., 0.) ); } + inline bool IdenticalEqualCon( + const std::complex &x, const std::complex &y) + { return (x == y); } +} +/* %$$ + +$head Ordered$$ +Complex types do not support comparison operators, +$srccode%cpp% */ +# undef CPPAD_USER_MACRO +# define CPPAD_USER_MACRO(Fun) \ +inline bool Fun(const std::complex& x) \ +{ CppAD::ErrorHandler::Call( \ + true , __LINE__ , __FILE__ , \ + #Fun"(x)", \ + "Error: cannot use " #Fun " with x complex " \ + ); \ + return false; \ +} +namespace CppAD { + CPPAD_USER_MACRO(LessThanZero) + CPPAD_USER_MACRO(LessThanOrZero) + CPPAD_USER_MACRO(GreaterThanOrZero) + CPPAD_USER_MACRO(GreaterThanZero) + inline bool abs_geq( + const std::complex& x , + const std::complex& y ) + { return std::abs(x) >= std::abs(y); } +} +/* %$$ + +$head Integer$$ +The implementation of this function must agree +with the CppAD user specifications for complex arguments to the +$cref/Integer/Integer/x/Complex Types/$$ function: +$srccode%cpp% */ +namespace CppAD { + inline int Integer(const std::complex &x) + { return static_cast( x.real() ); } +} +/* %$$ + +$head azmul$$ +$srccode%cpp% */ +namespace CppAD { + CPPAD_AZMUL( std::complex ) +} +/* %$$ + +$head isnan$$ +The gcc 4.1.1 complier defines the function +$codei% + int std::complex::isnan( std::complex %z% ) +%$$ +(which is not specified in the C++ 1998 standard ISO/IEC 14882). +This causes an ambiguity between the function above and the CppAD +$cref/isnan/nan/$$ template function. +We avoid this ambiguity by defining a non-template version of +this function in the CppAD namespace. +$srccode%cpp% */ +namespace CppAD { + inline bool isnan(const std::complex& z) + { return (z != z); + } +} +/* %$$ + +$head Valid Unary Math$$ +The following macro invocations define the standard unary +math functions that are valid with complex arguments and are +required to use $code AD< std::complex >$$. +$srccode%cpp% */ +namespace CppAD { + CPPAD_STANDARD_MATH_UNARY(std::complex, cos) + CPPAD_STANDARD_MATH_UNARY(std::complex, cosh) + CPPAD_STANDARD_MATH_UNARY(std::complex, exp) + CPPAD_STANDARD_MATH_UNARY(std::complex, log) + CPPAD_STANDARD_MATH_UNARY(std::complex, sin) + CPPAD_STANDARD_MATH_UNARY(std::complex, sinh) + CPPAD_STANDARD_MATH_UNARY(std::complex, sqrt) +} +/* %$$ + +$head Invalid Unary Math$$ +The following macro definition and invocations define the standard unary +math functions that are invalid with complex arguments and are +required to use $code AD< std::complex >$$. +$srccode%cpp% */ +# undef CPPAD_USER_MACRO +# define CPPAD_USER_MACRO(Fun) \ +inline std::complex Fun(const std::complex& x) \ +{ CppAD::ErrorHandler::Call( \ + true , __LINE__ , __FILE__ , \ + #Fun"(x)", \ + "Error: cannot use " #Fun " with x complex " \ + ); \ + return std::complex(0); \ +} +namespace CppAD { + CPPAD_USER_MACRO(abs) + CPPAD_USER_MACRO(fabs) + CPPAD_USER_MACRO(acos) + CPPAD_USER_MACRO(asin) + CPPAD_USER_MACRO(atan) + CPPAD_USER_MACRO(sign) + CPPAD_USER_MACRO(asinh) + CPPAD_USER_MACRO(acosh) + CPPAD_USER_MACRO(atanh) + CPPAD_USER_MACRO(erf) + CPPAD_USER_MACRO(erfc) + CPPAD_USER_MACRO(expm1) + CPPAD_USER_MACRO(log1p) +} +/* %$$ + +$head pow $$ +The following defines a $code CppAD::pow$$ function that +is required to use $code AD< std::complex >$$: +$srccode%cpp% */ +namespace CppAD { + inline std::complex pow( + const std::complex &x , + const std::complex &y ) + { return std::pow(x, y); } +} +/* %$$ + +$head numeric_limits$$ +The following defines the CppAD $cref numeric_limits$$ +for the type $code std::complex$$: +$srccode%cpp% */ +namespace CppAD { + CPPAD_NUMERIC_LIMITS(double, std::complex) +} +/* %$$ + +$head to_string$$ +The following defines the function CppAD $cref to_string$$ +for the type $code std::complex$$: +$srccode%cpp% */ +namespace CppAD { + CPPAD_TO_STRING(std::complex) +} +/* %$$ +$end +*/ +# undef CPPAD_USER_MACRO_ONE +# define CPPAD_USER_MACRO_ONE(Fun) \ +inline bool Fun(const std::complex& x) \ +{ CppAD::ErrorHandler::Call( \ + true , __LINE__ , __FILE__ , \ + #Fun"(x)", \ + "Error: cannot use " #Fun " with x complex " \ + ); \ + return false; \ +} +# undef CPPAD_USER_MACRO_TWO +# define CPPAD_USER_MACRO_TWO(Fun) \ +inline std::complex Fun(const std::complex& x) \ +{ CppAD::ErrorHandler::Call( \ + true , __LINE__ , __FILE__ , \ + #Fun"(x)", \ + "Error: cannot use " #Fun " with x complex " \ + ); \ + return std::complex(0); \ +} +namespace CppAD { + // CondExpOp ------------------------------------------------------ + inline std::complex CondExpOp( + enum CppAD::CompareOp cop , + const std::complex &left , + const std::complex &right , + const std::complex &trueCase , + const std::complex &falseCase ) + { CppAD::ErrorHandler::Call( + true , __LINE__ , __FILE__ , + "std::complex CondExpOp(...)", + "Error: cannot use CondExp with a complex type" + ); + return std::complex(0); + } + // CondExpRel -------------------------------------------------------- + CPPAD_COND_EXP_REL( std::complex ) + // EqualOpSeq ----------------------------------------------------- + inline bool EqualOpSeq( + const std::complex &x , + const std::complex &y ) + { return x == y; + } + // Identical ------------------------------------------------------ + inline bool IdenticalCon(const std::complex &x) + { return true; } + inline bool IdenticalZero(const std::complex &x) + { return (x == std::complex(0., 0.) ); } + inline bool IdenticalOne(const std::complex &x) + { return (x == std::complex(1., 0.) ); } + inline bool IdenticalEqualCon( + const std::complex &x, const std::complex &y) + { return (x == y); } + // Ordered -------------------------------------------------------- + CPPAD_USER_MACRO_ONE(LessThanZero) + CPPAD_USER_MACRO_ONE(LessThanOrZero) + CPPAD_USER_MACRO_ONE(GreaterThanOrZero) + CPPAD_USER_MACRO_ONE(GreaterThanZero) + inline bool abs_geq( + const std::complex& x , + const std::complex& y ) + { return std::abs(x) >= std::abs(y); } + // Integer ------------------------------------------------------ + inline int Integer(const std::complex &x) + { return static_cast( x.real() ); } + // isnan ------------------------------------------------------------- + inline bool isnan(const std::complex& z) + { return (z != z); + } + // Valid standard math functions -------------------------------- + CPPAD_STANDARD_MATH_UNARY(std::complex, cos) + CPPAD_STANDARD_MATH_UNARY(std::complex, cosh) + CPPAD_STANDARD_MATH_UNARY(std::complex, exp) + CPPAD_STANDARD_MATH_UNARY(std::complex, log) + CPPAD_STANDARD_MATH_UNARY(std::complex, sin) + CPPAD_STANDARD_MATH_UNARY(std::complex, sinh) + CPPAD_STANDARD_MATH_UNARY(std::complex, sqrt) + // Invalid standrd math functions ------------------------------- + CPPAD_USER_MACRO_TWO(abs) + CPPAD_USER_MACRO_TWO(acos) + CPPAD_USER_MACRO_TWO(asin) + CPPAD_USER_MACRO_TWO(atan) + CPPAD_USER_MACRO_TWO(sign) + // The pow function + inline std::complex pow( + const std::complex &x , + const std::complex &y ) + { return std::pow(x, y); } + // numeric_limits ------------------------------------------------- + CPPAD_NUMERIC_LIMITS(float, std::complex) + // to_string ------------------------------------------------- + CPPAD_TO_STRING(std::complex) +} + +// undefine macros only used by this file +# undef CPPAD_USER_MACRO +# undef CPPAD_USER_MACRO_ONE +# undef CPPAD_USER_MACRO_TWO + +# endif diff --git a/build-config/cppad/include/cppad/core/base_cond_exp.hpp b/build-config/cppad/include/cppad/core/base_cond_exp.hpp new file mode 100644 index 00000000..ff07cf2b --- /dev/null +++ b/build-config/cppad/include/cppad/core/base_cond_exp.hpp @@ -0,0 +1,284 @@ +# ifndef CPPAD_CORE_BASE_COND_EXP_HPP +# define CPPAD_CORE_BASE_COND_EXP_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +/* +$begin base_cond_exp$$ +$spell + alloc + Rel + hpp + enum + namespace + Op + Lt + Le + Eq + Ge + Gt + Ne + cond + exp + const + adolc + CppAD + inline +$$ + +$section Base Type Requirements for Conditional Expressions$$ + +$head Purpose$$ +These definitions are required by the user's code to support the +$codei%AD<%Base%>%$$ type for $cref CondExp$$ operations: + +$head CompareOp$$ +The following $code enum$$ type is used in the specifications below: +$codep +namespace CppAD { + // The conditional expression operator enum type + enum CompareOp + { CompareLt, // less than + CompareLe, // less than or equal + CompareEq, // equal + CompareGe, // greater than or equal + CompareGt, // greater than + CompareNe // not equal + }; +} +$$ + +$head CondExpTemplate$$ +The type $icode Base$$ must support the syntax +$codei% + %result% = CppAD::CondExpOp( + %cop%, %left%, %right%, %exp_if_true%, %exp_if_false% + ) +%$$ +which computes implements the corresponding $cref CondExp$$ +function when the result has prototype +$codei% + %Base% %result% +%$$ +The argument $icode cop$$ has prototype +$codei% + enum CppAD::CompareOp %cop% +%$$ +The other arguments have the prototype +$codei% + const %Base%& %left% + const %Base%& %right% + const %Base%& %exp_if_true% + const %Base%& %exp_if_false% +%$$ + +$subhead Ordered Type$$ +If $icode Base$$ is a relatively simple type +that supports +$code <$$, $code <=$$, $code ==$$, $code >=$$, and $code >$$ operators +its $code CondExpOp$$ function can be defined by +$codei% +namespace CppAD { + inline %Base% CondExpOp( + enum CppAD::CompareOp %cop% , + const %Base% &%left% , + const %Base% &%right% , + const %Base% &%exp_if_true% , + const %Base% &%exp_if_false% ) + { return CondExpTemplate( + cop, left, right, trueCase, falseCase); + } +} +%$$ +For example, see +$cref/double CondExpOp/base_alloc.hpp/CondExpOp/$$. +For an example of and implementation of $code CondExpOp$$ with +a more involved $icode Base$$ type see +$cref/adolc CondExpOp/base_adolc.hpp/CondExpOp/$$. + + +$subhead Not Ordered$$ +If the type $icode Base$$ does not support ordering, +the $code CondExpOp$$ function does not make sense. +In this case one might (but need not) define $code CondExpOp$$ as follows: +$codei% +namespace CppAD { + inline %Base% CondExpOp( + enum CompareOp %cop% , + const %Base% &%left% , + const %Base% &%right% , + const %Base% &%exp_if_true% , + const %Base% &%exp_if_false% ) + { // attempt to use CondExp with a %Base% argument + assert(0); + return %Base%(0); + } +} +%$$ +For example, see +$cref/complex CondExpOp/base_complex.hpp/CondExpOp/$$. + +$head CondExpRel$$ +The macro invocation +$codei% + CPPAD_COND_EXP_REL(%Base%) +%$$ +uses $code CondExpOp$$ above to define the following functions +$codei% + CondExpLt(%left%, %right%, %exp_if_true%, %exp_if_false%) + CondExpLe(%left%, %right%, %exp_if_true%, %exp_if_false%) + CondExpEq(%left%, %right%, %exp_if_true%, %exp_if_false%) + CondExpGe(%left%, %right%, %exp_if_true%, %exp_if_false%) + CondExpGt(%left%, %right%, %exp_if_true%, %exp_if_false%) +%$$ +where the arguments have type $icode Base$$. +This should be done inside of the CppAD namespace. +For example, see +$cref/base_alloc/base_alloc.hpp/CondExpRel/$$. + +$end +*/ + +namespace CppAD { // BEGIN_CPPAD_NAMESPACE + +/*! +\file base_cond_exp.hpp +CondExp operations that aid in meeting Base type requirements. +*/ + +/*! +\def CPPAD_COND_EXP_BASE_REL(Type, Rel, Op) +This macro defines the operation +\verbatim + CondExpRel(left, right, exp_if_true, exp_if_false) +\endverbatim +The argument Type is the Base type for this base require operation. +The argument Rel is one of Lt, Le, Eq, Ge, Gt. +The argument Op is the corresponding CompareOp value. +*/ +# define CPPAD_COND_EXP_BASE_REL(Type, Rel, Op) \ + inline Type CondExp##Rel( \ + const Type& left , \ + const Type& right , \ + const Type& exp_if_true , \ + const Type& exp_if_false ) \ + { return CondExpOp(Op, left, right, exp_if_true, exp_if_false); \ + } + +/*! +\def CPPAD_COND_EXP_REL(Type) +The macro defines the operations +\verbatim + CondExpLt(left, right, exp_if_true, exp_if_false) + CondExpLe(left, right, exp_if_true, exp_if_false) + CondExpEq(left, right, exp_if_true, exp_if_false) + CondExpGe(left, right, exp_if_true, exp_if_false) + CondExpGt(left, right, exp_if_true, exp_if_false) +\endverbatim +The argument Type is the Base type for this base require operation. +*/ +# define CPPAD_COND_EXP_REL(Type) \ + CPPAD_COND_EXP_BASE_REL(Type, Lt, CompareLt) \ + CPPAD_COND_EXP_BASE_REL(Type, Le, CompareLe) \ + CPPAD_COND_EXP_BASE_REL(Type, Eq, CompareEq) \ + CPPAD_COND_EXP_BASE_REL(Type, Ge, CompareGe) \ + CPPAD_COND_EXP_BASE_REL(Type, Gt, CompareGt) + +/*! +Template function to implement Conditional Expressions for simple types +that have comparison operators. + +\tparam CompareType +is the type of the left and right operands to the comparison operator. + +\tparam ResultType +is the type of the result, which is the same as CompareType except +during forward and reverse mode sparese calculations. + +\param cop +specifices which comparison to use; i.e., +$code <$$, +$code <=$$, +$code ==$$, +$code >=$$, +$code >$$, or +$code !=$$. + +\param left +is the left operand to the comparison operator. + +\param right +is the right operand to the comparison operator. + +\param exp_if_true +is the return value is the comparison results in true. + +\param exp_if_false +is the return value is the comparison results in false. + +\return +see exp_if_true and exp_if_false above. +*/ +template +ResultType CondExpTemplate( + enum CompareOp cop , + const CompareType& left , + const CompareType& right , + const ResultType& exp_if_true , + const ResultType& exp_if_false ) +{ ResultType returnValue; + switch( cop ) + { + case CompareLt: + if( left < right ) + returnValue = exp_if_true; + else + returnValue = exp_if_false; + break; + + case CompareLe: + if( left <= right ) + returnValue = exp_if_true; + else + returnValue = exp_if_false; + break; + + case CompareEq: + if( left == right ) + returnValue = exp_if_true; + else + returnValue = exp_if_false; + break; + + case CompareGe: + if( left >= right ) + returnValue = exp_if_true; + else + returnValue = exp_if_false; + break; + + case CompareGt: + if( left > right ) + returnValue = exp_if_true; + else + returnValue = exp_if_false; + break; + + default: + CPPAD_ASSERT_UNKNOWN(0); + returnValue = exp_if_true; + } + return returnValue; +} + +} // END_CPPAD_NAMESPACE +# endif diff --git a/build-config/cppad/include/cppad/core/base_double.hpp b/build-config/cppad/include/cppad/core/base_double.hpp new file mode 100644 index 00000000..b2ab521d --- /dev/null +++ b/build-config/cppad/include/cppad/core/base_double.hpp @@ -0,0 +1,229 @@ +# ifndef CPPAD_CORE_BASE_DOUBLE_HPP +# define CPPAD_CORE_BASE_DOUBLE_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ +# include +# include + +/* +$begin base_double.hpp$$ +$spell + namespaces + cppad + hpp + azmul + expm1 + atanh + acosh + asinh + erf + erfc + endif + abs_geq + acos + asin + atan + cos + sqrt + tanh + std + fabs + bool + Lt Le Eq Ge Gt + Rel + CppAD + CondExpOp + namespace + inline + enum + const + exp + const +$$ + + +$section Enable use of AD where Base is double$$ + +$head CondExpOp$$ +The type $code double$$ is a relatively simple type that supports +$code <$$, $code <=$$, $code ==$$, $code >=$$, and $code >$$ operators; see +$cref/ordered type/base_cond_exp/CondExpTemplate/Ordered Type/$$. +Hence its $code CondExpOp$$ function is defined by +$srccode%cpp% */ +namespace CppAD { + inline double CondExpOp( + enum CompareOp cop , + const double& left , + const double& right , + const double& exp_if_true , + const double& exp_if_false ) + { return CondExpTemplate(cop, left, right, exp_if_true, exp_if_false); + } +} +/* %$$ + +$head CondExpRel$$ +The $cref/CPPAD_COND_EXP_REL/base_cond_exp/CondExpRel/$$ macro invocation +$srccode%cpp% */ +namespace CppAD { + CPPAD_COND_EXP_REL(double) +} +/* %$$ +uses $code CondExpOp$$ above to +define $codei%CondExp%Rel%$$ for $code double$$ arguments +and $icode%Rel%$$ equal to +$code Lt$$, $code Le$$, $code Eq$$, $code Ge$$, and $code Gt$$. + +$head EqualOpSeq$$ +The type $code double$$ is simple (in this respect) and so we define +$srccode%cpp% */ +namespace CppAD { + inline bool EqualOpSeq(const double& x, const double& y) + { return x == y; } +} +/* %$$ + +$head Identical$$ +The type $code double$$ is simple (in this respect) and so we define +$srccode%cpp% */ +namespace CppAD { + inline bool IdenticalCon(const double& x) + { return true; } + inline bool IdenticalZero(const double& x) + { return (x == 0.); } + inline bool IdenticalOne(const double& x) + { return (x == 1.); } + inline bool IdenticalEqualCon(const double& x, const double& y) + { return (x == y); } +} +/* %$$ + +$head Integer$$ +$srccode%cpp% */ +namespace CppAD { + inline int Integer(const double& x) + { return static_cast(x); } +} +/* %$$ + +$head azmul$$ +$srccode%cpp% */ +namespace CppAD { + CPPAD_AZMUL( double ) +} +/* %$$ + +$head Ordered$$ +The $code double$$ type supports ordered comparisons +$srccode%cpp% */ +namespace CppAD { + inline bool GreaterThanZero(const double& x) + { return x > 0.; } + inline bool GreaterThanOrZero(const double& x) + { return x >= 0.; } + inline bool LessThanZero(const double& x) + { return x < 0.; } + inline bool LessThanOrZero(const double& x) + { return x <= 0.; } + inline bool abs_geq(const double& x, const double& y) + { return std::fabs(x) >= std::fabs(y); } +} +/* %$$ + +$head Unary Standard Math$$ +The following macro invocations import the $code double$$ versions of +the unary standard math functions into the $code CppAD$$ namespace. +Importing avoids ambiguity errors when using both the +$code CppAD$$ and $code std$$ namespaces. +Note this also defines the $cref/float/base_float.hpp/Unary Standard Math/$$ +versions of these functions. +$srccode%cpp% */ +namespace CppAD { + using std::acos; + using std::asin; + using std::atan; + using std::cos; + using std::cosh; + using std::exp; + using std::fabs; + using std::log; + using std::log10; + using std::sin; + using std::sinh; + using std::sqrt; + using std::tan; + using std::tanh; + using std::asinh; + using std::acosh; + using std::atanh; + using std::erf; + using std::erfc; + using std::expm1; + using std::log1p; +} +/* %$$ +The absolute value function is special because its $code std$$ name is +$code fabs$$ +$srccode%cpp% */ +namespace CppAD { + inline double abs(const double& x) + { return std::fabs(x); } +} +/* %$$ + +$head sign$$ +The following defines the $code CppAD::sign$$ function that +is required to use $code AD$$: +$srccode%cpp% */ +namespace CppAD { + inline double sign(const double& x) + { if( x > 0. ) + return 1.; + if( x == 0. ) + return 0.; + return -1.; + } +} +/* %$$ + +$head pow$$ +The following defines a $code CppAD::pow$$ function that +is required to use $code AD$$. +As with the unary standard math functions, +this has the exact same signature as $code std::pow$$, +so use it instead of defining another function. +$srccode%cpp% */ +namespace CppAD { + using std::pow; +} +/* %$$ + +$head numeric_limits$$ +The following defines the CppAD $cref numeric_limits$$ +for the type $code double$$: +$srccode%cpp% */ +namespace CppAD { + CPPAD_NUMERIC_LIMITS(double, double) +} +/* %$$ + +$head to_string$$ +There is no need to define $code to_string$$ for $code double$$ +because it is defined by including $code cppad/utility/to_string.hpp$$; +see $cref to_string$$. +See $cref/base_complex.hpp/base_complex.hpp/to_string/$$ for an example where +it is necessary to define $code to_string$$ for a $icode Base$$ type. + +$end +*/ + +# endif diff --git a/build-config/cppad/include/cppad/core/base_float.hpp b/build-config/cppad/include/cppad/core/base_float.hpp new file mode 100644 index 00000000..3c04fea4 --- /dev/null +++ b/build-config/cppad/include/cppad/core/base_float.hpp @@ -0,0 +1,230 @@ +# ifndef CPPAD_CORE_BASE_FLOAT_HPP +# define CPPAD_CORE_BASE_FLOAT_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ +# include +# include + +/* +$begin base_float.hpp$$ +$spell + namespaces + cppad + hpp + azmul + expm1 + atanh + acosh + asinh + erf + erfc + endif + abs_geq + acos + asin + atan + cos + sqrt + tanh + std + fabs + bool + Lt Le Eq Ge Gt + Rel + CppAD + CondExpOp + namespace + inline + enum + const + exp + const +$$ + + +$section Enable use of AD where Base is float$$ + +$head CondExpOp$$ +The type $code float$$ is a relatively simple type that supports +$code <$$, $code <=$$, $code ==$$, $code >=$$, and $code >$$ operators; see +$cref/ordered type/base_cond_exp/CondExpTemplate/Ordered Type/$$. +Hence its $code CondExpOp$$ function is defined by +$srccode%cpp% */ +namespace CppAD { + inline float CondExpOp( + enum CompareOp cop , + const float& left , + const float& right , + const float& exp_if_true , + const float& exp_if_false ) + { return CondExpTemplate(cop, left, right, exp_if_true, exp_if_false); + } +} +/* %$$ + +$head CondExpRel$$ +The $cref/CPPAD_COND_EXP_REL/base_cond_exp/CondExpRel/$$ macro invocation +$srccode%cpp% */ +namespace CppAD { + CPPAD_COND_EXP_REL(float) +} +/* %$$ +uses $code CondExpOp$$ above to +define $codei%CondExp%Rel%$$ for $code float$$ arguments +and $icode%Rel%$$ equal to +$code Lt$$, $code Le$$, $code Eq$$, $code Ge$$, and $code Gt$$. + +$head EqualOpSeq$$ +The type $code float$$ is simple (in this respect) and so we define +$srccode%cpp% */ +namespace CppAD { + inline bool EqualOpSeq(const float& x, const float& y) + { return x == y; } +} +/* %$$ + +$head Identical$$ +The type $code float$$ is simple (in this respect) and so we define +$srccode%cpp% */ +namespace CppAD { + inline bool IdenticalCon(const float& x) + { return true; } + inline bool IdenticalZero(const float& x) + { return (x == 0.f); } + inline bool IdenticalOne(const float& x) + { return (x == 1.f); } + inline bool IdenticalEqualCon(const float& x, const float& y) + { return (x == y); } +} +/* %$$ + +$head Integer$$ +$srccode%cpp% */ +namespace CppAD { + inline int Integer(const float& x) + { return static_cast(x); } +} +/* %$$ + +$head azmul$$ +$srccode%cpp% */ +namespace CppAD { + CPPAD_AZMUL( float ) +} +/* %$$ + +$head Ordered$$ +The $code float$$ type supports ordered comparisons +$srccode%cpp% */ +namespace CppAD { + inline bool GreaterThanZero(const float& x) + { return x > 0.f; } + inline bool GreaterThanOrZero(const float& x) + { return x >= 0.f; } + inline bool LessThanZero(const float& x) + { return x < 0.f; } + inline bool LessThanOrZero(const float& x) + { return x <= 0.f; } + inline bool abs_geq(const float& x, const float& y) + { return std::fabs(x) >= std::fabs(y); } +} +/* %$$ + +$head Unary Standard Math$$ +The following macro invocations import the $code float$$ versions of +the unary standard math functions into the $code CppAD$$ namespace. +Importing avoids ambiguity errors when using both the +$code CppAD$$ and $code std$$ namespaces. +Note this also defines the $cref/double/base_double.hpp/Unary Standard Math/$$ +versions of these functions. +$srccode%cpp% */ +namespace CppAD { + using std::acos; + using std::asin; + using std::atan; + using std::cos; + using std::cosh; + using std::exp; + using std::fabs; + using std::log; + using std::log10; + using std::sin; + using std::sinh; + using std::sqrt; + using std::tan; + using std::tanh; + using std::asinh; + using std::acosh; + using std::atanh; + using std::erf; + using std::erfc; + using std::expm1; + using std::log1p; +} + +/* %$$ +The absolute value function is special because its $code std$$ name is +$code fabs$$ +$srccode%cpp% */ +namespace CppAD { + inline float abs(const float& x) + { return std::fabs(x); } +} +/* %$$ + +$head sign$$ +The following defines the $code CppAD::sign$$ function that +is required to use $code AD$$: +$srccode%cpp% */ +namespace CppAD { + inline float sign(const float& x) + { if( x > 0.f ) + return 1.f; + if( x == 0.f ) + return 0.f; + return -1.f; + } +} +/* %$$ +$head pow$$ +The following defines a $code CppAD::pow$$ function that +is required to use $code AD$$. +As with the unary standard math functions, +this has the exact same signature as $code std::pow$$, +so use it instead of defining another function. +$srccode%cpp% */ +namespace CppAD { + using std::pow; +} +/* %$$ + +$head numeric_limits$$ +The following defines the CppAD $cref numeric_limits$$ +for the type $code float$$: +$srccode%cpp% */ +namespace CppAD { + CPPAD_NUMERIC_LIMITS(float, float) +} +/* %$$ + +$head to_string$$ +There is no need to define $code to_string$$ for $code float$$ +because it is defined by including $code cppad/utility/to_string.hpp$$; +see $cref to_string$$. +See $cref/base_complex.hpp/base_complex.hpp/to_string/$$ for an example where +it is necessary to define $code to_string$$ for a $icode Base$$ type. + +$end +*/ + + +# endif diff --git a/build-config/cppad/include/cppad/core/base_hash.hpp b/build-config/cppad/include/cppad/core/base_hash.hpp new file mode 100644 index 00000000..4bf9a5aa --- /dev/null +++ b/build-config/cppad/include/cppad/core/base_hash.hpp @@ -0,0 +1,84 @@ +# ifndef CPPAD_CORE_BASE_HASH_HPP +# define CPPAD_CORE_BASE_HASH_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-18 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ +/* +$begin base_hash$$ +$spell + alloc + Cpp + adouble + valgrind + const + inline +$$ + +$section Base Type Requirements for Hash Coding Values$$ + +$head Syntax$$ +$icode%code% = hash_code(%x%)%$$ + +$head Purpose$$ +CppAD uses a table of $icode Base$$ type values when recording +$codei%AD<%Base%>%$$ operations. +A hashing function is used to reduce number of values stored in this table; +for example, it is not necessary to store the value 3.0 every +time it is used as a $cref/parameter/con_dyn_var/Parameter/$$. + +$head Default$$ +The default hashing function works with the set of bits that correspond +to a $icode Base$$ value. +In most cases this works well, but in some cases +it does not. For example, in the +$cref base_adolc.hpp$$ case, an $code adouble$$ value can have +fields that are not initialized and $code valgrind$$ reported an error +when these are used to form the hash code. + +$head x$$ +This argument has prototype +$codei% + const %Base%& %x +%$$ +It is the value we are forming a hash code for. + +$head code$$ +The return value $icode code$$ has prototype +$codei% + unsigned short %code% +%$$ +It is the hash code corresponding to $icode x$$. This intention is the +commonly used values will have different hash codes. +The hash code must satisfy +$codei% + %code% < CPPAD_HASH_TABLE_SIZE +%$$ +so that it is a valid index into the hash code table. + +$head inline$$ +If you define this function, it should declare it to be $code inline$$, +so that you do not get multiple definitions from different compilation units. + +$head Example$$ +See the $code base_alloc$$ $cref/hash_code/base_alloc.hpp/hash_code/$$ +and the $code adouble$$ $cref/hash_code/base_adolc.hpp/hash_code/$$. + +$end +*/ + +/*! +\def CPPAD_HASH_TABLE_SIZE +the codes retruned by hash_code are between zero and CPPAD_HASH_TABLE_SIZE +minus one. +*/ +# define CPPAD_HASH_TABLE_SIZE 10000 + +# endif diff --git a/build-config/cppad/include/cppad/core/base_limits.hpp b/build-config/cppad/include/cppad/core/base_limits.hpp new file mode 100644 index 00000000..c7f68a6e --- /dev/null +++ b/build-config/cppad/include/cppad/core/base_limits.hpp @@ -0,0 +1,67 @@ +# ifndef CPPAD_CORE_BASE_LIMITS_HPP +# define CPPAD_CORE_BASE_LIMITS_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-17 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +/* +$begin base_limits$$ +$spell + std + namespace + CppAD +$$ + +$section Base Type Requirements for Numeric Limits$$ + +$head CppAD::numeric_limits$$ +A specialization for +$cref/CppAD::numeric_limits/numeric_limits/$$ +must be defined in order to use the type $codei%AD<%Base%>%$$. +CppAD does not use a specialization of +$codei%std::numeric_limits<%Base%>%$$. +Since C++11, using a specialization of +$codei%std::numeric_limits<%Base%>%$$ +would require that $icode Base$$ be a literal type. + +$head CPPAD_NUMERIC_LIMITS$$ +In most cases, this macro can be used to define the specialization where +the numeric limits for the type $icode Base$$ +are the same as the standard numeric limits for the type $icode Other$$. +For most $icode Base$$ types, +there is a choice of $icode Other$$, +for which the following preprocessor macro invocation suffices: +$codei% + namespace CppAD { + CPPAD_NUMERIC_LIMITS(%Other%, %Base%) + } +%$$ +where the macro is defined by +$srccode%cpp% */ +# define CPPAD_NUMERIC_LIMITS(Other, Base) \ +template <> class numeric_limits\ +{\ + public:\ + static Base min(void) \ + { return static_cast( std::numeric_limits::min() ); }\ + static Base max(void) \ + { return static_cast( std::numeric_limits::max() ); }\ + static Base epsilon(void) \ + { return static_cast( std::numeric_limits::epsilon() ); }\ + static Base quiet_NaN(void) \ + { return static_cast( std::numeric_limits::quiet_NaN() ); }\ + static const int digits10 = std::numeric_limits::digits10;\ +}; +/* %$$ +$end +*/ + +# endif diff --git a/build-config/cppad/include/cppad/core/base_std_math.hpp b/build-config/cppad/include/cppad/core/base_std_math.hpp new file mode 100644 index 00000000..6bef3947 --- /dev/null +++ b/build-config/cppad/include/cppad/core/base_std_math.hpp @@ -0,0 +1,171 @@ +# ifndef CPPAD_CORE_BASE_STD_MATH_HPP +# define CPPAD_CORE_BASE_STD_MATH_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +/* +$begin base_std_math$$ +$spell + expm1 + atanh + acosh + asinh + inline + fabs + isnan + alloc + std + acos + asin + atan + cos + exp + sqrt + const + CppAD + namespace + erf + erfc +$$ + +$section Base Type Requirements for Standard Math Functions$$ + +$head Purpose$$ +These definitions are required for the user's code to use the type +$codei%AD<%Base%>%$$: + +$head Unary Standard Math$$ +The type $icode Base$$ must support the following functions +unary standard math functions (in the CppAD namespace): +$table +$bold Syntax$$ $cnext $bold Result$$ +$rnext +$icode%y% = abs(%x%)%$$ $cnext absolute value $rnext +$icode%y% = acos(%x%)%$$ $cnext inverse cosine $rnext +$icode%y% = acosh(%x%)%$$ $cnext inverse hyperbolic cosine $rnext +$icode%y% = asin(%x%)%$$ $cnext inverse sine $rnext +$icode%y% = asinh(%x%)%$$ $cnext inverse hyperbolic sin $rnext +$icode%y% = atan(%x%)%$$ $cnext inverse tangent $rnext +$icode%y% = atanh(%x%)%$$ $cnext inverse hyperbolic tangent $rnext +$icode%y% = cos(%x%)%$$ $cnext cosine $rnext +$icode%y% = cosh(%x%)%$$ $cnext hyperbolic cosine $rnext +$icode%y% = erf(%x%)%$$ $cnext error function $rnext +$icode%y% = erfc(%x%)%$$ $cnext complementary error function $rnext +$icode%y% = exp(%x%)%$$ $cnext exponential $rnext +$icode%y% = expm1(%x%)%$$ $cnext exponential of x minus one $rnext +$icode%y% = fabs(%x%)%$$ $cnext absolute value $rnext +$icode%y% = log(%x%)%$$ $cnext natural logarithm $rnext +$icode%y% = log1p(%x%)%$$ $cnext logarithm of one plus x $rnext +$icode%y% = sin(%x%)%$$ $cnext sine $rnext +$icode%y% = sinh(%x%)%$$ $cnext hyperbolic sine $rnext +$icode%y% = sqrt(%x%)%$$ $cnext square root $rnext +$icode%y% = tan(%x%)%$$ $cnext tangent +$tend +where the arguments and return value have the prototypes +$codei% + const %Base%& %x% + %Base% %y% +%$$ +For example, +$cref/base_alloc/base_alloc.hpp/Unary Standard Math/$$, + + +$head CPPAD_STANDARD_MATH_UNARY$$ +The macro invocation, within the CppAD namespace, +$codei% + CPPAD_STANDARD_MATH_UNARY(%Base%, %Fun%) +%$$ +defines the syntax +$codei% + %y% = CppAD::%Fun%(%x%) +%$$ +This macro uses the functions $codei%std::%Fun%$$ which +must be defined and have the same prototype as $codei%CppAD::%Fun%$$. +For example, +$cref/float/base_float.hpp/Unary Standard Math/$$. + +$head sign$$ +The type $icode Base$$ must support the syntax +$codei% + %y% = CppAD::sign(%x%) +%$$ +which computes +$latex \[ +y = \left\{ \begin{array}{ll} + +1 & {\rm if} \; x > 0 \\ + 0 & {\rm if} \; x = 0 \\ + -1 & {\rm if} \; x < 0 +\end{array} \right. +\] $$ +where $icode x$$ and $icode y$$ have the same prototype as above. +For example, see +$cref/base_alloc/base_alloc.hpp/sign/$$. +Note that, if ordered comparisons are not defined for the type $icode Base$$, +the $code code sign$$ function should generate an assert if it is used; see +$cref/complex invalid unary math/base_complex.hpp/Invalid Unary Math/$$. + +$head pow$$ +The type $icode Base$$ must support the syntax +$codei% + %z% = CppAD::pow(%x%, %y%) +%$$ +which computes $latex z = x^y$$. +The arguments $icode x$$ and $icode y$$ have prototypes +$codei% + const %Base%& %x% + const %Base%& %y% +%$$ +and the return value $icode z$$ has prototype +$codei% + %Base% %z% +%$$ +For example, see +$cref/base_alloc/base_alloc.hpp/pow/$$. + + +$head isnan$$ +If $icode Base$$ defines the $code isnan$$ function, +you may also have to provide a definition in the CppAD namespace +(to avoid a function ambiguity). +For example, see +$cref/base_complex/base_complex.hpp/isnan/$$. + + +$end +------------------------------------------------------------------------------- +*/ + +# include + +namespace CppAD { // BEGIN_CPPAD_NAMESPACE + +/*! +\file base_std_math.hpp +Defintions that aid meeting Base type requirements for standard math functions. +*/ + +/*! +\def CPPAD_STANDARD_MATH_UNARY(Type, Fun) +This macro defines the function +\verbatim + y = CppAD:Fun(x) +\endverbatim +where the argument x and return value y have type Type +using the corresponding function std::Fun. +*/ +# define CPPAD_STANDARD_MATH_UNARY(Type, Fun) \ + inline Type Fun(const Type& x) \ + { return std::Fun(x); } + +} // END_CPPAD_NAMESPACE + +# endif diff --git a/build-config/cppad/include/cppad/core/base_to_string.hpp b/build-config/cppad/include/cppad/core/base_to_string.hpp new file mode 100644 index 00000000..5a4ded2e --- /dev/null +++ b/build-config/cppad/include/cppad/core/base_to_string.hpp @@ -0,0 +1,65 @@ +# ifndef CPPAD_CORE_BASE_TO_STRING_HPP +# define CPPAD_CORE_BASE_TO_STRING_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-17 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ +/* +$begin base_to_string$$ +$spell + std + namespace + CppAD + struct + const + stringstream + setprecision + str +$$ + +$section Extending to_string To Another Floating Point Type$$ + +$head Base Requirement$$ +If the function $cref to_string$$ is used by an +$cref/AD type above Base/glossary/AD Type Above Base/$$, +A specialization for the template structure +$code CppAD::to_string_struct$$ must be defined. + +$head CPPAD_TO_STRING$$ +For most $icode Base$$ types, +the following can be used to define the specialization: +$codei% + namespace CppAD { + CPPAD_TO_STRING(%Base%) + } +%$$ +Note that the $code CPPAD_TO_STRING$$ macro assumes that the +$cref base_limits$$ and $cref base_std_math$$ have already been defined +for this type. +This macro is defined as follows: +$srccode%cpp% */ +# define CPPAD_TO_STRING(Base) \ +template <> struct to_string_struct\ +{ std::string operator()(const Base& value) \ + { std::stringstream os;\ + int n_digits = 1 + CppAD::numeric_limits::digits10; \ + os << std::setprecision(n_digits);\ + os << value;\ + return os.str();\ + }\ +}; +/* %$$ +$end +------------------------------------------------------------------------------ +*/ +// make sure to_string has been included +# include + +# endif diff --git a/build-config/cppad/include/cppad/core/bender_quad.hpp b/build-config/cppad/include/cppad/core/bender_quad.hpp new file mode 100644 index 00000000..c3e32d25 --- /dev/null +++ b/build-config/cppad/include/cppad/core/bender_quad.hpp @@ -0,0 +1,402 @@ +# ifndef CPPAD_CORE_BENDER_QUAD_HPP +# define CPPAD_CORE_BENDER_QUAD_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-17 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ +/* +$begin BenderQuad$$ +$spell + cppad.hpp + BAvector + gx + gxx + CppAD + Fy + dy + Jacobian + ADvector + const + dg + ddg +$$ + + +$section Computing Jacobian and Hessian of Bender's Reduced Objective$$ + +$head Syntax$$ +$codei% +# include +BenderQuad(%x%, %y%, %fun%, %g%, %gx%, %gxx%)%$$ + +$head See Also$$ +$cref opt_val_hes$$ + +$head Problem$$ +The type $cref/ADvector/BenderQuad/ADvector/$$ cannot be determined +form the arguments above +(currently the type $icode ADvector$$ must be +$codei%CPPAD_TESTVECTOR(%Base%)%$$.) +This will be corrected in the future by requiring $icode Fun$$ +to define $icode%Fun%::vector_type%$$ which will specify the +type $icode ADvector$$. + +$head Purpose$$ +We are given the optimization problem +$latex \[ +\begin{array}{rcl} +{\rm minimize} & F(x, y) & {\rm w.r.t.} \; (x, y) \in \B{R}^n \times \B{R}^m +\end{array} +\] $$ +that is convex with respect to $latex y$$. +In addition, we are given a set of equations $latex H(x, y)$$ +such that +$latex \[ + H[ x , Y(x) ] = 0 \;\; \Rightarrow \;\; F_y [ x , Y(x) ] = 0 +\] $$ +(In fact, it is often the case that $latex H(x, y) = F_y (x, y)$$.) +Furthermore, it is easy to calculate a Newton step for these equations; i.e., +$latex \[ + dy = - [ \partial_y H(x, y)]^{-1} H(x, y) +\] $$ +The purpose of this routine is to compute the +value, Jacobian, and Hessian of the reduced objective function +$latex \[ + G(x) = F[ x , Y(x) ] +\] $$ +Note that if only the value and Jacobian are needed, they can be +computed more quickly using the relations +$latex \[ + G^{(1)} (x) = \partial_x F [x, Y(x) ] +\] $$ + +$head x$$ +The $code BenderQuad$$ argument $icode x$$ has prototype +$codei% + const %BAvector% &%x% +%$$ +(see $cref/BAvector/BenderQuad/BAvector/$$ below) +and its size must be equal to $icode n$$. +It specifies the point at which we evaluating +the reduced objective function and its derivatives. + + +$head y$$ +The $code BenderQuad$$ argument $icode y$$ has prototype +$codei% + const %BAvector% &%y% +%$$ +and its size must be equal to $icode m$$. +It must be equal to $latex Y(x)$$; i.e., +it must solve the problem in $latex y$$ for this given value of $latex x$$ +$latex \[ +\begin{array}{rcl} + {\rm minimize} & F(x, y) & {\rm w.r.t.} \; y \in \B{R}^m +\end{array} +\] $$ + +$head fun$$ +The $code BenderQuad$$ object $icode fun$$ +must support the member functions listed below. +The $codei%AD<%Base%>%$$ arguments will be variables for +a tape created by a call to $cref Independent$$ from $code BenderQuad$$ +(hence they can not be combined with variables corresponding to a +different tape). + +$subhead fun.f$$ +The $code BenderQuad$$ argument $icode fun$$ supports the syntax +$codei% + %f% = %fun%.f(%x%, %y%) +%$$ +The $icode%fun%.f%$$ argument $icode x$$ has prototype +$codei% + const %ADvector% &%x% +%$$ +(see $cref/ADvector/BenderQuad/ADvector/$$ below) +and its size must be equal to $icode n$$. +The $icode%fun%.f%$$ argument $icode y$$ has prototype +$codei% + const %ADvector% &%y% +%$$ +and its size must be equal to $icode m$$. +The $icode%fun%.f%$$ result $icode f$$ has prototype +$codei% + %ADvector% %f% +%$$ +and its size must be equal to one. +The value of $icode f$$ is +$latex \[ + f = F(x, y) +\] $$. + +$subhead fun.h$$ +The $code BenderQuad$$ argument $icode fun$$ supports the syntax +$codei% + %h% = %fun%.h(%x%, %y%) +%$$ +The $icode%fun%.h%$$ argument $icode x$$ has prototype +$codei% + const %ADvector% &%x% +%$$ +and its size must be equal to $icode n$$. +The $icode%fun%.h%$$ argument $icode y$$ has prototype +$codei% + const %BAvector% &%y% +%$$ +and its size must be equal to $icode m$$. +The $icode%fun%.h%$$ result $icode h$$ has prototype +$codei% + %ADvector% %h% +%$$ +and its size must be equal to $icode m$$. +The value of $icode h$$ is +$latex \[ + h = H(x, y) +\] $$. + +$subhead fun.dy$$ +The $code BenderQuad$$ argument $icode fun$$ supports the syntax +$codei% + %dy% = %fun%.dy(%x%, %y%, %h%) + +%x% +%$$ +The $icode%fun%.dy%$$ argument $icode x$$ has prototype +$codei% + const %BAvector% &%x% +%$$ +and its size must be equal to $icode n$$. +Its value will be exactly equal to the $code BenderQuad$$ argument +$icode x$$ and values depending on it can be stored as private objects +in $icode f$$ and need not be recalculated. +$codei% + +%y% +%$$ +The $icode%fun%.dy%$$ argument $icode y$$ has prototype +$codei% + const %BAvector% &%y% +%$$ +and its size must be equal to $icode m$$. +Its value will be exactly equal to the $code BenderQuad$$ argument +$icode y$$ and values depending on it can be stored as private objects +in $icode f$$ and need not be recalculated. +$codei% + +%h% +%$$ +The $icode%fun%.dy%$$ argument $icode h$$ has prototype +$codei% + const %ADvector% &%h% +%$$ +and its size must be equal to $icode m$$. +$codei% + +%dy% +%$$ +The $icode%fun%.dy%$$ result $icode dy$$ has prototype +$codei% + %ADvector% %dy% +%$$ +and its size must be equal to $icode m$$. +The return value $icode dy$$ is given by +$latex \[ + dy = - [ \partial_y H (x , y) ]^{-1} h +\] $$ +Note that if $icode h$$ is equal to $latex H(x, y)$$, +$latex dy$$ is the Newton step for finding a zero +of $latex H(x, y)$$ with respect to $latex y$$; +i.e., +$latex y + dy$$ is an approximate solution for the equation +$latex H (x, y + dy) = 0$$. + +$head g$$ +The argument $icode g$$ has prototype +$codei% + %BAvector% &%g% +%$$ +and has size one. +The input value of its element does not matter. +On output, +it contains the value of $latex G (x)$$; i.e., +$latex \[ + g[0] = G (x) +\] $$ + +$head gx$$ +The argument $icode gx$$ has prototype +$codei% + %BAvector% &%gx% +%$$ +and has size $latex n $$. +The input values of its elements do not matter. +On output, +it contains the Jacobian of $latex G (x)$$; i.e., +for $latex j = 0 , \ldots , n-1$$, +$latex \[ + gx[ j ] = G^{(1)} (x)_j +\] $$ + +$head gxx$$ +The argument $icode gx$$ has prototype +$codei% + %BAvector% &%gxx% +%$$ +and has size $latex n \times n$$. +The input values of its elements do not matter. +On output, +it contains the Hessian of $latex G (x)$$; i.e., +for $latex i = 0 , \ldots , n-1$$, and +$latex j = 0 , \ldots , n-1$$, +$latex \[ + gxx[ i * n + j ] = G^{(2)} (x)_{i,j} +\] $$ + +$head BAvector$$ +The type $icode BAvector$$ must be a +$cref SimpleVector$$ class. +We use $icode Base$$ to refer to the type of the elements of +$icode BAvector$$; i.e., +$codei% + %BAvector%::value_type +%$$ + +$head ADvector$$ +The type $icode ADvector$$ must be a +$cref SimpleVector$$ class with elements of type +$codei%AD<%Base%>%$$; i.e., +$codei% + %ADvector%::value_type +%$$ +must be the same type as +$codei% + AD< %BAvector%::value_type > +%$$. + + +$head Example$$ +$children% + example/general/bender_quad.cpp +%$$ +The file +$cref bender_quad.cpp$$ +contains an example and test of this operation. + + +$end +----------------------------------------------------------------------------- +*/ + +namespace CppAD { // BEGIN CppAD namespace + +template +void BenderQuad( + const BAvector &x , + const BAvector &y , + Fun fun , + BAvector &g , + BAvector &gx , + BAvector &gxx ) +{ // determine the base type + typedef typename BAvector::value_type Base; + + // check that BAvector is a SimpleVector class + CheckSimpleVector(); + + // declare the ADvector type + typedef CPPAD_TESTVECTOR(AD) ADvector; + + // size of the x and y spaces + size_t n = size_t(x.size()); + size_t m = size_t(y.size()); + + // check the size of gx and gxx + CPPAD_ASSERT_KNOWN( + g.size() == 1, + "BenderQuad: size of the vector g is not equal to 1" + ); + CPPAD_ASSERT_KNOWN( + size_t(gx.size()) == n, + "BenderQuad: size of the vector gx is not equal to n" + ); + CPPAD_ASSERT_KNOWN( + size_t(gxx.size()) == n * n, + "BenderQuad: size of the vector gxx is not equal to n * n" + ); + + // some temporary indices + size_t i, j; + + // variable versions x + ADvector vx(n); + for(j = 0; j < n; j++) + vx[j] = x[j]; + + // declare the independent variables + Independent(vx); + + // evaluate h = H(x, y) + ADvector h(m); + h = fun.h(vx, y); + + // evaluate dy (x) = Newton step as a function of x through h only + ADvector dy(m); + dy = fun.dy(x, y, h); + + // variable version of y + ADvector vy(m); + for(j = 0; j < m; j++) + vy[j] = y[j] + dy[j]; + + // evaluate G~ (x) = F [ x , y + dy(x) ] + ADvector gtilde(1); + gtilde = fun.f(vx, vy); + + // AD function object that corresponds to G~ (x) + // We will make heavy use of this tape, so optimize it + ADFun Gtilde; + Gtilde.Dependent(vx, gtilde); + Gtilde.optimize(); + + // value of G(x) + g = Gtilde.Forward(0, x); + + // initial forward direction vector as zero + BAvector dx(n); + for(j = 0; j < n; j++) + dx[j] = Base(0.0); + + // weight, first and second order derivative values + BAvector dg(1), w(1), ddw(2 * n); + w[0] = 1.; + + + // Jacobian and Hessian of G(x) is equal Jacobian and Hessian of Gtilde + for(j = 0; j < n; j++) + { // compute partials in x[j] direction + dx[j] = Base(1.0); + dg = Gtilde.Forward(1, dx); + gx[j] = dg[0]; + + // restore the dx vector to zero + dx[j] = Base(0.0); + + // compute second partials w.r.t x[j] and x[l] for l = 1, n + ddw = Gtilde.Reverse(2, w); + for(i = 0; i < n; i++) + gxx[ i * n + j ] = ddw[ i * 2 + 1 ]; + } + + return; +} + +} // END CppAD namespace + +# endif diff --git a/build-config/cppad/include/cppad/core/bool_fun.hpp b/build-config/cppad/include/cppad/core/bool_fun.hpp new file mode 100644 index 00000000..0964eee1 --- /dev/null +++ b/build-config/cppad/include/cppad/core/bool_fun.hpp @@ -0,0 +1,241 @@ +# ifndef CPPAD_CORE_BOOL_FUN_HPP +# define CPPAD_CORE_BOOL_FUN_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-17 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +/* +$begin BoolFun$$ +$spell + namespace + bool + CppAD + const +$$ + + +$section AD Boolean Functions$$ + +$head Syntax$$ +$codei%CPPAD_BOOL_UNARY(%Base%, %unary_name%) +%$$ +$icode%b% = %unary_name%(%u%) +%$$ +$icode%b% = %unary_name%(%x%) +%$$ +$codei%CPPAD_BOOL_BINARY(%Base%, %binary_name%) +%$$ +$icode%b% = %binary_name%(%u%, %v%) +%$$ +$icode%b% = %binary_name%(%x%, %y%)%$$ + + +$head Purpose$$ +Create a $code bool$$ valued function that has $codei%AD<%Base%>%$$ arguments. + +$head unary_name$$ +This is the name of the $code bool$$ valued function with one argument +(as it is used in the source code). +The user must provide a version of $icode unary_name$$ where +the argument has type $icode Base$$. +CppAD uses this to create a version of $icode unary_name$$ where the +argument has type $codei%AD<%Base%>%$$. + +$head u$$ +The argument $icode u$$ has prototype +$codei% + const %Base% &%u% +%$$ +It is the value at which the user provided version of $icode unary_name$$ +is to be evaluated. +It is also used for the first argument to the +user provided version of $icode binary_name$$. + +$head x$$ +The argument $icode x$$ has prototype +$codei% + const AD<%Base%> &%x% +%$$ +It is the value at which the CppAD provided version of $icode unary_name$$ +is to be evaluated. +It is also used for the first argument to the +CppAD provided version of $icode binary_name$$. + +$head b$$ +The result $icode b$$ has prototype +$codei% + bool %b% +%$$ + +$head Create Unary$$ +The preprocessor macro invocation +$codei% + CPPAD_BOOL_UNARY(%Base%, %unary_name%) +%$$ +defines the version of $icode unary_name$$ with a $codei%AD<%Base%>%$$ +argument. +This can with in a namespace +(not the $code CppAD$$ namespace) +but must be outside of any routine. + +$head binary_name$$ +This is the name of the $code bool$$ valued function with two arguments +(as it is used in the source code). +The user must provide a version of $icode binary_name$$ where +the arguments have type $icode Base$$. +CppAD uses this to create a version of $icode binary_name$$ where the +arguments have type $codei%AD<%Base%>%$$. + +$head v$$ +The argument $icode v$$ has prototype +$codei% + const %Base% &%v% +%$$ +It is the second argument to +the user provided version of $icode binary_name$$. + +$head y$$ +The argument $icode x$$ has prototype +$codei% + const AD<%Base%> &%y% +%$$ +It is the second argument to +the CppAD provided version of $icode binary_name$$. + +$head Create Binary$$ +The preprocessor macro invocation +$codei% + CPPAD_BOOL_BINARY(%Base%, %binary_name%) +%$$ +defines the version of $icode binary_name$$ with $codei%AD<%Base%>%$$ +arguments. +This can with in a namespace +(not the $code CppAD$$ namespace) +but must be outside of any routine. + + +$head Operation Sequence$$ +The result of this operation is not an +$cref/AD of Base/glossary/AD of Base/$$ object. +Thus it will not be recorded as part of an +AD of $icode Base$$ +$cref/operation sequence/glossary/Operation/Sequence/$$. + +$head Example$$ +$children% + example/general/bool_fun.cpp +%$$ +The file +$cref bool_fun.cpp$$ +contains an example and test of these operations. + +$head Deprecated 2007-07-31$$ +The preprocessor symbols $code CppADCreateUnaryBool$$ +and $code CppADCreateBinaryBool$$ are defined to be the same as +$code CPPAD_BOOL_UNARY$$ and $code CPPAD_BOOL_BINARY$$ respectively +(but their use is deprecated). + +$end +*/ + +namespace CppAD { // BEGIN_CPPAD_NAMESPACE +/*! +\file bool_fun.hpp +Routines and macros that implement functions from AD to bool. +*/ + +/*! +Macro that defines a unary function bool F(AD x) +using bool F(Base x). + +\param Base +base for the AD type of arguments to this unary bool valued function. + +\param unary_name +name of this unary function; i.e., F. +*/ +# define CPPAD_BOOL_UNARY(Base, unary_name) \ + inline bool unary_name (const CppAD::AD &x) \ + { \ + return CppAD::AD::UnaryBool(unary_name, x); \ + } + +/*! +Deprecated name for CPPAD_BOOL_UNARY +*/ +# define CppADCreateUnaryBool CPPAD_BOOL_UNARY + +/*! +Link a function name, and AD value pair to function call with base argument +and bool retrun value. + +\param FunName +is the name of the function that we are linking. + +\param x +is the argument where we are evaluating the function. +*/ +template +bool AD::UnaryBool( + bool FunName(const Base &x), + const AD &x +) +{ + return FunName(x.value_); +} + +/*! +Macro that defines a binary function bool F(AD x, AD y) +using bool F(Base x, Base y). + +\param Base +base for the AD type of arguments to this binary bool valued function. + +\param binary_name +name of this binary function; i.e., F. +*/ + +# define CPPAD_BOOL_BINARY(Base, binary_name) \ + inline bool binary_name ( \ + const CppAD::AD &x, const CppAD::AD &y) \ + { \ + return CppAD::AD::BinaryBool(binary_name, x, y); \ + } +/*! +Deprecated name for CPPAD_BOOL_BINARY +*/ +# define CppADCreateBinaryBool CPPAD_BOOL_BINARY + + +/*! +Link a function name, and two AD values to function call with base arguments +and bool retrun value. + +\param FunName +is the name of the function that we are linking. + +\param x +is the first argument where we are evaluating the function at. + +\param y +is the second argument where we are evaluating the function at. +*/ +template +bool AD::BinaryBool( + bool FunName(const Base &x, const Base &y), + const AD &x, const AD &y +) +{ + return FunName(x.value_, y.value_); +} + +} // END_CPPAD_NAMESPACE +# endif diff --git a/build-config/cppad/include/cppad/core/bool_valued.hpp b/build-config/cppad/include/cppad/core/bool_valued.hpp new file mode 100644 index 00000000..56b183b3 --- /dev/null +++ b/build-config/cppad/include/cppad/core/bool_valued.hpp @@ -0,0 +1,49 @@ +# ifndef CPPAD_CORE_BOOL_VALUED_HPP +# define CPPAD_CORE_BOOL_VALUED_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-18 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +/* +$begin BoolValued$$ +$spell + Bool +$$ + + +$section Bool Valued Operations and Functions with AD Arguments$$ + +$children% + include/cppad/core/compare.hpp% + include/cppad/core/near_equal_ext.hpp% + include/cppad/core/bool_fun.hpp% + include/cppad/core/con_dyn_var.hpp% + include/cppad/core/equal_op_seq.hpp +%$$ +$table +$rref Compare$$ +$rref NearEqualExt$$ +$rref BoolFun$$ +$rref con_dyn_var$$ +$rref EqualOpSeq$$ +$tend + + +$end +*/ + +# include +# include +# include +# include +# include + +# endif diff --git a/build-config/cppad/include/cppad/core/capacity_order.hpp b/build-config/cppad/include/cppad/core/capacity_order.hpp new file mode 100644 index 00000000..2ec0ee24 --- /dev/null +++ b/build-config/cppad/include/cppad/core/capacity_order.hpp @@ -0,0 +1,256 @@ +# ifndef CPPAD_CORE_CAPACITY_ORDER_HPP +# define CPPAD_CORE_CAPACITY_ORDER_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-18 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +/* +$begin capacity_order$$ +$spell + var + taylor_ + xq + yq +$$ + + +$section Controlling Taylor Coefficients Memory Allocation$$ + +$head Syntax$$ +$icode%f%.capacity_order(%c%)%$$ + +$subhead See Also$$ +$cref seq_property$$ + +$head Purpose$$ +The Taylor coefficients calculated by $cref Forward$$ mode calculations +are retained in an $cref ADFun$$ object for subsequent use during +$cref Reverse$$ mode and higher order Forward mode calculations. +For example, a call to $cref/Forward/forward_order/$$ with the syntax +$codei% + %yq% = %f%.Forward(%q%, %xq%) +%$$ +where $icode%q% > 0%$$ and $icode%xq%.size() == %f%.Domain()%$$, +uses the lower order Taylor coefficients and +computes the $th q$$ order Taylor coefficients for all +the variables in the operation sequence corresponding to $icode f$$. +The $code capacity_order$$ operation allows you to control that +amount of memory that is retained by an AD function object +(to hold $code Forward$$ results for subsequent calculations). + +$head f$$ +The object $icode f$$ has prototype +$codei% + ADFun<%Base%> %f% +%$$ + +$head c$$ +The argument $icode c$$ has prototype +$codei% + size_t %c% +%$$ +It specifies the number of Taylor coefficient orders that are allocated +in the AD operation sequence corresponding to $icode f$$. + +$subhead Pre-Allocating Memory$$ +If you plan to make calls to $code Forward$$ with the maximum value of +$icode q$$ equal to $icode Q$$, +it should be faster to pre-allocate memory for these calls using +$codei% + %f%.capacity_order(%c%) +%$$ +with $icode c$$ equal to $latex Q + 1$$. +If you do no do this, $code Forward$$ will automatically allocate memory +and will copy the results to a larger buffer, when necessary. +$pre + +$$ +Note that each call to $cref Dependent$$ frees the old memory +connected to the function object and sets the corresponding +taylor capacity to zero. + +$subhead Freeing Memory$$ +If you no longer need the Taylor coefficients of order $icode q$$ +and higher (that are stored in $icode f$$), +you can reduce the memory allocated to $icode f$$ using +$codei% + %f%.capacity_order(%c%) +%$$ +with $icode c$$ equal to $icode q$$. +Note that, if $cref ta_hold_memory$$ is true, this memory is not actually +returned to the system, but rather held for future use by the same thread. + +$head Original State$$ +If $icode f$$ is $cref/constructed/FunConstruct/$$ with the syntax +$codei% + ADFun<%Base%> %f%(%x%, %y%) +%$$, +there is an implicit call to $cref forward_zero$$ with $icode xq$$ equal to +the value of the +$cref/independent variables/glossary/Tape/Independent Variable/$$ +when the AD operation sequence was recorded. +This corresponds to $icode%c% == 1%$$. + +$children% + example/general/capacity_order.cpp +%$$ +$head Example$$ +The file +$cref capacity_order.cpp$$ +contains an example and test of these operations. + +$end +----------------------------------------------------------------------------- +*/ + +namespace CppAD { // BEGIN_CPPAD_NAMESPACE +/*! +\file capacity_order.hpp +Control of number of orders allocated. +\} +*/ + +/*! +Control of number of orders and directions allocated. + +\tparam Base +The type used during the forward mode computations; i.e., the corresponding +recording of operations used the type AD. + +\param c +is the number of orders to allocate memory for. +If c == 0 then r must also be zero. +In this case num_order_taylor_, cap_order_taylor_, and num_direction_taylor_ +are all set to zero. +In addition, taylor_.clear() is called. + +\param r +is the number of directions to allocate memory for. +If c == 1 then r must also be one. +In all cases, it must hold that + + r == num_direction_taylor_ || num_order_taylor <= 1 + +Upon return, num_direction_taylor_ is equal to r. + +\par num_order_taylor_ +The output value of num_order_taylor_ is the mininumum of its input +value and c. This minimum is the number of orders that are copied to the +new taylor coefficient buffer. + +\par num_direction_taylor_ +The output value of num_direction_taylor_ is equal to r. +*/ + +template +void ADFun::capacity_order(size_t c, size_t r) +{ // temporary indices + size_t i, k, ell; + + if( (c == cap_order_taylor_) & (r == num_direction_taylor_) ) + return; + + if( c == 0 ) + { CPPAD_ASSERT_UNKNOWN( r == 0 ); + taylor_.clear(); + num_order_taylor_ = 0; + cap_order_taylor_ = 0; + num_direction_taylor_ = r; + return; + } + CPPAD_ASSERT_UNKNOWN(r==num_direction_taylor_ || num_order_taylor_<=1); + + // Allocate new taylor with requested number of orders and directions + size_t new_len = ( (c-1)*r + 1 ) * num_var_tape_; + local::pod_vector_maybe new_taylor(new_len); + + // number of orders to copy + size_t p = std::min(num_order_taylor_, c); + if( p > 0 ) + { + // old order capacity + size_t C = cap_order_taylor_; + + // old number of directions + size_t R = num_direction_taylor_; + + // copy the old data into the new matrix + CPPAD_ASSERT_UNKNOWN( p == 1 || r == R ); + for(i = 0; i < num_var_tape_; i++) + { // copy zero order + size_t old_index = ((C-1) * R + 1) * i + 0; + size_t new_index = ((c-1) * r + 1) * i + 0; + new_taylor[ new_index ] = taylor_[ old_index ]; + // copy higher orders + for(k = 1; k < p; k++) + { for(ell = 0; ell < R; ell++) + { old_index = ((C-1) * R + 1) * i + (k-1) * R + ell + 1; + new_index = ((c-1) * r + 1) * i + (k-1) * r + ell + 1; + new_taylor[ new_index ] = taylor_[ old_index ]; + } + } + } + } + + // replace taylor_ by new_taylor + taylor_.swap(new_taylor); + cap_order_taylor_ = c; + num_order_taylor_ = p; + num_direction_taylor_ = r; + + // note that the destructor for new_taylor will free the old taylor memory + return; +} + +/*! +User API control of number of orders allocated. + +\tparam Base +The type used during the forward mode computations; i.e., the corresponding +recording of operations used the type AD. + +\param c +is the number of orders to allocate memory for. +If c == 0, +num_order_taylor_, cap_order_taylor_, and num_direction_taylor_ +are all set to zero. +In addition, taylor_.clear() is called. + +\par num_order_taylor_ +The output value of num_order_taylor_ is the mininumum of its input +value and c. This minimum is the number of orders that are copied to the +new taylor coefficient buffer. + +\par num_direction_taylor_ +If is zero (one), num_direction_taylor_ is set to zero (one). +Otherwise, if num_direction_taylor_ is zero, it is set to one. +Othwerwise, num_direction_taylor_ is not modified. +*/ + +template +void ADFun::capacity_order(size_t c) +{ size_t r; + if( (c == 0) | (c == 1) ) + { r = c; + capacity_order(c, r); + return; + } + r = num_direction_taylor_; + if( r == 0 ) + r = 1; + capacity_order(c, r); + return; +} + +} // END CppAD namespace + + +# endif diff --git a/build-config/cppad/include/cppad/core/check_for_nan.hpp b/build-config/cppad/include/cppad/core/check_for_nan.hpp new file mode 100644 index 00000000..91fdac33 --- /dev/null +++ b/build-config/cppad/include/cppad/core/check_for_nan.hpp @@ -0,0 +1,244 @@ +# ifndef CPPAD_CORE_CHECK_FOR_NAN_HPP +# define CPPAD_CORE_CHECK_FOR_NAN_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ +/* +$begin check_for_nan$$ +$spell + std + vec + Cpp + const + bool + newline +$$ +$section Check an ADFun Object For Nan Results$$ + +$head Syntax$$ +$icode%f%.check_for_nan(%b%) +%$$ +$icode%b% = %f%.check_for_nan() +%$$ +$codei%get_check_for_nan(%vec%, %file%) +%$$ + +$head Debugging$$ +If $code NDEBUG$$ is not defined, and +the result of a $cref/forward/forward_order/$$ or $cref/reverse/reverse_any/$$ +calculation contains a $cref nan$$, +CppAD can halt with an error message. + +$head f$$ +For the syntax where $icode b$$ is an argument, +$icode f$$ has prototype +$codei% + ADFun<%Base%> %f% +%$$ +(see $codei%ADFun<%Base%>%$$ $cref/constructor/FunConstruct/$$). +For the syntax where $icode b$$ is the result, +$icode f$$ has prototype +$codei% + const ADFun<%Base%> %f% +%$$ + +$head b$$ +This argument or result has prototype +$codei% + bool %b% +%$$ +If $icode b$$ is true (false), +future calls to $icode%f%.Forward%$$ will (will not) check for $code nan$$. + +$head Default$$ +The value for this setting after construction of $icode f$$ is true. +The value of this setting is not affected by calling +$cref Dependent$$ for this function object. + +$head Error Message$$ +If this error is detected during zero order forward mode, +the values of the independent variables that resulted in the $code nan$$ +are written to a temporary binary file. +This is so that you can run the original source code with those values +to see what is causing the $code nan$$. + +$subhead vector_size$$ +The error message with contain the text +$codei%vector_size = %vector_size%$$ followed the newline character +$code '\n'$$. +The value of $icode vector_size$$ is the number of elements +in the independent vector. + +$subhead file_name$$ +The error message with contain the text +$codei%file_name = %file_name%$$ followed the newline character +$code '\n'$$. +The value of $icode file_name$$ is the name of the temporary file +that contains the dependent variable values. + +$subhead index$$ +The error message will contain the text +$codei%index = %index%$$ followed by the newline character $code '\n'$$. +The value of $icode index$$ is the lowest dependent variable index +that has the value $code nan$$. + +$head get_check_for_nan$$ +This routine can be used to get the independent variable +values that result in a $code nan$$. + +$subhead vec$$ +This argument has prototype +$codei% + CppAD::vector<%Base%>& %vec% +%$$ +It size must be equal to the corresponding value of +$cref/vector_size/check_for_nan/Error Message/vector_size/$$ +in the corresponding error message. +The input value of its elements does not matter. +Upon return, it will contain the values for the independent variables, +in the corresponding call to $cref Independent$$, +that resulted in the $code nan$$. +(Note that the call to $code Independent$$ uses an vector with elements +of type $codei%AD<%Base%>%$$ and $icode vec$$ has elements of type +$icode Base$$.) + +$subhead file$$ +This argument has prototype +$codei% + const std::string& %file% +%$$ +It must be the value of +$cref/file_name/check_for_nan/Error Message/file_name/$$ +in the corresponding error message. + +$head Example$$ +$children% + example/general/check_for_nan.cpp +%$$ +The file +$cref check_for_nan.cpp$$ +contains an example and test of these operations. + +$end +*/ + +# include +# include +# include + +# if CPPAD_HAS_MKSTEMP +# include +# include +# else +# if CPPAD_HAS_TMPNAM_S +# include +# else +# include +# endif +# endif + + +namespace CppAD { // BEGIN_CPPAD_NAMESPACE + +/*! +Set check_for_nan + +\param value +new value for this flag. +*/ +template +void ADFun::check_for_nan(bool value) +{ check_for_nan_ = value; } + +/*! +Get check_for_nan + +\return +current value of check_for_nan_. +*/ +template +bool ADFun::check_for_nan(void) const +{ return check_for_nan_; } + +/*! +Stores a vector in a file when nans occur. + +\param vec [in] +is the vector that is stored. + +\param [out] file_name +is the file where the vector is stored +*/ +template +void put_check_for_nan(const CppAD::vector& vec, std::string& file_name) +{ + size_t char_size = sizeof(Base) * vec.size(); + // 2DO: add vec.data() to C11 tests and use it when C11 true + // const char* char_ptr = reinterpret_cast( vec.data() ); + const char* char_ptr = reinterpret_cast( &vec[0] ); + +# if CPPAD_HAS_MKSTEMP + char pattern[] = "/tmp/fileXXXXXX"; + int fd = mkstemp(pattern); + file_name = pattern; + ssize_t flag = write(fd, char_ptr, char_size); + if( flag < 0 ) + { std::cerr << "put_check_nan: write error\n"; + std::exit(1); + } + close(fd); +# else +# if CPPAD_HAS_TMPNAM_S + std::vector name(L_tmpnam_s); + // if( tmpnam_s( name.data(), L_tmpnam_s ) != 0 ) + if( tmpnam_s( &name[0], L_tmpnam_s ) != 0 ) + { CPPAD_ASSERT_KNOWN( + false, + "Cannot create a temporary file name" + ); + } + // file_name = name.data(); + file_name = &name[0]; +# else + file_name = tmpnam( nullptr ); +# endif + std::fstream file_out(file_name.c_str(), std::ios::out|std::ios::binary ); + file_out.write(char_ptr, char_size); + file_out.close(); +# endif + return; +} + +/*! +Gets a vector that was stored by put_check_for_nan. + +\param vec [out] +is the vector that is stored. + +\param file_name [in] +is the file where the vector is stored +*/ +template +void get_check_for_nan(CppAD::vector& vec, const std::string& file_name) +{ // + std::streamsize char_size = std::streamsize( sizeof(Base) * vec.size() ); + // char* char_ptr = reinterpret_cast( vec.data() ); + char* char_ptr = reinterpret_cast( &vec[0] ); + // + std::fstream file_in(file_name.c_str(), std::ios::in|std::ios::binary ); + file_in.read(char_ptr, char_size); + // + return; +} + +} // END_CPPAD_NAMESPACE + +# endif diff --git a/build-config/cppad/include/cppad/core/chkpoint_one/chkpoint_one.hpp b/build-config/cppad/include/cppad/core/chkpoint_one/chkpoint_one.hpp new file mode 100644 index 00000000..7ce66cfc --- /dev/null +++ b/build-config/cppad/include/cppad/core/chkpoint_one/chkpoint_one.hpp @@ -0,0 +1,621 @@ +# ifndef CPPAD_CORE_CHKPOINT_ONE_CHKPOINT_ONE_HPP +# define CPPAD_CORE_CHKPOINT_ONE_CHKPOINT_ONE_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ +# include +# include + +namespace CppAD { // BEGIN_CPPAD_NAMESPACE +/*! +\file chkpoint_one.hpp +First generation checkpoint functions. +*/ + +/* +$begin chkpoint_one$$ +$spell + mul + chkpoint + alloc + inuse + sv + var + cppad.hpp + CppAD + checkpoint + checkpointing + algo + atom_fun + const + enum + bool + recomputed +$$ + +$section Checkpoint Functions: First Generation$$ + +$head Deprecated 2019-01-14$$ +Using the $code checkpoint$$ class has been deprecated. +Use $cref chkpoint_two$$ instead. + +$head Syntax$$ +$codei%checkpoint<%Base%> %atom_fun%( + %name%, %algo%, %ax%, %ay%, %sparsity%, %optimize% +) +%sv% = %atom_fun%.size_var() +%atom_fun%.option(%option_value%) +%algo%(%ax%, %ay%) +%atom_fun%(%ax%, %ay%) +checkpoint<%Base%>::clear()%$$ + +$head See Also$$ +$cref atomic_two$$, $cref rev_checkpoint.cpp$$ + +$head Purpose$$ + +$subhead Reduce Memory$$ +You can reduce the size of the tape and memory required for AD by +checkpointing functions of the form $latex y = f(x)$$ where +$latex f : \B{R}^n \rightarrow \B{R}^m$$. + +$subhead Faster Recording$$ +It may also reduce the time to make a recording the same function +for different values of the independent variable. +Note that the operation sequence for a recording that uses $latex f(x)$$ +may depend on its independent variables. + +$subhead Repeating Forward$$ +Normally, CppAD store $cref forward$$ mode results until they freed +using $cref capacity_order$$ or the corresponding $cref ADFun$$ object is +deleted. This is not true for checkpoint functions because a checkpoint +function may be used repeatedly with different arguments in the same tape. +Thus, forward mode results are recomputed each time a checkpoint function +is used during a forward or reverse mode sweep. + +$subhead Restriction$$ +The $cref/operation sequence/glossary/Operation/Sequence/$$ +representing $latex f(x)$$ cannot depend on the value of $latex x$$. +The approach in the $cref rev_checkpoint.cpp$$ example case be applied +when the operation sequence depends on $latex x$$. + +$subhead Multiple Level AD$$ +If $icode Base$$ is an AD type, it is possible to record $icode Base$$ +operations. +Note that $icode atom_fun$$ will treat $icode algo$$ as an atomic +operation while recording $codei%AD%<%Base%>%$$ operations, but not while +recording $icode Base$$ operations. +See the $code chkpoint_one_mul_level.cpp$$ example. + + +$head Method$$ +The $code checkpoint$$ class is derived from $code atomic_base$$ +and makes this easy. +It implements all the $code atomic_base$$ +$cref/virtual functions/atomic_two/Virtual Functions/$$ +and hence its source code $code cppad/core/chkpoint_one/chkpoint_one.hpp$$ +provides an example implementation of $cref atomic_two$$. +The difference is that $code chkpoint_one.hpp$$ uses AD +instead of user provided derivatives. + +$head constructor$$ +The syntax for the checkpoint constructor is +$codei% + checkpoint<%Base%> %atom_fun%(%name%, %algo%, %ax%, %ay%) +%$$ +$list number$$ +This constructor cannot be called in $cref/parallel/ta_in_parallel/$$ mode. +$lnext +You cannot currently be recording +$codei%AD<%Base%>%$$ operations when the constructor is called. +$lnext +This object $icode atom_fun$$ must not be destructed for as long +as any $codei%ADFun<%Base%>%$$ object uses its atomic operation. +$lnext +This class is implemented as a derived class of +$cref/atomic/atomic_two_ctor/atomic_base/$$ and hence +some of its error message will refer to $code atomic_base$$. +$lend + +$head Base$$ +The type $icode Base$$ specifies the base type for AD operations. + +$head ADVector$$ +The type $icode ADVector$$ must be a +$cref/simple vector class/SimpleVector/$$ with elements of type +$codei%AD<%Base%>%$$. + +$head name$$ +This $icode checkpoint$$ constructor argument has prototype +$codei% + const char* %name% +%$$ +It is the name used for error reporting. +The suggested value for $icode name$$ is $icode atom_fun$$; i.e., +the same name as used for the object being constructed. + +$head ax$$ +This argument has prototype +$codei% + const %ADVector%& %ax% +%$$ +and size must be equal to $icode n$$. +It specifies vector $latex x \in \B{R}^n$$ +at which an $codei%AD<%Base%>%$$ version of +$latex y = f(x)$$ is to be evaluated. + +$head ay$$ +This argument has prototype +$codei% + %ADVector%& %ay% +%$$ +Its input size must be equal to $icode m$$ and does not change. +The input values of its elements do not matter. +Upon return, it is an $codei%AD<%Base%>%$$ version of +$latex y = f(x)$$. + +$head sparsity$$ +This argument has prototype +$codei% + atomic_base<%Base%>::option_enum %sparsity% +%$$ +It specifies $cref/sparsity/atomic_two_ctor/atomic_base/sparsity/$$ +in the $code atomic_base$$ constructor and must be either +$codei%atomic_base<%Base%>::pack_sparsity_enum%$$, +$codei%atomic_base<%Base%>::bool_sparsity_enum%$$, or +$codei%atomic_base<%Base%>::set_sparsity_enum%$$. +This argument is optional and its default value is unspecified. + +$head optimize$$ +This argument has prototype +$codei% + bool %optimize% +%$$ +It specifies if the recording corresponding to the atomic function +should be $cref/optimized/optimize/$$. +One expects to use a checkpoint function many times, so it should +be worth the time to optimize its operation sequence. +For debugging purposes, it may be useful to use the +original operation sequence (before optimization) +because it corresponds more closely to $icode algo$$. +This argument is optional and its default value is true. + + +$head size_var$$ +This $code size_var$$ member function return value has prototype +$codei% + size_t %sv% +%$$ +It is the $cref/size_var/seq_property/size_var/$$ for the +$codei%ADFun<%Base%>%$$ object is used to store the operation sequence +corresponding to $icode algo$$. + +$head option$$ +The $code option$$ syntax can be used to set the type of sparsity +pattern used by $icode atom_fun$$. +This is an $codei%atomic_base<%Base%>%$$ function and its documentation +can be found at $cref atomic_two_option$$. + +$head algo$$ +The type of $icode algo$$ is arbitrary, except for the fact that +the syntax +$codei% + %algo%(%ax%, %ay%) +%$$ +must evaluate the function $latex y = f(x)$$ using +$codei%AD<%Base%>%$$ operations. +In addition, we assume that the +$cref/operation sequence/glossary/Operation/Sequence/$$ +does not depend on the value of $icode ax$$. + +$head atom_fun$$ +Given $icode ax$$ it computes the corresponding value of $icode ay$$ +using the operation sequence corresponding to $icode algo$$. +If $codei%AD<%Base%>%$$ operations are being recorded, +it enters the computation as single operation in the recording +see $cref/start recording/Independent/Start Recording/$$. +(Currently each use of $icode atom_fun$$ actually corresponds to +$icode%m%+%n%+2%$$ operations and creates $icode m$$ new variables, +but this is not part of the CppAD specifications and my change.) + +$head Memory$$ + +$subhead Restriction$$ +The $code clear$$ routine cannot be called +while in $cref/parallel/ta_in_parallel/$$ execution mode. + +$head Parallel Mode$$ +The CppAD checkpoint function delays the caching of certain calculations +until they are needed. +In $cref/parallel model/ta_parallel_setup/$$, +this may result in $cref/thread_alloc::inuse(thread)/ta_inuse/$$ +being non-zero even though the specified thread is no longer active. +This memory will be freed when the checkpoint object is deleted. + +$subhead clear$$ +The $code atomic_base$$ class holds onto static work space +that is not connected to a particular object +(in order to increase speed by avoiding system memory allocation calls). +This call makes to work space $cref/available/ta_available/$$ to +for other uses by the same thread. +This should be called when you are done using the +atomic functions for a specific value of $icode Base$$. + +$end +*/ + +template +class checkpoint : public atomic_base { +// --------------------------------------------------------------------------- +private: + /// same as option_enum in base class + typedef typename atomic_base::option_enum option_enum; + // + // ------------------------------------------------------------------------ + // member_ + // ------------------------------------------------------------------------ + // same checkpoint object can be used by multiple threads + struct member_struct { + // + /// AD function corresponding to this checkpoint object + ADFun f_; + ADFun< AD, Base > af_; + // + /// sparsity for entire Jacobian f(x)^{(1)} + /// does not change so can cache it + local::sparse::list_setvec jac_sparse_set_; + vectorBool jac_sparse_bool_; + // + /// sparsity for sum_i f_i(x)^{(2)} does not change so can cache it + local::sparse::list_setvec hes_sparse_set_; + vectorBool hes_sparse_bool_; + }; + /// This version of work is const except during constructor + member_struct const_member_; + + /// use pointers and allocate memory to avoid false sharing + member_struct* member_[CPPAD_MAX_NUM_THREADS]; + // + /// allocate member_ for this thread + void allocate_member(size_t thread) + { if( member_[thread] == nullptr ) + { member_[thread] = new member_struct; + // The function is recorded in sequential mode and placed in + // const_member_.f_, other threads have copy. + member_[thread]->f_ = const_member_.f_; + } + return; + } + // + /// free member_ for this thread + void free_member(size_t thread) + { if( member_[thread] != nullptr ) + { delete member_[thread]; + member_[thread] = nullptr; + } + return; + } + // ------------------------------------------------------------------------ + option_enum sparsity(void) + { return static_cast< atomic_base* >(this)->sparsity(); } + // ------------------------------------------------------------------------ + /// set jac_sparse_set_ + void set_jac_sparse_set(void); + /// set jac_sparse_bool_ + void set_jac_sparse_bool(void); + // ------------------------------------------------------------------------ + /// set hes_sparse_set_ + void set_hes_sparse_set(void); + /// set hes_sparse_bool_ + void set_hes_sparse_bool(void); + // ------------------------------------------------------------------------ + /*! + Link from user_atomic to forward sparse Jacobian pack and bool + + \copydetails atomic_base::for_sparse_jac + */ + template + bool for_sparse_jac( + size_t q , + const sparsity_type& r , + sparsity_type& s , + const vector& x + ); + // ------------------------------------------------------------------------ + /*! + Link from user_atomic to reverse sparse Jacobian pack and bool + + \copydetails atomic_base::rev_sparse_jac + */ + template + bool rev_sparse_jac( + size_t q , + const sparsity_type& rt , + sparsity_type& st , + const vector& x + ); + /*! + Link from user_atomic to reverse sparse Hessian bools + + \copydetails atomic_base::rev_sparse_hes + */ + template + bool rev_sparse_hes( + const vector& vx , + const vector& s , + vector& t , + size_t q , + const sparsity_type& r , + const sparsity_type& u , + sparsity_type& v , + const vector& x + ); +public: + // ------------------------------------------------------------------------ + /*! + Constructor of a checkpoint object + + \param name [in] + is the user's name for the AD version of this atomic operation. + + \param algo [in/out] + user routine that compute AD function values + (not const because state may change during evaluation). + + \param ax [in] + argument value where algo operation sequence is taped. + + \param ay [out] + function value at specified argument value. + + \param sparsity [in] + what type of sparsity patterns are computed by this function, + pack_sparsity_enum bool_sparsity_enum, or set_sparsity_enum. + The default value is unspecified. + + \param optimize [in] + should the operation sequence corresponding to the algo be optimized. + The default value is true, but it is + sometimes useful to use false for debugging purposes. + */ + template + checkpoint( + const char* name , + Algo& algo , + const ADVector& ax , + ADVector& ay , + option_enum sparsity = + atomic_base::pack_sparsity_enum , + bool optimize = true + ); + /// destructor + ~checkpoint(void) + { +# ifndef NDEBUG + if( thread_alloc::in_parallel() ) + { std::string msg = atomic_base::atomic_name(); + msg += ": checkpoint destructor called in parallel mode."; + CPPAD_ASSERT_KNOWN(false, msg.c_str() ); + } +# endif + for(size_t thread = 0; thread < CPPAD_MAX_NUM_THREADS; ++thread) + free_member(thread); + } + // ------------------------------------------------------------------------ + /*! + Implement the user call to atom_fun.size_var(). + */ + size_t size_var(void) + { // make sure member_ is allocated for this thread + size_t thread = thread_alloc::thread_num(); + allocate_member(thread); + // + return member_[thread]->f_.size_var(); + } + // ------------------------------------------------------------------------ + /*! + Implement the user call to atom_fun(ax, ay). + + \tparam ADVector + A simple vector class with elements of type AD. + + \param id + optional parameter which must be zero if present. + + \param ax + is the argument vector for this call, + ax.size() determines the number of arguments. + + \param ay + is the result vector for this call, + ay.size() determines the number of results. + */ + template + void operator()(const ADVector& ax, ADVector& ay, size_t id = 0) + { CPPAD_ASSERT_KNOWN( + id == 0, + "checkpoint: id is non-zero in atom_fun(ax, ay, id)" + ); + this->atomic_base::operator()(ax, ay, id); + } + // ------------------------------------------------------------------------ + /*! + Link from user_atomic to forward mode + + \copydetails atomic_base::forward + */ + virtual bool forward( + size_t p , + size_t q , + const vector& vx , + vector& vy , + const vector& tx , + vector& ty + ); + virtual bool forward( + size_t p , + size_t q , + const vector& vx , + vector& vy , + const vector< AD >& atx , + vector< AD >& aty + ); + // ------------------------------------------------------------------------ + /*! + Link from user_atomic to reverse mode + + \copydetails atomic_base::reverse + */ + virtual bool reverse( + size_t q , + const vector& tx , + const vector& ty , + vector& px , + const vector& py + ); + virtual bool reverse( + size_t q , + const vector< AD >& atx , + const vector< AD >& aty , + vector< AD >& apx , + const vector< AD >& apy + ); + // ------------------------------------------------------------------------ + /*! + Link from user_atomic to forward sparse Jacobian pack + + \copydetails atomic_base::for_sparse_jac + */ + virtual bool for_sparse_jac( + size_t q , + const vectorBool& r , + vectorBool& s , + const vector& x + ); + /*! + Link from user_atomic to forward sparse Jacobian bool + + \copydetails atomic_base::for_sparse_jac + */ + virtual bool for_sparse_jac( + size_t q , + const vector& r , + vector& s , + const vector& x + ); + /*! + Link from user_atomic to forward sparse Jacobian sets + + \copydetails atomic_base::for_sparse_jac + */ + virtual bool for_sparse_jac( + size_t q , + const vector< std::set >& r , + vector< std::set >& s , + const vector& x + ); + // ------------------------------------------------------------------------ + /*! + Link from user_atomic to reverse sparse Jacobian pack + + \copydetails atomic_base::rev_sparse_jac + */ + virtual bool rev_sparse_jac( + size_t q , + const vectorBool& rt , + vectorBool& st , + const vector& x + ); + /*! + Link from user_atomic to reverse sparse Jacobian bool + + \copydetails atomic_base::rev_sparse_jac + */ + virtual bool rev_sparse_jac( + size_t q , + const vector& rt , + vector& st , + const vector& x + ); + /*! + Link from user_atomic to reverse Jacobian sets + + \copydetails atomic_base::rev_sparse_jac + */ + virtual bool rev_sparse_jac( + size_t q , + const vector< std::set >& rt , + vector< std::set >& st , + const vector& x + ); + // ------------------------------------------------------------------------ + /*! + Link from user_atomic to reverse sparse Hessian pack + + \copydetails atomic_base::rev_sparse_hes + */ + virtual bool rev_sparse_hes( + const vector& vx , + const vector& s , + vector& t , + size_t q , + const vectorBool& r , + const vectorBool& u , + vectorBool& v , + const vector& x + ); + /*! + Link from user_atomic to reverse sparse Hessian bool + + \copydetails atomic_base::rev_sparse_hes + */ + virtual bool rev_sparse_hes( + const vector& vx , + const vector& s , + vector& t , + size_t q , + const vector& r , + const vector& u , + vector& v , + const vector& x + ); + /*! + Link from user_atomic to reverse sparse Hessian sets + + \copydetails atomic_base::rev_sparse_hes + */ + virtual bool rev_sparse_hes( + const vector& vx , + const vector& s , + vector& t , + size_t q , + const vector< std::set >& r , + const vector< std::set >& u , + vector< std::set >& v , + const vector& x + ); +}; + +} // END_CPPAD_NAMESPACE + +// functions implemented in cppad/core/checkpoint files +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include + +# endif diff --git a/build-config/cppad/include/cppad/core/chkpoint_one/ctor.hpp b/build-config/cppad/include/cppad/core/chkpoint_one/ctor.hpp new file mode 100644 index 00000000..b6a3c9bc --- /dev/null +++ b/build-config/cppad/include/cppad/core/chkpoint_one/ctor.hpp @@ -0,0 +1,62 @@ +# ifndef CPPAD_CORE_CHKPOINT_ONE_CTOR_HPP +# define CPPAD_CORE_CHKPOINT_ONE_CTOR_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +namespace CppAD { // BEGIN_CPPAD_NAMESPACE + +template +template +checkpoint::checkpoint( + const char* name , + Algo& algo , + const ADVector& ax , + ADVector& ay , + option_enum sparsity , + bool optimize +) : atomic_base(name, sparsity) +{ +# ifndef NDEBUG + if( thread_alloc::in_parallel() ) + { std::string msg = name; + msg += ": checkpoint constructor called in parallel mode."; + CPPAD_ASSERT_KNOWN(false, msg.c_str() ); + } +# endif + for(size_t thread = 0; thread < CPPAD_MAX_NUM_THREADS; ++thread) + member_[thread] = nullptr; + // + CheckSimpleVector< CppAD::AD , ADVector>(); + // + // make a copy of ax because Independent modifies AD information + ADVector x_tmp(ax); + // delcare x_tmp as the independent variables + Independent(x_tmp); + // record mapping from x_tmp to ay + algo(x_tmp, ay); + // create function f_ : x -> y + const_member_.f_.Dependent(ay); + if( optimize ) + { // suppress checking for nan in f_ results + // (see optimize documentation for atomic functions) + const_member_.f_.check_for_nan(false); + // + // now optimize + const_member_.f_.optimize(); + } + // now disable checking of comparison operations + // 2DO: add a debugging mode that checks for changes and aborts + const_member_.f_.compare_change_count(0); +} + +} // END_CPPAD_NAMESPACE +# endif diff --git a/build-config/cppad/include/cppad/core/chkpoint_one/for_sparse_jac.hpp b/build-config/cppad/include/cppad/core/chkpoint_one/for_sparse_jac.hpp new file mode 100644 index 00000000..601bb05a --- /dev/null +++ b/build-config/cppad/include/cppad/core/chkpoint_one/for_sparse_jac.hpp @@ -0,0 +1,135 @@ +# ifndef CPPAD_CORE_CHKPOINT_ONE_FOR_SPARSE_JAC_HPP +# define CPPAD_CORE_CHKPOINT_ONE_FOR_SPARSE_JAC_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +namespace CppAD { // BEGIN_CPPAD_NAMESPACE + +template +template +bool checkpoint::for_sparse_jac( + size_t q , + const sparsity_type& r , + sparsity_type& s , + const vector& x ) +{ // make sure member_ is allocated for this thread + size_t thread = thread_alloc::thread_num(); + allocate_member(thread); + // + // during user sparsity calculations + size_t m = member_[thread]->f_.Range(); + size_t n = member_[thread]->f_.Domain(); + if( member_[thread]->jac_sparse_bool_.size() == 0 ) + set_jac_sparse_bool(); + if( member_[thread]->jac_sparse_set_.n_set() != 0 ) + member_[thread]->jac_sparse_set_.resize(0, 0); + CPPAD_ASSERT_UNKNOWN( member_[thread]->jac_sparse_bool_.size() == m * n ); + CPPAD_ASSERT_UNKNOWN( member_[thread]->jac_sparse_set_.n_set() == 0 ); + CPPAD_ASSERT_UNKNOWN( r.size() == n * q ); + CPPAD_ASSERT_UNKNOWN( s.size() == m * q ); + // + bool ok = true; + for(size_t i = 0; i < m; i++) + { for(size_t k = 0; k < q; k++) + s[i * q + k] = false; + } + // sparsity for s = jac_sparse_bool_ * r + for(size_t i = 0; i < m; i++) + { for(size_t k = 0; k < q; k++) + { // initialize sparsity for S(i,k) + bool s_ik = false; + // S(i,k) = sum_j J(i,j) * R(j,k) + for(size_t j = 0; j < n; j++) + { bool J_ij = member_[thread]->jac_sparse_bool_[ i * n + j]; + bool R_jk = r[j * q + k ]; + s_ik |= ( J_ij & R_jk ); + } + s[i * q + k] = s_ik; + } + } + return ok; +} +template +bool checkpoint::for_sparse_jac( + size_t q , + const vectorBool& r , + vectorBool& s , + const vector& x ) +{ // make sure member_ is allocated for this thread + size_t thread = thread_alloc::thread_num(); + allocate_member(thread); + // + return for_sparse_jac< vectorBool >(q, r, s, x); +} +template +bool checkpoint::for_sparse_jac( + size_t q , + const vector& r , + vector& s , + const vector& x ) +{ // make sure member_ is allocated for this thread + size_t thread = thread_alloc::thread_num(); + allocate_member(thread); + // + return for_sparse_jac< vector >(q, r, s, x); +} +template +bool checkpoint::for_sparse_jac( + size_t q , + const vector< std::set >& r , + vector< std::set >& s , + const vector& x ) +{ // make sure member_ is allocated for this thread + size_t thread = thread_alloc::thread_num(); + allocate_member(thread); + // + // during user sparsity calculations + size_t m = member_[thread]->f_.Range(); + size_t n = member_[thread]->f_.Domain(); + if( member_[thread]->jac_sparse_bool_.size() != 0 ) + member_[thread]->jac_sparse_bool_.clear(); + if( member_[thread]->jac_sparse_set_.n_set() == 0 ) + set_jac_sparse_set(); + CPPAD_ASSERT_UNKNOWN( member_[thread]->jac_sparse_bool_.size() == 0 ); + CPPAD_ASSERT_UNKNOWN( member_[thread]->jac_sparse_set_.n_set() == m ); + CPPAD_ASSERT_UNKNOWN( member_[thread]->jac_sparse_set_.end() == n ); + CPPAD_ASSERT_UNKNOWN( r.size() == n ); + CPPAD_ASSERT_UNKNOWN( s.size() == m ); + + bool ok = true; + for(size_t i = 0; i < m; i++) + s[i].clear(); + + // sparsity for s = jac_sparse_set_ * r + for(size_t i = 0; i < m; i++) + { // compute row i of the return pattern + local::sparse::list_setvec::const_iterator set_itr( + member_[thread]->jac_sparse_set_, i + ); + size_t j = *set_itr; + while(j < n ) + { std::set::const_iterator itr_j; + const std::set& r_j( r[j] ); + for(itr_j = r_j.begin(); itr_j != r_j.end(); itr_j++) + { size_t k = *itr_j; + CPPAD_ASSERT_UNKNOWN( k < q ); + s[i].insert(k); + } + j = *(++set_itr); + } + } + + return ok; +} + +} // END_CPPAD_NAMESPACE +# endif diff --git a/build-config/cppad/include/cppad/core/chkpoint_one/forward.hpp b/build-config/cppad/include/cppad/core/chkpoint_one/forward.hpp new file mode 100644 index 00000000..c058c346 --- /dev/null +++ b/build-config/cppad/include/cppad/core/chkpoint_one/forward.hpp @@ -0,0 +1,170 @@ +# ifndef CPPAD_CORE_CHKPOINT_ONE_FORWARD_HPP +# define CPPAD_CORE_CHKPOINT_ONE_FORWARD_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +namespace CppAD { // BEGIN_CPPAD_NAMESPACE + +// --------------------------------------------------------------------------- +template +bool checkpoint::forward( + size_t p , + size_t q , + const vector& vx , + vector& vy , + const vector& tx , + vector& ty ) +{ // make sure member_ is allocated for this thread + size_t thread = thread_alloc::thread_num(); + allocate_member(thread); + // + size_t n = member_[thread]->f_.Domain(); + size_t m = member_[thread]->f_.Range(); + // + CPPAD_ASSERT_UNKNOWN( member_[thread]->f_.size_var() > 0 ); + CPPAD_ASSERT_UNKNOWN( tx.size() % (q+1) == 0 ); + CPPAD_ASSERT_UNKNOWN( ty.size() % (q+1) == 0 ); + CPPAD_ASSERT_UNKNOWN( n == tx.size() / (q+1) ); + CPPAD_ASSERT_UNKNOWN( m == ty.size() / (q+1) ); + bool ok = true; + // + if( vx.size() == 0 ) + { // during user forward mode + if( member_[thread]->jac_sparse_set_.n_set() != 0 ) + member_[thread]->jac_sparse_set_.resize(0,0); + if( member_[thread]->jac_sparse_bool_.size() != 0 ) + member_[thread]->jac_sparse_bool_.clear(); + // + if( member_[thread]->hes_sparse_set_.n_set() != 0 ) + member_[thread]->hes_sparse_set_.resize(0,0); + if( member_[thread]->hes_sparse_bool_.size() != 0 ) + member_[thread]->hes_sparse_bool_.clear(); + } + if( vx.size() > 0 ) + { // need Jacobian sparsity pattern to determine variable relation + // during user recording using checkpoint functions + if( sparsity() == atomic_base::set_sparsity_enum ) + { if( member_[thread]->jac_sparse_set_.n_set() == 0 ) + set_jac_sparse_set(); + CPPAD_ASSERT_UNKNOWN( + member_[thread]->jac_sparse_set_.n_set() == m + ); + CPPAD_ASSERT_UNKNOWN( + member_[thread]->jac_sparse_set_.end() == n + ); + // + for(size_t i = 0; i < m; i++) + { vy[i] = false; + local::sparse::list_setvec::const_iterator set_itr( + member_[thread]->jac_sparse_set_, i + ); + size_t j = *set_itr; + while(j < n ) + { // y[i] depends on the value of x[j] + // cast avoid Microsoft warning (should not be needed) + vy[i] |= static_cast( vx[j] ); + j = *(++set_itr); + } + } + } + else + { if( member_[thread]->jac_sparse_set_.n_set() != 0 ) + member_[thread]->jac_sparse_set_.resize(0, 0); + if( member_[thread]->jac_sparse_bool_.size() == 0 ) + set_jac_sparse_bool(); + CPPAD_ASSERT_UNKNOWN( + member_[thread]->jac_sparse_set_.n_set() == 0 + ); + CPPAD_ASSERT_UNKNOWN( + member_[thread]->jac_sparse_bool_.size() == m * n + ); + // + for(size_t i = 0; i < m; i++) + { vy[i] = false; + for(size_t j = 0; j < n; j++) + { if( member_[thread]->jac_sparse_bool_[ i * n + j ] ) + { // y[i] depends on the value of x[j] + // cast avoid Microsoft warning + vy[i] |= static_cast( vx[j] ); + } + } + } + } + } + // compute forward results for orders zero through q + ty = member_[thread]->f_.Forward(q, tx); + + // no longer need the Taylor coefficients in f_ + // (have to reconstruct them every time) + // Hold onto sparsity pattern because it is always good. + size_t c = 0; + size_t r = 0; + member_[thread]->f_.capacity_order(c, r); + return ok; +} + +// --------------------------------------------------------------------------- +template +bool checkpoint::forward( + size_t p , + size_t q , + const vector& vx , + vector& vy , + const vector< AD >& atx , + vector< AD >& aty ) +{ // make sure member_ is allocated for this thread + size_t thread = thread_alloc::thread_num(); + allocate_member(thread); + // + // make sure af_ is defined + if( member_[thread]->af_.size_var() == 0 ) + member_[thread]->af_ = member_[thread]->f_.base2ad(); + // +# ifndef NDEBUG + size_t n = member_[thread]->f_.Domain(); + size_t m = member_[thread]->f_.Range(); +# endif + // + CPPAD_ASSERT_UNKNOWN( member_[thread]->f_.size_var() > 0 ); + CPPAD_ASSERT_UNKNOWN( atx.size() % (q+1) == 0 ); + CPPAD_ASSERT_UNKNOWN( aty.size() % (q+1) == 0 ); + CPPAD_ASSERT_UNKNOWN( n == atx.size() / (q+1) ); + CPPAD_ASSERT_UNKNOWN( m == aty.size() / (q+1) ); + CPPAD_ASSERT_UNKNOWN( vx.size() == 0 ) + bool ok = true; + // + // during user forward mode + if( member_[thread]->jac_sparse_set_.n_set() != 0 ) + member_[thread]->jac_sparse_set_.resize(0,0); + if( member_[thread]->jac_sparse_bool_.size() != 0 ) + member_[thread]->jac_sparse_bool_.clear(); + // + if( member_[thread]->hes_sparse_set_.n_set() != 0 ) + member_[thread]->hes_sparse_set_.resize(0,0); + if( member_[thread]->hes_sparse_bool_.size() != 0 ) + member_[thread]->hes_sparse_bool_.clear(); + // + // compute forward results for orders zero through q + aty = member_[thread]->af_.Forward(q, atx); + + // no longer need the Taylor coefficients in af_ + // (have to reconstruct them every time) + // Hold onto sparsity pattern because it is always good. + size_t c = 0; + size_t r = 0; + member_[thread]->af_.capacity_order(c, r); + // + return ok; +} + +} // END_CPPAD_NAMESPACE +# endif diff --git a/build-config/cppad/include/cppad/core/chkpoint_one/rev_sparse_hes.hpp b/build-config/cppad/include/cppad/core/chkpoint_one/rev_sparse_hes.hpp new file mode 100644 index 00000000..d28c16ab --- /dev/null +++ b/build-config/cppad/include/cppad/core/chkpoint_one/rev_sparse_hes.hpp @@ -0,0 +1,214 @@ +# ifndef CPPAD_CORE_CHKPOINT_ONE_REV_SPARSE_HES_HPP +# define CPPAD_CORE_CHKPOINT_ONE_REV_SPARSE_HES_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +namespace CppAD { // BEGIN_CPPAD_NAMESPACE + +template +template +bool checkpoint::rev_sparse_hes( + const vector& vx , + const vector& s , + vector& t , + size_t q , + const sparsity_type& r , + const sparsity_type& u , + sparsity_type& v , + const vector& x ) +{ // make sure member_ is allocated for this thread + size_t thread = thread_alloc::thread_num(); + allocate_member(thread); + // + size_t n = member_[thread]->f_.Domain(); +# ifndef NDEBUG + size_t m = member_[thread]->f_.Range(); +# endif + CPPAD_ASSERT_UNKNOWN( vx.size() == n ); + CPPAD_ASSERT_UNKNOWN( s.size() == m ); + CPPAD_ASSERT_UNKNOWN( t.size() == n ); + CPPAD_ASSERT_UNKNOWN( r.size() == n * q ); + CPPAD_ASSERT_UNKNOWN( u.size() == m * q ); + CPPAD_ASSERT_UNKNOWN( v.size() == n * q ); + // + bool ok = true; + + // make sure hes_sparse_bool_ has been set + if( member_[thread]->hes_sparse_bool_.size() == 0 ) + set_hes_sparse_bool(); + if( member_[thread]->hes_sparse_set_.n_set() != 0 ) + member_[thread]->hes_sparse_set_.resize(0, 0); + CPPAD_ASSERT_UNKNOWN( member_[thread]->hes_sparse_bool_.size() == n * n ); + CPPAD_ASSERT_UNKNOWN( member_[thread]->hes_sparse_set_.n_set() == 0 ); + + + // compute sparsity pattern for T(x) = S(x) * f'(x) + t = member_[thread]->f_.RevSparseJac(1, s); +# ifndef NDEBUG + for(size_t j = 0; j < n; j++) + CPPAD_ASSERT_UNKNOWN( vx[j] || ! t[j] ) +# endif + + // V(x) = f'(x)^T * g''(y) * f'(x) * R + g'(y) * f''(x) * R + // U(x) = g''(y) * f'(x) * R + // S(x) = g'(y) + + // compute sparsity pattern for A(x) = f'(x)^T * U(x) + bool transpose = true; + sparsity_type a(n * q); + a = member_[thread]->f_.RevSparseJac(q, u, transpose); + + // Need sparsity pattern for H(x) = (S(x) * f(x))''(x) * R, + // but use less efficient sparsity for f(x)''(x) * R so that + // hes_sparse_set_ can be used every time this is needed. + for(size_t i = 0; i < n; i++) + { for(size_t k = 0; k < q; k++) + { // initialize sparsity pattern for H(i,k) + bool h_ik = false; + // H(i,k) = sum_j f''(i,j) * R(j,k) + for(size_t j = 0; j < n; j++) + { bool f_ij = member_[thread]->hes_sparse_bool_[i * n + j]; + bool r_jk = r[j * q + k]; + h_ik |= ( f_ij & r_jk ); + } + // sparsity for H(i,k) + v[i * q + k] = h_ik; + } + } + + // compute sparsity pattern for V(x) = A(x) + H(x) + for(size_t i = 0; i < n; i++) + { for(size_t k = 0; k < q; k++) + // v[ i * q + k ] |= a[ i * q + k]; + v[ i * q + k ] = bool(v[ i * q + k]) | bool(a[ i * q + k]); + } + return ok; +} +template +bool checkpoint::rev_sparse_hes( + const vector& vx , + const vector& s , + vector& t , + size_t q , + const vectorBool& r , + const vectorBool& u , + vectorBool& v , + const vector& x ) +{ // make sure member_ is allocated for this thread + size_t thread = thread_alloc::thread_num(); + allocate_member(thread); + // + return rev_sparse_hes< vectorBool >(vx, s, t, q, r, u, v, x); +} +template +bool checkpoint::rev_sparse_hes( + const vector& vx , + const vector& s , + vector& t , + size_t q , + const vector& r , + const vector& u , + vector& v , + const vector& x ) +{ // make sure member_ is allocated for this thread + size_t thread = thread_alloc::thread_num(); + allocate_member(thread); + // + return rev_sparse_hes< vector >(vx, s, t, q, r, u, v, x); +} +template +bool checkpoint::rev_sparse_hes( + const vector& vx , + const vector& s , + vector& t , + size_t q , + const vector< std::set >& r , + const vector< std::set >& u , + vector< std::set >& v , + const vector& x ) +{ // make sure member_ is allocated for this thread + size_t thread = thread_alloc::thread_num(); + allocate_member(thread); + // + size_t n = member_[thread]->f_.Domain(); +# ifndef NDEBUG + size_t m = member_[thread]->f_.Range(); +# endif + CPPAD_ASSERT_UNKNOWN( vx.size() == n ); + CPPAD_ASSERT_UNKNOWN( s.size() == m ); + CPPAD_ASSERT_UNKNOWN( t.size() == n ); + CPPAD_ASSERT_UNKNOWN( r.size() == n ); + CPPAD_ASSERT_UNKNOWN( u.size() == m ); + CPPAD_ASSERT_UNKNOWN( v.size() == n ); + // + bool ok = true; + + // make sure hes_sparse_set_ has been set + if( member_[thread]->hes_sparse_bool_.size() != 0 ) + member_[thread]->hes_sparse_bool_.clear(); + if( member_[thread]->hes_sparse_set_.n_set() == 0 ) + set_hes_sparse_set(); + CPPAD_ASSERT_UNKNOWN( member_[thread]->hes_sparse_bool_.size() == 0 ); + CPPAD_ASSERT_UNKNOWN( member_[thread]->hes_sparse_set_.n_set() == n ); + CPPAD_ASSERT_UNKNOWN( member_[thread]->hes_sparse_set_.end() == n ); + + // compute sparsity pattern for T(x) = S(x) * f'(x) + t = member_[thread]->f_.RevSparseJac(1, s); +# ifndef NDEBUG + for(size_t j = 0; j < n; j++) + CPPAD_ASSERT_UNKNOWN( vx[j] || ! t[j] ) +# endif + + // V(x) = f'(x)^T * g''(y) * f'(x) * R + g'(y) * f''(x) * R + // U(x) = g''(y) * f'(x) * R + // S(x) = g'(y) + + // compute sparsity pattern for A(x) = f'(x)^T * U(x) + // 2DO: change a to use INTERNAL_SPARSE_SET + bool transpose = true; + vector< std::set > a(n); + a = member_[thread]->f_.RevSparseJac(q, u, transpose); + + // Need sparsity pattern for H(x) = (S(x) * f(x))''(x) * R, + // but use less efficient sparsity for f(x)''(x) * R so that + // hes_sparse_set_ can be used every time this is needed. + for(size_t i = 0; i < n; i++) + { v[i].clear(); + local::sparse::list_setvec::const_iterator set_itr( + member_[thread]->hes_sparse_set_, i + ); + size_t j = *set_itr; + while( j < n ) + { std::set::const_iterator itr_j; + const std::set& r_j( r[j] ); + for(itr_j = r_j.begin(); itr_j != r_j.end(); itr_j++) + { size_t k = *itr_j; + v[i].insert(k); + } + j = *(++set_itr); + } + } + // compute sparsity pattern for V(x) = A(x) + H(x) + std::set::const_iterator itr; + for(size_t i = 0; i < n; i++) + { for(itr = a[i].begin(); itr != a[i].end(); itr++) + { size_t j = *itr; + CPPAD_ASSERT_UNKNOWN( j < q ); + v[i].insert(j); + } + } + + return ok; +} + +} // END_CPPAD_NAMESPACE +# endif diff --git a/build-config/cppad/include/cppad/core/chkpoint_one/rev_sparse_jac.hpp b/build-config/cppad/include/cppad/core/chkpoint_one/rev_sparse_jac.hpp new file mode 100644 index 00000000..6a425163 --- /dev/null +++ b/build-config/cppad/include/cppad/core/chkpoint_one/rev_sparse_jac.hpp @@ -0,0 +1,139 @@ +# ifndef CPPAD_CORE_CHKPOINT_ONE_REV_SPARSE_JAC_HPP +# define CPPAD_CORE_CHKPOINT_ONE_REV_SPARSE_JAC_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +namespace CppAD { // BEGIN_CPPAD_NAMESPACE + +template +template +bool checkpoint::rev_sparse_jac( + size_t q , + const sparsity_type& rt , + sparsity_type& st , + const vector& x ) +{ // make sure member_ is allocated for this thread + size_t thread = thread_alloc::thread_num(); + allocate_member(thread); + // + // during user sparsity calculations + size_t m = member_[thread]->f_.Range(); + size_t n = member_[thread]->f_.Domain(); + if( member_[thread]->jac_sparse_bool_.size() == 0 ) + set_jac_sparse_bool(); + if( member_[thread]->jac_sparse_set_.n_set() != 0 ) + member_[thread]->jac_sparse_set_.resize(0, 0); + CPPAD_ASSERT_UNKNOWN( member_[thread]->jac_sparse_bool_.size() == m * n ); + CPPAD_ASSERT_UNKNOWN( member_[thread]->jac_sparse_set_.n_set() == 0 ); + CPPAD_ASSERT_UNKNOWN( rt.size() == m * q ); + CPPAD_ASSERT_UNKNOWN( st.size() == n * q ); + bool ok = true; + // + // S = R * J where J is jacobian + for(size_t i = 0; i < q; i++) + { for(size_t j = 0; j < n; j++) + { // initialize sparsity for S(i,j) + bool s_ij = false; + // S(i,j) = sum_k R(i,k) * J(k,j) + for(size_t k = 0; k < m; k++) + { // sparsity for R(i, k) + bool R_ik = rt[ k * q + i ]; + bool J_kj = member_[thread]->jac_sparse_bool_[ k * n + j ]; + s_ij |= (R_ik & J_kj); + } + // set sparsity for S^T + st[ j * q + i ] = s_ij; + } + } + return ok; +} +template +bool checkpoint::rev_sparse_jac( + size_t q , + const vectorBool& rt , + vectorBool& st , + const vector& x ) +{ // make sure member_ is allocated for this thread + size_t thread = thread_alloc::thread_num(); + allocate_member(thread); + // + return rev_sparse_jac< vectorBool >(q, rt, st, x); +} +template +bool checkpoint::rev_sparse_jac( + size_t q , + const vector& rt , + vector& st , + const vector& x ) +{ // make sure member_ is allocated for this thread + size_t thread = thread_alloc::thread_num(); + allocate_member(thread); + // + return rev_sparse_jac< vector >(q, rt, st, x); +} +template +bool checkpoint::rev_sparse_jac( + size_t q , + const vector< std::set >& rt , + vector< std::set >& st , + const vector& x ) +{ // make sure member_ is allocated for this thread + size_t thread = thread_alloc::thread_num(); + allocate_member(thread); + // + // during user sparsity calculations + size_t m = member_[thread]->f_.Range(); + size_t n = member_[thread]->f_.Domain(); + if( member_[thread]->jac_sparse_bool_.size() != 0 ) + member_[thread]->jac_sparse_bool_.clear(); + if( member_[thread]->jac_sparse_set_.n_set() == 0 ) + set_jac_sparse_set(); + CPPAD_ASSERT_UNKNOWN( member_[thread]->jac_sparse_bool_.size() == 0 ); + CPPAD_ASSERT_UNKNOWN( member_[thread]->jac_sparse_set_.n_set() == m ); + CPPAD_ASSERT_UNKNOWN( member_[thread]->jac_sparse_set_.end() == n ); + CPPAD_ASSERT_UNKNOWN( rt.size() == m ); + CPPAD_ASSERT_UNKNOWN( st.size() == n ); + // + bool ok = true; + // + for(size_t j = 0; j < n; j++) + st[j].clear(); + // + // sparsity for s = r * jac_sparse_set_ + // s^T = jac_sparse_set_^T * r^T + for(size_t i = 0; i < m; i++) + { // i is the row index in r^T + std::set::const_iterator itr_i; + const std::set& r_i( rt[i] ); + for(itr_i = r_i.begin(); itr_i != r_i.end(); itr_i++) + { // k is the column index in r^T + size_t k = *itr_i; + CPPAD_ASSERT_UNKNOWN( k < q ); + // + // i is column index in jac_sparse_set^T + local::sparse::list_setvec::const_iterator set_itr( + member_[thread]->jac_sparse_set_, i + ); + size_t j = *set_itr; + while( j < n ) + { // j is row index in jac_sparse_set^T + st[j].insert(k); + j = *(++set_itr); + } + } + } + + return ok; +} + +} // END_CPPAD_NAMESPACE +# endif diff --git a/build-config/cppad/include/cppad/core/chkpoint_one/reverse.hpp b/build-config/cppad/include/cppad/core/chkpoint_one/reverse.hpp new file mode 100644 index 00000000..654fddf8 --- /dev/null +++ b/build-config/cppad/include/cppad/core/chkpoint_one/reverse.hpp @@ -0,0 +1,125 @@ +# ifndef CPPAD_CORE_CHKPOINT_ONE_REVERSE_HPP +# define CPPAD_CORE_CHKPOINT_ONE_REVERSE_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-18 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +namespace CppAD { // BEGIN_CPPAD_NAMESPACE + +// --------------------------------------------------------------------------- +template +bool checkpoint::reverse( + size_t q , + const vector& tx , + const vector& ty , + vector& px , + const vector& py ) +{ // make sure member_ is allocated for this thread + size_t thread = thread_alloc::thread_num(); + allocate_member(thread); + // + +# ifndef NDEBUG + size_t n = member_[thread]->f_.Domain(); + size_t m = member_[thread]->f_.Range(); +# endif + CPPAD_ASSERT_UNKNOWN( member_[thread]->f_.size_var() > 0 ); + CPPAD_ASSERT_UNKNOWN( n == tx.size() / (q+1) ); + CPPAD_ASSERT_UNKNOWN( m == ty.size() / (q+1) ); + CPPAD_ASSERT_UNKNOWN( tx.size() % (q+1) == 0 ); + CPPAD_ASSERT_UNKNOWN( ty.size() % (q+1) == 0 ); + CPPAD_ASSERT_UNKNOWN( px.size() == n * (q+1) ); + CPPAD_ASSERT_UNKNOWN( py.size() == m * (q+1) ); + bool ok = true; + + // put proper forward mode coefficients in f_ +# ifdef NDEBUG + // compute forward results for orders zero through q + member_[thread]->f_.Forward(q, tx); +# else + size_t i, j, k; + // + // compute forward results for orders zero through q + vector check_ty = member_[thread]->f_.Forward(q, tx); + for(i = 0; i < m; i++) + { for(k = 0; k <= q; k++) + { j = i * (q+1) + k; + CPPAD_ASSERT_UNKNOWN( check_ty[j] == ty[j] ); + } + } +# endif + // now can run reverse mode + px = member_[thread]->f_.Reverse(q+1, py); + + // no longer need the Taylor coefficients in f_ + // (have to reconstruct them every time) + size_t c = 0; + size_t r = 0; + member_[thread]->f_.capacity_order(c, r); + return ok; +} +// --------------------------------------------------------------------------- +template +bool checkpoint::reverse( + size_t q , + const vector< AD >& atx , + const vector< AD >& aty , + vector< AD >& apx , + const vector< AD >& apy ) +{ // make sure member_ is allocated for this thread + size_t thread = thread_alloc::thread_num(); + allocate_member(thread); + // + // make sure af_ is defined + if( member_[thread]->af_.size_var() == 0 ) + member_[thread]->af_ = member_[thread]->f_.base2ad(); +# ifndef NDEBUG + size_t n = member_[thread]->f_.Domain(); + size_t m = member_[thread]->f_.Range(); +# endif + CPPAD_ASSERT_UNKNOWN( member_[thread]->f_.size_var() > 0 ); + CPPAD_ASSERT_UNKNOWN( n == atx.size() / (q+1) ); + CPPAD_ASSERT_UNKNOWN( m == aty.size() / (q+1) ); + CPPAD_ASSERT_UNKNOWN( atx.size() % (q+1) == 0 ); + CPPAD_ASSERT_UNKNOWN( aty.size() % (q+1) == 0 ); + CPPAD_ASSERT_UNKNOWN( apx.size() == n * (q+1) ); + CPPAD_ASSERT_UNKNOWN( apy.size() == m * (q+1) ); + bool ok = true; + + // put proper forward mode coefficients in f_ +# ifdef NDEBUG + // compute forward results for orders zero through q + member_[thread]->af_.Forward(q, atx); +# else + size_t i, j, k; + // + // compute forward results for orders zero through q + vector< AD > check_aty = member_[thread]->af_.Forward(q, atx); + for(i = 0; i < m; i++) + { for(k = 0; k <= q; k++) + { j = i * (q+1) + k; + CPPAD_ASSERT_UNKNOWN( check_aty[j] == aty[j] ); + } + } +# endif + // now can run reverse mode + apx = member_[thread]->af_.Reverse(q+1, apy); + + // no longer need the Taylor coefficients in f_ + // (have to reconstruct them every time) + size_t c = 0; + size_t r = 0; + member_[thread]->af_.capacity_order(c, r); + return ok; +} + +} // END_CPPAD_NAMESPACE +# endif diff --git a/build-config/cppad/include/cppad/core/chkpoint_one/set_hes_sparse_bool.hpp b/build-config/cppad/include/cppad/core/chkpoint_one/set_hes_sparse_bool.hpp new file mode 100644 index 00000000..33c43197 --- /dev/null +++ b/build-config/cppad/include/cppad/core/chkpoint_one/set_hes_sparse_bool.hpp @@ -0,0 +1,53 @@ +# ifndef CPPAD_CORE_CHKPOINT_ONE_SET_HES_SPARSE_BOOL_HPP +# define CPPAD_CORE_CHKPOINT_ONE_SET_HES_SPARSE_BOOL_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-18 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +namespace CppAD { // BEGIN_CPPAD_NAMESPACE + +template +void checkpoint::set_hes_sparse_bool(void) +{ // make sure member_ is allocated for this thread + size_t thread = thread_alloc::thread_num(); + allocate_member(thread); + // + CPPAD_ASSERT_UNKNOWN( member_[thread]->hes_sparse_bool_.size() == 0 ); + size_t n = member_[thread]->f_.Domain(); + size_t m = member_[thread]->f_.Range(); + // + // set version of sparsity for vector of all ones + vectorBool all_one(m); + for(size_t i = 0; i < m; i++) + all_one[i] = true; + + // set version of sparsity for n by n idendity matrix + vectorBool identity(n * n); + for(size_t j = 0; j < n; j++) + { for(size_t i = 0; i < n; i++) + identity[ i * n + j ] = (i == j); + } + + // compute sparsity pattern for H(x) = sum_i f_i(x)^{(2)} + bool transpose = false; + bool dependency = false; + member_[thread]->f_.ForSparseJac(n, identity, transpose, dependency); + member_[thread]->hes_sparse_bool_ = member_[thread]->f_.RevSparseHes(n, all_one, transpose); + CPPAD_ASSERT_UNKNOWN( member_[thread]->hes_sparse_bool_.size() == n * n ); + // + // drop the forward sparsity results from f_ + member_[thread]->f_.size_forward_bool(0); + CPPAD_ASSERT_UNKNOWN( member_[thread]->f_.size_forward_bool() == 0 ); + CPPAD_ASSERT_UNKNOWN( member_[thread]->f_.size_forward_set() == 0 ); +} + +} // END_CPPAD_NAMESPACE +# endif diff --git a/build-config/cppad/include/cppad/core/chkpoint_one/set_hes_sparse_set.hpp b/build-config/cppad/include/cppad/core/chkpoint_one/set_hes_sparse_set.hpp new file mode 100644 index 00000000..d153b5a8 --- /dev/null +++ b/build-config/cppad/include/cppad/core/chkpoint_one/set_hes_sparse_set.hpp @@ -0,0 +1,57 @@ +# ifndef CPPAD_CORE_CHKPOINT_ONE_SET_HES_SPARSE_SET_HPP +# define CPPAD_CORE_CHKPOINT_ONE_SET_HES_SPARSE_SET_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +namespace CppAD { // BEGIN_CPPAD_NAMESPACE + +template +void checkpoint::set_hes_sparse_set(void) +{ // make sure member_ is allocated for this thread + size_t thread = thread_alloc::thread_num(); + allocate_member(thread); + // + CPPAD_ASSERT_UNKNOWN( member_[thread]->hes_sparse_set_.n_set() == 0 ); + size_t n = member_[thread]->f_.Domain(); + size_t m = member_[thread]->f_.Range(); + // + // set version of sparsity for vector of all ones + vector all_one(m); + for(size_t i = 0; i < m; i++) + all_one[i] = true; + + // set version of sparsity for n by n idendity matrix + local::sparse::list_setvec identity; + identity.resize(n, n); + for(size_t j = 0; j < n; j++) + { // Not using post_element because only adding one element per set + identity.add_element(j, j); + } + + // compute sparsity pattern for H(x) = sum_i f_i(x)^{(2)} + bool transpose = false; + bool dependency = false; + member_[thread]->f_.ForSparseJacCheckpoint( + n, identity, transpose, dependency, member_[thread]->jac_sparse_set_ + ); + member_[thread]->f_.RevSparseHesCheckpoint( + n, all_one, transpose, member_[thread]->hes_sparse_set_ + ); + CPPAD_ASSERT_UNKNOWN( member_[thread]->hes_sparse_set_.n_set() == n ); + CPPAD_ASSERT_UNKNOWN( member_[thread]->hes_sparse_set_.end() == n ); + // + // drop the forward sparsity results from f_ + member_[thread]->f_.size_forward_set(0); +} + +} // END_CPPAD_NAMESPACE +# endif diff --git a/build-config/cppad/include/cppad/core/chkpoint_one/set_jac_sparse_bool.hpp b/build-config/cppad/include/cppad/core/chkpoint_one/set_jac_sparse_bool.hpp new file mode 100644 index 00000000..3c640ba7 --- /dev/null +++ b/build-config/cppad/include/cppad/core/chkpoint_one/set_jac_sparse_bool.hpp @@ -0,0 +1,56 @@ +# ifndef CPPAD_CORE_CHKPOINT_ONE_SET_JAC_SPARSE_BOOL_HPP +# define CPPAD_CORE_CHKPOINT_ONE_SET_JAC_SPARSE_BOOL_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-18 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +namespace CppAD { // BEGIN_CPPAD_NAMESPACE + +template +void checkpoint::set_jac_sparse_bool(void) +{ // make sure member_ is allocated for this thread + size_t thread = thread_alloc::thread_num(); + allocate_member(thread); + // + CPPAD_ASSERT_UNKNOWN( member_[thread]->jac_sparse_bool_.size() == 0 ); + bool transpose = false; + bool dependency = true; + size_t n = member_[thread]->f_.Domain(); + size_t m = member_[thread]->f_.Range(); + // Use the choice for forward / reverse that results in smaller + // size for the sparsity pattern of all variables in the tape. + if( n <= m ) + { vectorBool identity(n * n); + for(size_t j = 0; j < n; j++) + { for(size_t i = 0; i < n; i++) + identity[ i * n + j ] = (i == j); + } + member_[thread]->jac_sparse_bool_ = member_[thread]->f_.ForSparseJac( + n, identity, transpose, dependency + ); + member_[thread]->f_.size_forward_bool(0); + } + else + { vectorBool identity(m * m); + for(size_t j = 0; j < m; j++) + { for(size_t i = 0; i < m; i++) + identity[ i * m + j ] = (i == j); + } + member_[thread]->jac_sparse_bool_ = member_[thread]->f_.RevSparseJac( + m, identity, transpose, dependency + ); + } + CPPAD_ASSERT_UNKNOWN( member_[thread]->f_.size_forward_bool() == 0 ); + CPPAD_ASSERT_UNKNOWN( member_[thread]->f_.size_forward_set() == 0 ); +} + +} // END_CPPAD_NAMESPACE +# endif diff --git a/build-config/cppad/include/cppad/core/chkpoint_one/set_jac_sparse_set.hpp b/build-config/cppad/include/cppad/core/chkpoint_one/set_jac_sparse_set.hpp new file mode 100644 index 00000000..c138e9f5 --- /dev/null +++ b/build-config/cppad/include/cppad/core/chkpoint_one/set_jac_sparse_set.hpp @@ -0,0 +1,58 @@ +# ifndef CPPAD_CORE_CHKPOINT_ONE_SET_JAC_SPARSE_SET_HPP +# define CPPAD_CORE_CHKPOINT_ONE_SET_JAC_SPARSE_SET_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +namespace CppAD { // BEGIN_CPPAD_NAMESPACE + +template +void checkpoint::set_jac_sparse_set(void) +{ // make sure member_ is allocated for this thread + size_t thread = thread_alloc::thread_num(); + allocate_member(thread); + // + CPPAD_ASSERT_UNKNOWN( member_[thread]->jac_sparse_set_.n_set() == 0 ); + bool transpose = false; + bool dependency = true; + size_t n = member_[thread]->f_.Domain(); + size_t m = member_[thread]->f_.Range(); + // Use the choice for forward / reverse that results in smaller + // size for the sparsity pattern of all variables in the tape. + if( n <= m ) + { local::sparse::list_setvec identity; + identity.resize(n, n); + for(size_t j = 0; j < n; j++) + { // Not using post_element because only adding one element per set + identity.add_element(j, j); + } + member_[thread]->f_.ForSparseJacCheckpoint( + n, identity, transpose, dependency, member_[thread]->jac_sparse_set_ + ); + member_[thread]->f_.size_forward_set(0); + } + else + { local::sparse::list_setvec identity; + identity.resize(m, m); + for(size_t i = 0; i < m; i++) + { // Not using post_element because only adding one element per set + identity.add_element(i, i); + } + member_[thread]->f_.RevSparseJacCheckpoint( + m, identity, transpose, dependency, member_[thread]->jac_sparse_set_ + ); + } + CPPAD_ASSERT_UNKNOWN( member_[thread]->f_.size_forward_set() == 0 ); + CPPAD_ASSERT_UNKNOWN( member_[thread]->f_.size_forward_bool() == 0 ); +} + +} // END_CPPAD_NAMESPACE +# endif diff --git a/build-config/cppad/include/cppad/core/chkpoint_two/chk_fun.omh b/build-config/cppad/include/cppad/core/chkpoint_two/chk_fun.omh new file mode 100644 index 00000000..bb449f53 --- /dev/null +++ b/build-config/cppad/include/cppad/core/chkpoint_two/chk_fun.omh @@ -0,0 +1,65 @@ +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-18 Bradley M. Bell + + CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + + This Source Code may also be made available under the following + Secondary License when the conditions for such availability set forth + in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +-------------------------------------------------------------------------- */ +$begin chkpoint_two_chk_fun$$ + +$spell + const + chk + chkpoint +$$ + +$section Using Checkpoint Functions$$ + +$head Syntax$$ +$icode%chk_fun%(%ax%, %ay%)%$$ + +$head Purpose$$ +Given $icode ax$$, +this call computes the corresponding value of $icode ay$$. +If $codei%AD<%Base%>%$$ operations are being recorded, +it enters the computation as an $cref atomic_three$$ +operation in the recording; +see $cref/start recording/Independent/Start Recording/$$. + +$head chk_fun$$ +This object must have been created using the +$cref/chkpoint_two/chkpoint_two_ctor/chk_fun/$$ constructor. + +$head ADVector$$ +The type $icode ADVector$$ must be a +$cref/simple vector class/SimpleVector/$$ with elements of type +$codei%AD<%Base%>%$$. + +$head ax$$ +This argument has prototype +$codei% + const %ADVector%& ax +%$$ +and its size equal to $icode%n% = %fun%.Domain()%$$ +where $cref/fun/chkpoint_two_ctor/fun/$$ is the $codei%ADFun<%Base%>%$$ +function in used the constructor for $icode chk_fun$$. +It specifies vector $latex x \in \B{R}^n$$ +at which we are computing an $codei%AD<%Base%>%$$ version of +$latex y = g(x)$$. + +$head ay$$ +This argument has prototype +$codei% + %ADVector%& ay +%$$ +and its size must be equal to $icode%m% = %fun%.Range()%$$. +The input values of its elements do not matter. +Upon return, it is an $codei%AD<%Base%>%$$ version of +$latex y = g(x)$$. + + +$end diff --git a/build-config/cppad/include/cppad/core/chkpoint_two/chkpoint_two.hpp b/build-config/cppad/include/cppad/core/chkpoint_two/chkpoint_two.hpp new file mode 100644 index 00000000..b89b0283 --- /dev/null +++ b/build-config/cppad/include/cppad/core/chkpoint_two/chkpoint_two.hpp @@ -0,0 +1,311 @@ +# ifndef CPPAD_CORE_CHKPOINT_TWO_CHKPOINT_TWO_HPP +# define CPPAD_CORE_CHKPOINT_TWO_CHKPOINT_TWO_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +namespace CppAD { // BEGIN_CPPAD_NAMESPACE +/*! +\file chkpoint_two.hpp +Second generation checkpoint functions. +*/ + +/* +$begin chkpoint_two$$ +$spell + CppAD + chk + chkpoint + hpp + cppad + bool + hes +$$ + +$section Checkpoint Functions: Second Generation$$ + +$head Syntax$$ + +$subhead Constructor$$ +$codei%chkpoint_two<%Base%> %chk_fun%( %fun%, %name%, + %internal_bool%, %use_hes_sparsity%, %use_base2ad%, %use_in_parallel% +)%$$ + +$subhead Use Checkpoint Function$$ +$codei% %chk_fun%(%ax%, %ay%)%$$ + +$subhead new_dynamic$$ +$icode%chk_fun%.new_dynamic(%dynamic%)%$$ + +$head Reduce Memory$$ +You can reduce the size of the tape and memory required for AD +using a checkpoint representation of a function +$latex g : \B{R}^n \rightarrow \B{R}^m$$. + +$head Faster Recording$$ +It may also reduce the time to make a recording if the same $latex g(x)$$ +is used many times (with different values) during the +recording of an $codei%ADFun<%Base%>%$$ object. + +$head Repeating Forward$$ +Normally, CppAD stores $cref forward$$ mode results, +until they freed using $cref capacity_order$$, +or the corresponding $cref ADFun$$ object is deleted. +This is not true for $code chkpoint_two$$ functions +because the same checkpoint function may be used repeatedly +with different arguments during a single forward mode operation. +Thus, forward mode results are computed for each use of $icode chk_fun$$ +in a forward mode sweep. + +$head Operation Sequence$$ +The $cref/operation sequence/glossary/Operation/Sequence/$$ +representing $latex g(x)$$ is fixed; i.e., +it cannot depend on the value of $latex x$$. + +$head atomic_three$$ +The $code chkpoint_two$$ class is derived from $code atomic_three$$, +hence some of its error message will refer to atomic operations. +The $code chkpoint_two$$ class implements all the +$cref/virtual functions/atomic_three/Virtual Functions/$$ +and hence its source code, +$codei% + include/cppad/core/chkpoint_two/chkpoint_two.hpp +%$$ +provides an example for $cref atomic_three$$ operations. +The difference is that $code chkpoint_two.hpp$$ uses AD +instead of user provided derivatives. + +$head Base$$ +The type $icode Base$$ specifies the base type for AD operations; +i.e., $icode chk_fun$$ can be used during the recording of +$codei%AD<%Base%>%$$ operations. + + +$childtable%include/cppad/core/chkpoint_two/ctor.hpp + %include/cppad/core/chkpoint_two/chk_fun.omh + %include/cppad/core/chkpoint_two/dynamic.hpp + %example/chkpoint_two/get_started.cpp + %example/chkpoint_two/compare.cpp + %example/chkpoint_two/base2ad.cpp + %example/chkpoint_two/dynamic.cpp + %example/chkpoint_two/ode.cpp +%$$ + +$end +*/ + +template +class chkpoint_two : public atomic_three { +// --------------------------------------------------------------------------- +private: + /// are sparsity calculations using bools or sets of integers + const bool internal_bool_; + // + /// can this checkpoint function calculate Hessian sparsity patterns + const bool use_hes_sparsity_; + // + /// can this checkpoint function be used in base2ad recordings + const bool use_base2ad_; + // + /// can this checkpoint function be used in parallel mode + const bool use_in_parallel_; + // + /// Jacobian sparsity for g(x) with dependncy true. + /// This is set by the constructor and constant after that. + sparse_rc< vector > jac_sparsity_; + // + /// Hessian sparsity for g(x). If use_hes_sparsity_ is true, + /// This is set by the constructor and constant after that. + sparse_rc< vector > hes_sparsity_; + // + /// Function corresponding to this checkpoint object. + /// If use_in_parallel_, this is constant after the constructor. + ADFun g_; + // + /// AD version of function corresponding to this checkpoint object + /// If use_in_parallel_, this is constant after the constructor. + ADFun< AD, Base> ag_; + // ------------------------------------------------------------------------ + // member_ + // ------------------------------------------------------------------------ + /// If use_in_parallel_ is true, must have a separate copy member data + /// that is not constant. + struct member_struct { + // + /// function corresponding to this checkpoint object + ADFun g_; + // + /// AD version of this function object + ADFun< AD, Base > ag_; + // + }; + /// use pointers and allocate memory to avoid false sharing + /// (initialized to null by constructor) + member_struct* member_[CPPAD_MAX_NUM_THREADS]; + // + // ------------------------------------------------------------------------ + /// allocate member_ for this thread + void allocate_member(size_t thread) + { CPPAD_ASSERT_UNKNOWN( use_in_parallel_ ); + if( member_[thread] == nullptr ) + { // allocaate raw memory + size_t min_bytes = sizeof(member_struct); + size_t num_bytes; + void* v_ptr = thread_alloc::get_memory(min_bytes, num_bytes); + // convert to member_struct* + member_[thread] = reinterpret_cast(v_ptr); + // call member_struct constructor + new( member_[thread] ) member_struct; + // + // The thread has a copy of corresponding informaiton. + member_[thread]->g_ = g_; + member_[thread]->ag_ = ag_; + } + return; + } + // + // ------------------------------------------------------------------------ + /// free member_ for this thread + void free_member(size_t thread) + { if( member_[thread] != nullptr ) + { // call destructor + member_[thread]->~member_struct(); + // return raw m,emory to available pool for this thread + void* v_ptr = reinterpret_cast(member_[thread]); + thread_alloc::return_memory(v_ptr); + // mark member for this thread as not allocated + member_[thread] = nullptr; + } + return; + } + // ----------------------------------------------------------------------- + // atomic_three virtual functions + // ------------------------------------------------------------------------ + // type + virtual bool for_type( + const vector& parameter_x , + const vector& type_x , + vector& type_y + ); + // forward + virtual bool forward( + const vector& parameter_x , + const vector& type_x , + size_t need_y , + size_t order_low , + size_t order_up , + const vector& taylor_x , + vector& taylor_y + ); + // AD forward + virtual bool forward( + const vector< AD >& aparameter_x , + const vector& type_x , + size_t need_y , + size_t order_low , + size_t order_up , + const vector< AD >& ataylor_x , + vector< AD >& ataylor_y + ); + // reverse + virtual bool reverse( + const vector& parameter_x , + const vector& type_x , + size_t order_up , + const vector& taylor_x , + const vector& taylor_y , + vector& partial_x , + const vector& partial_y + ); + // AD reverse + virtual bool reverse( + const vector< AD >& aparameter_x , + const vector& type_x , + size_t order_up , + const vector< AD >& ataylor_x , + const vector< AD >& ataylor_y , + vector< AD >& apartial_x , + const vector< AD >& apartial_y + ); + // jac_sparsity + virtual bool jac_sparsity( + const vector& parameter_x , + const vector& type_x , + bool dependency , + const vector& select_x , + const vector& select_y , + sparse_rc< vector >& pattern_out + ); + // hes_sparsity + virtual bool hes_sparsity( + const vector& parameter_x , + const vector& type_x , + const vector& select_x , + const vector& select_y , + sparse_rc< vector >& pattern_out + ); + // rev_depend + virtual bool rev_depend( + const vector& parameter_x , + const vector& type_x , + vector& depend_x , + const vector& depend_y + ); +public: + // ctor + chkpoint_two( + const ADFun& fun , + const std::string& name , + bool internal_bool , + bool use_hes_sparsity , + bool use_base2ad , + bool use_in_parallel + ); + // + // destructor + ~chkpoint_two(void); + // + // assignment operator + void operator=(const chkpoint_two& other) + { CPPAD_ASSERT_KNOWN(false, + "cannot use chkpoint_two assignment operator" + ); + } + // copy constructor + chkpoint_two(const chkpoint_two& other) + : + internal_bool_ ( other.internal_bool_ ) , + use_hes_sparsity_ ( other.use_hes_sparsity_ ) , + use_base2ad_ ( other.use_base2ad_ ) , + use_in_parallel_ ( other.use_in_parallel_ ) , + jac_sparsity_ ( other.jac_sparsity_ ) , + hes_sparsity_ ( other.hes_sparsity_ ) + { g_ = other.g_; + ag_ = other.ag_; + } + // + // new_dynamic + template + void new_dynamic(const BaseVector& dynamic); +}; + +} // END_CPPAD_NAMESPACE + +# include +# include +# include +# include +# include +# include +# include +# include + +# endif diff --git a/build-config/cppad/include/cppad/core/chkpoint_two/ctor.hpp b/build-config/cppad/include/cppad/core/chkpoint_two/ctor.hpp new file mode 100644 index 00000000..96421da1 --- /dev/null +++ b/build-config/cppad/include/cppad/core/chkpoint_two/ctor.hpp @@ -0,0 +1,222 @@ +# ifndef CPPAD_CORE_CHKPOINT_TWO_CTOR_HPP +# define CPPAD_CORE_CHKPOINT_TWO_CTOR_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ +/* +$begin chkpoint_two_ctor$$ +$spell + chkpoint + chk + bool + hes +$$ + +$section Checkpoint Function Constructor$$ + +$head Syntax$$ +$codei%chkpoint_two<%Base%> %chk_fun%( %fun%, %name%, + %internal_bool%, %use_hes_sparsity%, %use_base2ad%, %use_in_parallel% +)%$$ + +$head Prototype$$ +$srcthisfile% + 0%// BEGIN_PROTOTYPE%// END_PROTOTYPE%1 +%$$ + +$head Parallel$$ +This constructor, and its corresponding destructor, must not be called in +$cref/parallel/ta_in_parallel/$$ mode. +The object $icode chk_fun$$ should not be destructed for as long as there is +an $codei%ADFun<%Base%>%$$ object the has $icode chk_fun$$ in its recording. + +$head Base$$ +The type $icode Base$$ specifies the base type for AD operations. + +$head fun$$ +This specifies the function $latex g(x)$$. +Note that $icode fun$$ may or may not have been +$cref/optimized/optimize/$$ before calling the constructor. +This will determine if the internal representation for $icode g(x)$$ +is optimized. + +$head name$$ +is the name used for reporting errors using this checkpoint function. + +$head internal_bool$$ +If true, sparsity calculations are done with sets represented +by vectors of boolean values. +Otherwise, vectors of sets are used for sparsity patterns. + +$head use_hes_sparsity$$ +If true, Hessian sparsity patterns can be calculated for +$codei%ADFun<%Base%>%$$ objects that have uses of $icode chk_fun$$ +in their recording. +This requires some extra memory and extra computation during the constructor. + +$head use_base2ad$$ +If this is true, $icode chk_fun$$ can be used during the recording +of $codei%ADFun<%Base%>%$$ objects that get converted to +$codei%ADFun< AD<%Base%> >%$$ objects using $cref base2ad$$. +This requires some extra memory and extra computation during the constructor. + +$head use_in_parallel$$ +If this is true, $icode chk_fun$$ can be used +$cref/in_parallel/ta_parallel_setup/in_parallel/$$. +This requires some extra memory for a constant copy of the $icode fun$$ +information and a separate copy (that changes) for each thread. + +$head chk_fun$$ +This is a checkpoint function representation of $latex g(x)$$ +that can be used during the recording of $codei%AD<%Base%>%$$ operations. + +$end +*/ +namespace CppAD { // BEGIN_CPPAD_NAMESPACE +/*! +\file chkpoint_two/ctor.hpp +Constructor for chkpoint_two class. +*/ + +/*! +Constructor + +\tparam Base +base class for recording AD operations using this checkpoint object. + +\param fun +is the function g(x) corresponding to this checkpoint object. + +\param name +is the name used for error reporting. + +\param internal_bool +should sparisity calculations be done using bools (or sets). + +\param use_hes_sparsity +will this checkpoint function be used with Hessian sparsity calculations. + +\param use_base2ad +will this checkpoint function be used with base2ad. + +\param use_in_parallel +will this checkpoint function be used in parallel mode. +*/ + +// BEGIN_PROTOTYPE +template +chkpoint_two::chkpoint_two( + const ADFun& fun , + const std::string& name , + bool internal_bool , + bool use_hes_sparsity , + bool use_base2ad , + bool use_in_parallel ) +// END_PROTOTYPE +: +atomic_three(name) , +internal_bool_( internal_bool ) , +use_hes_sparsity_( use_hes_sparsity ) , +use_base2ad_ ( use_base2ad ) , +use_in_parallel_ ( use_in_parallel ) +{ CPPAD_ASSERT_KNOWN( + ! thread_alloc::in_parallel() , + "chkpoint_two: constructor cannot be called in parallel mode." + ); + // initialize member pointers as null; + for(size_t thread = 0; thread < CPPAD_MAX_NUM_THREADS; thread++) + member_[thread] = nullptr; + // + // g_ + g_ = fun; + // + // suppress check for nan because chkpoint_two object can be used in a + // function that gets optimized and some checkpoint results may not matter. + g_.check_for_nan(false); + // + // ag_ + if( use_base2ad ) + ag_ = g_.base2ad(); + // + // jac_sparsity__ + size_t n = g_.Domain(); + size_t m = g_.Range(); + sparse_rc< vector > pattern_in; + bool transpose = false; + bool dependency = true; + if( n <= m || use_hes_sparsity ) + { // use forward mode + pattern_in.resize(n, n, n); + for(size_t k = 0; k < n; ++k) + pattern_in.set(k, k, k); + g_.for_jac_sparsity( + pattern_in, + transpose, + dependency, + internal_bool, + jac_sparsity_ + ); + } + else + { // use reverse mode + pattern_in.resize(m, m, m); + for(size_t k = 0; k < m; ++k) + pattern_in.set(k, k, k); + g_.rev_jac_sparsity( + pattern_in, + transpose, + dependency, + internal_bool, + jac_sparsity_ + ); + } + // + // hes_sparsity_ + if( use_hes_sparsity ) + { vector select_y(m), select_x(n); + for(size_t i = 0; i < m; ++i) + select_y[i] = true; + if( n <= m ) + { for(size_t j = 0; j < n; ++j) + select_x[j] = true; + g_.for_hes_sparsity( + select_x, select_y, internal_bool, hes_sparsity_ + ); + } + else + { // forward jacobian sparsity is stored in g_ + g_.rev_hes_sparsity( + select_y, transpose, internal_bool, hes_sparsity_ + ); + } + } + // free memory holding forward Jacobian sparsity + if( internal_bool ) + g_.size_forward_bool(0); + else + g_.size_forward_set(0); +} +/// destructor +template +chkpoint_two::~chkpoint_two(void) +{ +# ifndef NDEBUG + if( thread_alloc::in_parallel() ) + { std::string msg = atomic_three::atomic_name(); + msg += ": chkpoint_two destructor called in parallel mode."; + CPPAD_ASSERT_KNOWN(false, msg.c_str() ); + } +# endif + for(size_t thread = 0; thread < CPPAD_MAX_NUM_THREADS; ++thread) + free_member(thread); + } +} // END_CPPAD_NAMESPACE +# endif diff --git a/build-config/cppad/include/cppad/core/chkpoint_two/dynamic.hpp b/build-config/cppad/include/cppad/core/chkpoint_two/dynamic.hpp new file mode 100644 index 00000000..6ce7f702 --- /dev/null +++ b/build-config/cppad/include/cppad/core/chkpoint_two/dynamic.hpp @@ -0,0 +1,102 @@ +# ifndef CPPAD_CORE_CHKPOINT_TWO_DYNAMIC_HPP +# define CPPAD_CORE_CHKPOINT_TWO_DYNAMIC_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ +/* +$begin chkpoint_two_dynamic$$ +$spell + chk + chkpoint + dyn_ind +$$ + +$section Dynamic Parameters in Checkpoint Functions$$ + +$head Syntax$$ +$icode%chk_fun%.new_dynamic(%dynamic%)%$$ + +$head Prototype$$ +$srcthisfile% + 0%// BEGIN_PROTOTYPE%// END_PROTOTYPE%1 +%$$ + +$head chk_fun$$ +This object must have been created using the +$cref/chkpoint_two/chkpoint_two_ctor/chk_fun/$$ constructor. + +$subhead Base$$ +This is the $cref/Base/chkpoint_two_ctor/Base/$$ type +in the $icode chk_fun$$ constructor. + +$subhead fun$$ +This is the function $cref/fun/chkpoint_two_ctor/fun/$$ +in the $icode chk_fun$$ constructor. + +$head BaseVector$$ +This must be a $cref SimpleVector$$ with elements of type $icode Base$$. + +$head dynamic$$ +This is a vector with new values for the dynamic parameters +in the function $icode fun$$. +Is size must be equal to +$cref/fun.size_dyn_ind()/seq_property/size_dyn_par/$$. +This only affects the copy of $icode fun$$ used by $icode chk_fun$$. + +$head Multi-Threading$$ +If one is using $cref/in_parallel/ta_in_parallel/$$, +there is a separate copy of $icode fun$$ for each thread. +In this case, only the dynamic parameters in the copy for the current +$cref/thread number/ta_thread_num/$$ are changed. + + +$end +*/ +namespace CppAD { // BEGIN_CPPAD_NAMESPACE +/*! +\file chkpoint_two/dynamic.hpp +Change the dynnamic parameter in a checkpoint function. +*/ + +/*! +Constructor + +\tparam Base +base class for recording AD operations using this checkpoint object. + +\param dynamic +is the new values for the dynamic parameters in the function +defining this checkpoint object. +*/ + +// BEGIN_PROTOTYPE +template +template +void chkpoint_two::new_dynamic(const BaseVector& dynamic) +// END_PROTOTYPE +{ ADFun* g_ptr = &g_; + if( use_in_parallel_ ) + { size_t thread = thread_alloc::thread_num(); + allocate_member(thread); + g_ptr = &(member_[thread]->g_); + } +# ifndef NDEBUG + else if( thread_alloc::in_parallel() ) + { std::string msg = atomic_three::atomic_name(); + msg += ": use_in_parallel is false and in_parallel() is true"; + CPPAD_ASSERT_KNOWN(false, msg.c_str() ); + } +# endif + g_ptr->new_dynamic(dynamic); +} + +} // END_CPPAD_NAMESPACE +# endif diff --git a/build-config/cppad/include/cppad/core/chkpoint_two/for_type.hpp b/build-config/cppad/include/cppad/core/chkpoint_two/for_type.hpp new file mode 100644 index 00000000..34e6f51c --- /dev/null +++ b/build-config/cppad/include/cppad/core/chkpoint_two/for_type.hpp @@ -0,0 +1,63 @@ +# ifndef CPPAD_CORE_CHKPOINT_TWO_FOR_TYPE_HPP +# define CPPAD_CORE_CHKPOINT_TWO_FOR_TYPE_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-18 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +namespace CppAD { // BEGIN_CPPAD_NAMESPACE +/*! +\file chkpoint_two/for_type.hpp +Second generation checkpoint type computation. +*/ +/*! +Link from atomic_three to type calculation + +\param parameter_x [in] +is the value of the parameters in the corresponding function call +afun(ax, ay). + +\param type_x [in] +specifies which components of x are +constants, dynamics, and variables + +\param type_y [out] +specifies which components of y are +constants, dynamics, and variables +*/ +template +bool chkpoint_two::for_type( + const vector& parameter_x , + const vector& type_x , + vector& type_y ) +{ size_t nr = jac_sparsity_.nr(); + size_t nnz = jac_sparsity_.nnz(); + const vector& row( jac_sparsity_.row() ); + const vector& col( jac_sparsity_.col() ); + // + CPPAD_ASSERT_UNKNOWN( jac_sparsity_.nr() == type_y.size() ); + CPPAD_ASSERT_UNKNOWN( jac_sparsity_.nc() == type_x.size() ); + // + // initialize type_y as constant_enum + for(size_t i = 0; i < nr; ++i) + type_y[i] = constant_enum; + // + // loop over entries in Dependency pattern + for(size_t k = 0; k < nnz; ++k) + { size_t i = row[k]; + size_t j = col[k]; + type_y[i] = std::max(type_y[i], type_x[j]); + } + return true; +} + +} // END_CPPAD_NAMESPACE + +# endif diff --git a/build-config/cppad/include/cppad/core/chkpoint_two/forward.hpp b/build-config/cppad/include/cppad/core/chkpoint_two/forward.hpp new file mode 100644 index 00000000..c80211d5 --- /dev/null +++ b/build-config/cppad/include/cppad/core/chkpoint_two/forward.hpp @@ -0,0 +1,130 @@ +# ifndef CPPAD_CORE_CHKPOINT_TWO_FORWARD_HPP +# define CPPAD_CORE_CHKPOINT_TWO_FORWARD_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ +namespace CppAD { // BEGIN_CPPAD_NAMESPACE +/*! +\file chkpoint_two/forward.hpp +Second generation checkpoint forward mode. +*/ +/*! +Link from chkpoint_two to forward mode + +\param parameter_x [in] +contains the values, in afun(ax, ay), for arguments that are parameters. + +\param type_x [in] +what is the type, in afun(ax, ay), for each component of x. + +\param need_y [in] +specifies which components of taylor_y are needed, + +\param order_low [in] +lowerest order for this forward mode calculation. + +\param order_up [in] +highest order for this forward mode calculation. + +\param taylor_x [in] +Taylor coefficients corresponding to x for this calculation. + +\param taylor_y [out] +Taylor coefficient corresponding to y for this calculation + +See the forward mode in user's documentation for atomic_three +*/ +template +bool chkpoint_two::forward( + const vector& parameter_x , + const vector& type_x , + size_t need_y , + size_t order_low , + size_t order_up , + const vector& taylor_x , + vector& taylor_y ) +{ ADFun* g_ptr = &g_; + if( use_in_parallel_ ) + { size_t thread = thread_alloc::thread_num(); + allocate_member(thread); + g_ptr = &(member_[thread]->g_); + } +# ifndef NDEBUG + else if( thread_alloc::in_parallel() ) + { std::string msg = atomic_three::atomic_name(); + msg += ": use_in_parallel is false and in_parallel() is true"; + CPPAD_ASSERT_KNOWN(false, msg.c_str() ); + } +# endif + // compute forward mode results for all values and orders + taylor_y = g_ptr->Forward(order_up, taylor_x); + // + return true; +} +/*! +Link from chkpoint_two to AD forward mode + +\param aparameter_x [in] +contains the values, in afun(ax, ay), for arguments that are parameters. + +\param type_x [in] +what is the type, in afun(ax, ay), for each component of x. + +\param need_y [in] +specifies which components of taylor_y are needed, + +\param order_low [in] +lowerest order for this forward mode calculation. + +\param order_up [in] +highest order for this forward mode calculation. + +\param ataylor_x [in] +Taylor coefficients corresponding to x for this calculation. + +\param ataylor_y [out] +Taylor coefficient corresponding to y for this calculation + +See the forward mode in user's documentation for atomic_three +*/ +template +bool chkpoint_two::forward( + const vector< AD >& aparameter_x , + const vector& type_x , + size_t need_y , + size_t order_low , + size_t order_up , + const vector< AD >& ataylor_x , + vector< AD >& ataylor_y ) +{ if( ! use_base2ad_ ) + return false; + // + ADFun< AD, Base >* ag_ptr = &ag_; + if( use_in_parallel_ ) + { size_t thread = thread_alloc::thread_num(); + allocate_member(thread); + ag_ptr = &(member_[thread]->ag_); + } +# ifndef NDEBUG + else if( thread_alloc::in_parallel() ) + { std::string msg = atomic_three::atomic_name(); + msg += ": use_in_parallel is false and in_parallel() is true"; + CPPAD_ASSERT_KNOWN(false, msg.c_str() ); + } +# endif + // compute forward mode results for all values and orders + ataylor_y = ag_ptr->Forward(order_up, ataylor_x); + // + return true; +} + +} // END_CPPAD_NAMESPACE +# endif diff --git a/build-config/cppad/include/cppad/core/chkpoint_two/hes_sparsity.hpp b/build-config/cppad/include/cppad/core/chkpoint_two/hes_sparsity.hpp new file mode 100644 index 00000000..3e54b696 --- /dev/null +++ b/build-config/cppad/include/cppad/core/chkpoint_two/hes_sparsity.hpp @@ -0,0 +1,86 @@ +# ifndef CPPAD_CORE_CHKPOINT_TWO_HES_SPARSITY_HPP +# define CPPAD_CORE_CHKPOINT_TWO_HES_SPARSITY_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ +namespace CppAD { // BEGIN_CPPAD_NAMESPACE +/*! +\file chkpoint_two/hes_sparsity.hpp +Second generation checkpoint Jacobian sparsity patterns. +*/ +/*! +chkpoint_two to Hessian sparsity calculations. + +\param parameter_x [in] +contains the values for arguments that are parameters. + +\param type_x [in] +what is the type, in afun(ax, ay), for each component of x. + +\param select_x [in] +which domain components to include in the dependency or sparsity pattern. +The index zero is used for parameters. + +\param select_y [in] +which range components to include in the dependency or sparsity pattern. +The index zero is used for parameters. +This argument is ignored because the sparsity pattern corresponding to +all components true is computed during the construction and used for all cases. +This errors on the side of caution for the sake of speed. + + +\param pattern_out [out] +is the dependency or sparsity pattern. +*/ +// BEGIN_PROTOTYPE +template +bool chkpoint_two::hes_sparsity( + const vector& parameter_x , + const vector& type_x , + const vector& select_x , + const vector& select_y , + sparse_rc< vector >& pattern_out ) +// END_PROTOTYPE +{ CPPAD_ASSERT_UNKNOWN( hes_sparsity_.nr() == select_x.size() ); + CPPAD_ASSERT_UNKNOWN( hes_sparsity_.nc() == select_x.size() ); + if( ! use_hes_sparsity_ ) + return false; + + // count number of non-zeros + size_t nnz = hes_sparsity_.nnz(); + size_t nr = hes_sparsity_.nr(); + size_t nc = hes_sparsity_.nc(); + const vector& row = hes_sparsity_.row(); + const vector& col = hes_sparsity_.col(); + size_t nnz_out = 0; + for(size_t k = 0; k < nnz; ++k) + { size_t i = row[k]; + size_t j = col[k]; + if( select_x[j] & select_x[i] ) + ++nnz_out; + } + + // set the output sparsity pattern + pattern_out.resize(nr, nc, nnz_out); + size_t ell = 0; + for(size_t k = 0; k < nnz; ++k) + { size_t i = row[k]; + size_t j = col[k]; + if( select_x[j] & select_x[i] ) + pattern_out.set(ell++, i, j); + } + CPPAD_ASSERT_UNKNOWN( ell == nnz_out ); + // + return true; +} + +} // END_CPPAD_NAMESPACE +# endif diff --git a/build-config/cppad/include/cppad/core/chkpoint_two/jac_sparsity.hpp b/build-config/cppad/include/cppad/core/chkpoint_two/jac_sparsity.hpp new file mode 100644 index 00000000..1d1ef1e7 --- /dev/null +++ b/build-config/cppad/include/cppad/core/chkpoint_two/jac_sparsity.hpp @@ -0,0 +1,86 @@ +# ifndef CPPAD_CORE_CHKPOINT_TWO_JAC_SPARSITY_HPP +# define CPPAD_CORE_CHKPOINT_TWO_JAC_SPARSITY_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-18 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ +namespace CppAD { // BEGIN_CPPAD_NAMESPACE +/*! +\file chkpoint_two/jac_sparsity.hpp +Second generation checkpoint Jacobian sparsity patterns. +*/ +/*! +chkpoint_two to Jacobian sparsity calculations. + +\param dependency [in] +This argument is ignored. +The return pattern is always a dependency pattern which is a correct, +but possibly not efficient, sparsity pattern. + +\param parameter_x [in] +contains the values for arguments that are parameters. + +\param type_x [in] +what is the type, in afun(ax, ay), for each component of x. + +\param select_x [in] +which domain components to include in the dependency or sparsity pattern. +The index zero is used for parameters. + +\param select_y [in] +which range components to include in the dependency or sparsity pattern. +The index zero is used for parameters. + +\param pattern_out [out] +is the dependency or sparsity pattern. +*/ +// BEGIN_PROTOTYPE +template +bool chkpoint_two::jac_sparsity( + const vector& parameter_x , + const vector& type_x , + bool dependency , + const vector& select_x , + const vector& select_y , + sparse_rc< vector >& pattern_out ) +// END_PROTOTYPE +{ CPPAD_ASSERT_UNKNOWN( jac_sparsity_.nr() == select_y.size() ); + CPPAD_ASSERT_UNKNOWN( jac_sparsity_.nc() == select_x.size() ); + + // count number of non-zeros + size_t nnz = jac_sparsity_.nnz(); + size_t nr = jac_sparsity_.nr(); + size_t nc = jac_sparsity_.nc(); + const vector& row = jac_sparsity_.row(); + const vector& col = jac_sparsity_.col(); + size_t nnz_out = 0; + for(size_t k = 0; k < nnz; ++k) + { size_t i = row[k]; + size_t j = col[k]; + if( select_x[j] & select_y[i] ) + ++nnz_out; + } + + // set the output sparsity pattern + pattern_out.resize(nr, nc, nnz_out); + size_t ell = 0; + for(size_t k = 0; k < nnz; ++k) + { size_t i = row[k]; + size_t j = col[k]; + if( select_x[j] & select_y[i] ) + pattern_out.set(ell++, i, j); + } + CPPAD_ASSERT_UNKNOWN( ell == nnz_out ); + // + return true; +} + +} // END_CPPAD_NAMESPACE +# endif diff --git a/build-config/cppad/include/cppad/core/chkpoint_two/rev_depend.hpp b/build-config/cppad/include/cppad/core/chkpoint_two/rev_depend.hpp new file mode 100644 index 00000000..9c11634c --- /dev/null +++ b/build-config/cppad/include/cppad/core/chkpoint_two/rev_depend.hpp @@ -0,0 +1,66 @@ +# ifndef CPPAD_CORE_CHKPOINT_TWO_REV_DEPEND_HPP +# define CPPAD_CORE_CHKPOINT_TWO_REV_DEPEND_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-18 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +namespace CppAD { // BEGIN_CPPAD_NAMESPACE +/*! +\file chkpoint_two/rev_depend.hpp +Second generation checkpoint type computation. +*/ +/*! +Link from atomic_three to dependency calculation + +\param parameter_x [in] +is the value of the parameters in the corresponding function call +afun(ax, ay). + +\param type_x [in] +is the AD type for ax in the corresponding afun(ax, ay) call. + +\param depend_x [out] +specifies which components of x affect the values of interest + +\param depend_y [in] +specifies which components of y affect the vlaues of interest +*/ +template +bool chkpoint_two::rev_depend( + const vector& parameter_x , + const vector& type_x , + vector& depend_x , + const vector& depend_y ) +{ size_t nc = jac_sparsity_.nc(); + size_t nnz = jac_sparsity_.nnz(); + const vector& row( jac_sparsity_.row() ); + const vector& col( jac_sparsity_.col() ); + // + CPPAD_ASSERT_UNKNOWN( jac_sparsity_.nr() == depend_y.size() ); + CPPAD_ASSERT_UNKNOWN( jac_sparsity_.nc() == depend_x.size() ); + // + // initialize depend_x as false + for(size_t j = 0; j < nc; ++j) + depend_x[j] = false; + // + // loop over entries in Dependency pattern + for(size_t k = 0; k < nnz; ++k) + { size_t i = row[k]; + size_t j = col[k]; + if( depend_y[i] ) + depend_x[j] = true; + } + return true; +} + +} // END_CPPAD_NAMESPACE + +# endif diff --git a/build-config/cppad/include/cppad/core/chkpoint_two/reverse.hpp b/build-config/cppad/include/cppad/core/chkpoint_two/reverse.hpp new file mode 100644 index 00000000..5506c3e5 --- /dev/null +++ b/build-config/cppad/include/cppad/core/chkpoint_two/reverse.hpp @@ -0,0 +1,139 @@ +# ifndef CPPAD_CORE_CHKPOINT_TWO_REVERSE_HPP +# define CPPAD_CORE_CHKPOINT_TWO_REVERSE_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ +namespace CppAD { // BEGIN_CPPAD_NAMESPACE +/*! +\file chkpoint_two/reverse.hpp +Second generation checkpoint reverse mode. +*/ +/*! +Link from chkpoint_two to reverse mode + +\param parameter_x [in] +contains the values, in afun(ax, ay), for arguments that are parameters. + +\param type_x [in] +what is the type, in afun(ax, ay), for each component of x. + +\param order_up [in] +highest order Taylor coefficient aht we are computing derivative of + +\param taylor_x [in] +Taylor coefficients corresponding to x for this calculation. + +\param taylor_y [in] +Taylor coefficient corresponding to y for this calculation + +\param partial_x [out] +Partials w.r.t. the x Taylor coefficients. + +\param partial_y [in] +Partials w.r.t. the y Taylor coefficients. + +See the reverse mode in user's documentation for atomic_three +*/ +template +bool chkpoint_two::reverse( + const vector& parameter_x , + const vector& type_x , + size_t order_up , + const vector& taylor_x , + const vector& taylor_y , + vector& partial_x , + const vector& partial_y ) + +{ ADFun* g_ptr = &g_; + if( use_in_parallel_ ) + { size_t thread = thread_alloc::thread_num(); + allocate_member(thread); + g_ptr = &(member_[thread]->g_); + } +# ifndef NDEBUG + else if( thread_alloc::in_parallel() ) + { std::string msg = atomic_three::atomic_name(); + msg += ": use_in_parallel is false and in_parallel() is true"; + CPPAD_ASSERT_KNOWN(false, msg.c_str() ); + } +# endif + // compute forward mode Taylor coefficient orders 0 through order_up +# ifdef NDEBUG + g_ptr->Forward(order_up, taylor_x); +# else + vector check = g_ptr->Forward(order_up, taylor_x); + CPPAD_ASSERT_UNKNOWN( taylor_y.size() == check.size() ) + for(size_t i = 0; i < taylor_y.size(); ++i) + CPPAD_ASSERT_UNKNOWN( taylor_y[i] == check[i] ); +# endif + // now can run reverse mode + partial_x = g_ptr->Reverse(order_up+1, partial_y); + // + return true; +} +/*! +Link from chkpoint_two to AD reverse mode + +\param aparameter_x [in] +contains the values, in afun(ax, ay), for arguments that are parameters. + +\param type_x [in] +what is the type, in afun(ax, ay), for each component of x. + +\param order_up [in] +highest order Taylor coefficient aht we are computing derivative of + +\param ataylor_x [in] +Taylor coefficients corresponding to x for this calculation. + +\param ataylor_y [in] +Taylor coefficient corresponding to y for this calculation + +\param apartial_x [out] +Partials w.r.t. the x Taylor coefficients. + +\param apartial_y [in] +Partials w.r.t. the y Taylor coefficients. + +See the reverse mode in user's documentation for atomic_three +*/ +template +bool chkpoint_two::reverse( + const vector< AD >& aparameter_x , + const vector& type_x , + size_t order_up , + const vector< AD >& ataylor_x , + const vector< AD >& ataylor_y , + vector< AD >& apartial_x , + const vector< AD >& apartial_y ) +{ ADFun< AD, Base >* ag_ptr = &ag_; + if( use_in_parallel_ ) + { size_t thread = thread_alloc::thread_num(); + allocate_member(thread); + ag_ptr = &(member_[thread]->ag_); + } + // compute forward mode Taylor coefficient orders 0 through order_up +# ifdef NDEBUG + ag_ptr->Forward(order_up, ataylor_x); +# else + vector< AD > acheck = ag_ptr->Forward(order_up, ataylor_x); + CPPAD_ASSERT_UNKNOWN( ataylor_y.size() == acheck.size() ) + for(size_t i = 0; i < ataylor_y.size(); ++i) + CPPAD_ASSERT_UNKNOWN( ataylor_y[i] == acheck[i] ); +# endif + // now can run reverse mode + apartial_x = ag_ptr->Reverse(order_up+1, apartial_y); + // + return true; +} + +} // END_CPPAD_NAMESPACE +# endif diff --git a/build-config/cppad/include/cppad/core/compare.hpp b/build-config/cppad/include/cppad/core/compare.hpp new file mode 100644 index 00000000..2a81cb4d --- /dev/null +++ b/build-config/cppad/include/cppad/core/compare.hpp @@ -0,0 +1,635 @@ +# ifndef CPPAD_CORE_COMPARE_HPP +# define CPPAD_CORE_COMPARE_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +/* +------------------------------------------------------------------------------- +$begin Compare$$ +$spell + cos + Op + bool + const +$$ + + + +$section AD Binary Comparison Operators$$ + + +$head Syntax$$ + +$icode%b% = %x% %Op% %y%$$ + + +$head Purpose$$ +Compares two operands where one of the operands is an +$codei%AD<%Base%>%$$ object. +The comparison has the same interpretation as for +the $icode Base$$ type. + + +$head Op$$ +The operator $icode Op$$ is one of the following: +$table +$bold Op$$ $pre $$ $cnext $bold Meaning$$ $rnext +$code <$$ $cnext is $icode x$$ less than $icode y$$ $rnext +$code <=$$ $cnext is $icode x$$ less than or equal $icode y$$ $rnext +$code >$$ $cnext is $icode x$$ greater than $icode y$$ $rnext +$code >=$$ $cnext is $icode x$$ greater than or equal $icode y$$ $rnext +$code ==$$ $cnext is $icode x$$ equal to $icode y$$ $rnext +$code !=$$ $cnext is $icode x$$ not equal to $icode y$$ +$tend + +$head x$$ +The operand $icode x$$ has prototype +$codei% + const %Type% &%x% +%$$ +where $icode Type$$ is $codei%AD<%Base%>%$$, $icode Base$$, or $code int$$. + +$head y$$ +The operand $icode y$$ has prototype +$codei% + const %Type% &%y% +%$$ +where $icode Type$$ is $codei%AD<%Base%>%$$, $icode Base$$, or $code int$$. + +$head b$$ +The result $icode b$$ has type +$codei% + bool %b% +%$$ + +$head Operation Sequence$$ +The result of this operation is a $code bool$$ value +(not an $cref/AD of Base/glossary/AD of Base/$$ object). +Thus it will not be recorded as part of an +AD of $icode Base$$ +$cref/operation sequence/glossary/Operation/Sequence/$$. +$pre + +$$ +For example, suppose +$icode x$$ and $icode y$$ are $codei%AD<%Base%>%$$ objects, +the tape corresponding to $codei%AD<%Base%>%$$ is recording, +$icode b$$ is true, +and the subsequent code is +$codei% + if( %b% ) + %y% = cos(%x%); + else + %y% = sin(%x%); +%$$ +only the assignment $icode%y% = cos(%x%)%$$ is recorded on the tape +(if $icode x$$ is a $cref/parameter/glossary/Parameter/$$, +nothing is recorded). +The $cref CompareChange$$ function can yield +some information about changes in comparison operation results. +You can use $cref CondExp$$ to obtain comparison operations +that depends on the +$cref/independent variable/glossary/Tape/Independent Variable/$$ +values with out re-taping the AD sequence of operations. + +$head Assumptions$$ +If one of the $icode Op$$ operators listed above +is used with an $codei%AD<%Base%>%$$ object, +it is assumed that the same operator is supported by the base type +$icode Base$$. + +$head Example$$ +$children% + example/general/compare.cpp +%$$ +The file +$cref compare.cpp$$ +contains an example and test of these operations. + +$end +------------------------------------------------------------------------------- +*/ +// BEGIN CppAD namespace +namespace CppAD { +// -------------------------------- < -------------------------- +template +CPPAD_INLINE_FRIEND_TEMPLATE_FUNCTION +bool operator < (const AD &left , const AD &right) +{ bool result = (left.value_ < right.value_); + // + // check if we are recording compare operators + local::ADTape *tape = AD::tape_ptr(); + if( tape == nullptr ) + return result; + if( ! tape->Rec_.get_record_compare() ) + return result; + tape_id_t tape_id = tape->id_; + // tape_id cannot match the default value for tape_id_; i.e., 0 + CPPAD_ASSERT_UNKNOWN( tape_id > 0 ); + + // check if left and right tapes match + bool match_left = left.tape_id_ == tape_id; + bool match_right = right.tape_id_ == tape_id; + + // check if left and right are dynamic parameters + bool dyn_left = match_left & (left.ad_type_ == dynamic_enum); + bool dyn_right = match_right & (right.ad_type_ == dynamic_enum); + + // check if left and right are variables + bool var_left = match_left & (left.ad_type_ != dynamic_enum); + bool var_right = match_right & (right.ad_type_ != dynamic_enum); + + CPPAD_ASSERT_KNOWN( + left.tape_id_ == right.tape_id_ || ! match_left || ! match_right , + "< : AD variables or dynamic parameters on different threads." + ); + if( var_left ) + { if( var_right ) + { // variable < variable + if( result ) + { tape->Rec_.PutOp(local::LtvvOp); + tape->Rec_.PutArg(left.taddr_, right.taddr_); + } + else + { tape->Rec_.PutOp(local::LevvOp); + tape->Rec_.PutArg(right.taddr_, left.taddr_); + } + } + else + { // variable < parameter + addr_t p = right.taddr_; + if( ! dyn_right ) + p = tape->Rec_.put_con_par(right.value_); + if( result ) + { tape->Rec_.PutOp(local::LtvpOp); + tape->Rec_.PutArg(left.taddr_, p); + } + else + { tape->Rec_.PutOp(local::LepvOp); + tape->Rec_.PutArg(p, left.taddr_); + } + } + } + else if ( var_right ) + { // parameter < variable + addr_t p = left.taddr_; + if( ! dyn_left ) + p = tape->Rec_.put_con_par(left.value_); + if( result ) + { tape->Rec_.PutOp(local::LtpvOp); + tape->Rec_.PutArg(p, right.taddr_); + } + else + { tape->Rec_.PutOp(local::LevpOp); + tape->Rec_.PutArg(right.taddr_, p); + } + } + else if( dyn_left | dyn_right ) + { // parameter < parameter + addr_t arg0 = left.taddr_; + addr_t arg1 = right.taddr_; + if( ! dyn_left ) + arg0 = tape->Rec_.put_con_par(left.value_); + if( ! dyn_right ) + arg1 = tape->Rec_.put_con_par(right.value_); + // + if( result ) + { tape->Rec_.PutOp(local::LtppOp); + tape->Rec_.PutArg(arg0, arg1); + } + else + { tape->Rec_.PutOp(local::LeppOp); + tape->Rec_.PutArg(arg1, arg0); + } + } + return result; +} +// convert other cases into the case above +CPPAD_FOLD_BOOL_VALUED_BINARY_OPERATOR(<) + +// -------------------------------- <= -------------------------- +template +CPPAD_INLINE_FRIEND_TEMPLATE_FUNCTION +bool operator <= (const AD &left , const AD &right) +{ bool result = (left.value_ <= right.value_); + // + // check if we are recording compare operators + local::ADTape *tape = AD::tape_ptr(); + if( tape == nullptr ) + return result; + if( ! tape->Rec_.get_record_compare() ) + return result; + tape_id_t tape_id = tape->id_; + // tape_id cannot match the default value for tape_id_; i.e., 0 + CPPAD_ASSERT_UNKNOWN( tape_id > 0 ); + + // check if left and right tapes match + bool match_left = left.tape_id_ == tape_id; + bool match_right = right.tape_id_ == tape_id; + + // check if left and right are dynamic parameters + bool dyn_left = match_left & (left.ad_type_ == dynamic_enum); + bool dyn_right = match_right & (right.ad_type_ == dynamic_enum); + + // check if left and right are variables + bool var_left = match_left & (left.ad_type_ != dynamic_enum); + bool var_right = match_right & (right.ad_type_ != dynamic_enum); + + CPPAD_ASSERT_KNOWN( + left.tape_id_ == right.tape_id_ || ! match_left || ! match_right , + "<= : AD variables or dynamic parameters on different threads." + ); + if( var_left ) + { if( var_right ) + { // variable <= variable + if( result ) + { tape->Rec_.PutOp(local::LevvOp); + tape->Rec_.PutArg(left.taddr_, right.taddr_); + } + else + { tape->Rec_.PutOp(local::LtvvOp); + tape->Rec_.PutArg(right.taddr_, left.taddr_); + } + } + else + { // variable <= parameter + addr_t p = right.taddr_; + if( ! dyn_right ) + p = tape->Rec_.put_con_par(right.value_); + if( result ) + { tape->Rec_.PutOp(local::LevpOp); + tape->Rec_.PutArg(left.taddr_, p); + } + else + { tape->Rec_.PutOp(local::LtpvOp); + tape->Rec_.PutArg(p, left.taddr_); + } + } + } + else if ( var_right ) + { // parameter <= variable + addr_t p = left.taddr_; + if( ! dyn_left ) + p = tape->Rec_.put_con_par(left.value_); + if( result ) + { tape->Rec_.PutOp(local::LepvOp); + tape->Rec_.PutArg(p, right.taddr_); + } + else + { tape->Rec_.PutOp(local::LtvpOp); + tape->Rec_.PutArg(right.taddr_, p); + } + } + else if( dyn_left | dyn_right ) + { // parameter <= parameter + addr_t arg0 = left.taddr_; + addr_t arg1 = right.taddr_; + if( ! dyn_left ) + arg0 = tape->Rec_.put_con_par(left.value_); + if( ! dyn_right ) + arg1 = tape->Rec_.put_con_par(right.value_); + // + if( result ) + { tape->Rec_.PutOp(local::LeppOp); + tape->Rec_.PutArg(arg0, arg1); + } + else + { tape->Rec_.PutOp(local::LtppOp); + tape->Rec_.PutArg(arg1, arg0); + } + } + return result; +} +// convert other cases into the case above +CPPAD_FOLD_BOOL_VALUED_BINARY_OPERATOR(<=) + +// -------------------------------- > -------------------------- +template +CPPAD_INLINE_FRIEND_TEMPLATE_FUNCTION +bool operator > (const AD &left , const AD &right) +{ bool result = (left.value_ > right.value_); + // + // check if we are recording compare operators + local::ADTape *tape = AD::tape_ptr(); + if( tape == nullptr ) + return result; + if( ! tape->Rec_.get_record_compare() ) + return result; + tape_id_t tape_id = tape->id_; + // tape_id cannot match the default value for tape_id_; i.e., 0 + CPPAD_ASSERT_UNKNOWN( tape_id > 0 ); + + // check if left and right tapes match + bool match_left = left.tape_id_ == tape_id; + bool match_right = right.tape_id_ == tape_id; + + // check if left and right are dynamic parameters + bool dyn_left = match_left & (left.ad_type_ == dynamic_enum); + bool dyn_right = match_right & (right.ad_type_ == dynamic_enum); + + // check if left and right are variables + bool var_left = match_left & (left.ad_type_ != dynamic_enum); + bool var_right = match_right & (right.ad_type_ != dynamic_enum); + + CPPAD_ASSERT_KNOWN( + left.tape_id_ == right.tape_id_ || ! match_left || ! match_right , + "> : AD variables or dynamic parameters on different threads." + ); + if( var_left ) + { if( var_right ) + { // variable > variable + if( result ) + { tape->Rec_.PutOp(local::LtvvOp); + tape->Rec_.PutArg(right.taddr_, left.taddr_); + } + else + { tape->Rec_.PutOp(local::LevvOp); + tape->Rec_.PutArg(left.taddr_, right.taddr_); + } + } + else + { // variable > parameter + addr_t p = right.taddr_; + if( ! dyn_right ) + p = tape->Rec_.put_con_par(right.value_); + if( result ) + { tape->Rec_.PutOp(local::LtpvOp); + tape->Rec_.PutArg(p, left.taddr_); + } + else + { tape->Rec_.PutOp(local::LevpOp); + tape->Rec_.PutArg(left.taddr_, p); + } + } + } + else if ( var_right ) + { // parameter > variable + addr_t p = left.taddr_; + if( ! dyn_left ) + p = tape->Rec_.put_con_par(left.value_); + if( result ) + { tape->Rec_.PutOp(local::LtvpOp); + tape->Rec_.PutArg(right.taddr_, p); + } + else + { tape->Rec_.PutOp(local::LepvOp); + tape->Rec_.PutArg(p, right.taddr_); + } + } + else if( dyn_left | dyn_right ) + { // parameter > parameter + addr_t arg0 = left.taddr_; + addr_t arg1 = right.taddr_; + if( ! dyn_left ) + arg0 = tape->Rec_.put_con_par(left.value_); + if( ! dyn_right ) + arg1 = tape->Rec_.put_con_par(right.value_); + // + if( result ) + { tape->Rec_.PutOp(local::LtppOp); + tape->Rec_.PutArg(arg1, arg0); + } + else + { tape->Rec_.PutOp(local::LeppOp); + tape->Rec_.PutArg(arg0, arg1); + } + } + return result; +} +// convert other cases into the case above +CPPAD_FOLD_BOOL_VALUED_BINARY_OPERATOR(>) + +// -------------------------------- >= -------------------------- +template +CPPAD_INLINE_FRIEND_TEMPLATE_FUNCTION +bool operator >= (const AD &left , const AD &right) +{ bool result = (left.value_ >= right.value_); + // + // check if we are recording compare operators + local::ADTape *tape = AD::tape_ptr(); + if( tape == nullptr ) + return result; + if( ! tape->Rec_.get_record_compare() ) + return result; + tape_id_t tape_id = tape->id_; + // tape_id cannot match the default value for tape_id_; i.e., 0 + CPPAD_ASSERT_UNKNOWN( tape_id > 0 ); + + // check if left and right tapes match + bool match_left = left.tape_id_ == tape_id; + bool match_right = right.tape_id_ == tape_id; + + // check if left and right are dynamic parameters + bool dyn_left = match_left & (left.ad_type_ == dynamic_enum); + bool dyn_right = match_right & (right.ad_type_ == dynamic_enum); + + // check if left and right are variables + bool var_left = match_left & (left.ad_type_ != dynamic_enum); + bool var_right = match_right & (right.ad_type_ != dynamic_enum); + + CPPAD_ASSERT_KNOWN( + left.tape_id_ == right.tape_id_ || ! match_left || ! match_right , + ">= : AD variables or dynamic parameters on different threads." + ); + if( var_left ) + { if( var_right ) + { // variable >= variable + if( result ) + { tape->Rec_.PutOp(local::LevvOp); + tape->Rec_.PutArg(right.taddr_, left.taddr_); + } + else + { tape->Rec_.PutOp(local::LtvvOp); + tape->Rec_.PutArg(left.taddr_, right.taddr_); + } + } + else + { // variable >= parameter + addr_t p = right.taddr_; + if( ! dyn_right ) + p = tape->Rec_.put_con_par(right.value_); + if( result ) + { tape->Rec_.PutOp(local::LepvOp); + tape->Rec_.PutArg(p, left.taddr_); + } + else + { tape->Rec_.PutOp(local::LtvpOp); + tape->Rec_.PutArg(left.taddr_, p); + } + } + } + else if ( var_right ) + { // parameter >= variable + addr_t p = left.taddr_; + if( ! dyn_left ) + p = tape->Rec_.put_con_par(left.value_); + if( result ) + { tape->Rec_.PutOp(local::LevpOp); + tape->Rec_.PutArg(right.taddr_, p); + } + else + { tape->Rec_.PutOp(local::LtpvOp); + tape->Rec_.PutArg(p, right.taddr_); + } + } + else if( dyn_left | dyn_right ) + { // parameter >= parameter + addr_t arg0 = left.taddr_; + addr_t arg1 = right.taddr_; + if( ! dyn_left ) + arg0 = tape->Rec_.put_con_par(left.value_); + if( ! dyn_right ) + arg1 = tape->Rec_.put_con_par(right.value_); + // + if( result ) + { tape->Rec_.PutOp(local::LeppOp); + tape->Rec_.PutArg(arg1, arg0); + } + else + { tape->Rec_.PutOp(local::LtppOp); + tape->Rec_.PutArg(arg0, arg1); + } + } + return result; +} +// convert other cases into the case above +CPPAD_FOLD_BOOL_VALUED_BINARY_OPERATOR(>=) + +// -------------------------------- == ------------------------- +template +CPPAD_INLINE_FRIEND_TEMPLATE_FUNCTION +bool operator == (const AD &left , const AD &right) +{ bool result = (left.value_ == right.value_); + // + // check if we are recording compare operators + local::ADTape *tape = AD::tape_ptr(); + if( tape == nullptr ) + return result; + if( ! tape->Rec_.get_record_compare() ) + return result; + tape_id_t tape_id = tape->id_; + // tape_id cannot match the default value for tape_id_; i.e., 0 + CPPAD_ASSERT_UNKNOWN( tape_id > 0 ); + + // check if left and right tapes match + bool match_left = left.tape_id_ == tape_id; + bool match_right = right.tape_id_ == tape_id; + + // check if left and right are dynamic parameters + bool dyn_left = match_left & (left.ad_type_ == dynamic_enum); + bool dyn_right = match_right & (right.ad_type_ == dynamic_enum); + + // check if left and right are variables + bool var_left = match_left & (left.ad_type_ != dynamic_enum); + bool var_right = match_right & (right.ad_type_ != dynamic_enum); + + CPPAD_ASSERT_KNOWN( + left.tape_id_ == right.tape_id_ || ! match_left || ! match_right , + "==: AD variables or dynamic parameters on different threads." + ); + // + tape->Rec_.comp_eq( + var_left, var_right, dyn_left, dyn_right, left, right, result + ); + // + return result; +} +// convert other cases into the case above +CPPAD_FOLD_BOOL_VALUED_BINARY_OPERATOR(==) + +// -------------------------------- != ------------------------- +template +CPPAD_INLINE_FRIEND_TEMPLATE_FUNCTION +bool operator != (const AD &left , const AD &right) +{ bool result = (left.value_ != right.value_); + // + // check if we are recording compare operators + local::ADTape *tape = AD::tape_ptr(); + if( tape == nullptr ) + return result; + if( ! tape->Rec_.get_record_compare() ) + return result; + tape_id_t tape_id = tape->id_; + // tape_id cannot match the default value for tape_id_; i.e., 0 + CPPAD_ASSERT_UNKNOWN( tape_id > 0 ); + + // check if left and right tapes match + bool match_left = left.tape_id_ == tape_id; + bool match_right = right.tape_id_ == tape_id; + + // check if left and right are dynamic parameters + bool dyn_left = match_left & (left.ad_type_ == dynamic_enum); + bool dyn_right = match_right & (right.ad_type_ == dynamic_enum); + + // check if left and right are variables + bool var_left = match_left & (left.ad_type_ != dynamic_enum); + bool var_right = match_right & (right.ad_type_ != dynamic_enum); + + CPPAD_ASSERT_KNOWN( + left.tape_id_ == right.tape_id_ || ! match_left || ! match_right , + "!=: AD variables or dynamic parameters on different threads." + ); + if( var_left ) + { if( var_right ) + { // variable == variable + tape->Rec_.PutArg(left.taddr_, right.taddr_); + if( result ) + tape->Rec_.PutOp(local::NevvOp); + else + tape->Rec_.PutOp(local::EqvvOp); + } + else + { // variable == parameter + addr_t p = right.taddr_; + if( ! dyn_right ) + p = tape->Rec_.put_con_par(right.value_); + tape->Rec_.PutArg(p, left.taddr_); + if( result ) + tape->Rec_.PutOp(local::NepvOp); + else + tape->Rec_.PutOp(local::EqpvOp); + } + } + else if ( var_right ) + { // parameter == variable + addr_t p = left.taddr_; + if( ! dyn_left ) + p = tape->Rec_.put_con_par(left.value_); + tape->Rec_.PutArg(p, right.taddr_); + if( result ) + tape->Rec_.PutOp(local::NepvOp); + else + tape->Rec_.PutOp(local::EqpvOp); + } + else if( dyn_left | dyn_right ) + { // parameter == parameter + addr_t arg0 = left.taddr_; + addr_t arg1 = right.taddr_; + if( ! dyn_left ) + arg0 = tape->Rec_.put_con_par(left.value_); + if( ! dyn_right ) + arg1 = tape->Rec_.put_con_par(right.value_); + // + tape->Rec_.PutArg(arg0, arg1); + if( result ) + tape->Rec_.PutOp(local::NeppOp); + else + tape->Rec_.PutOp(local::EqppOp); + } + return result; +} +// convert other cases into the case above +CPPAD_FOLD_BOOL_VALUED_BINARY_OPERATOR(!=) + +} // END CppAD namespace + +# endif diff --git a/build-config/cppad/include/cppad/core/compound_assign.hpp b/build-config/cppad/include/cppad/core/compound_assign.hpp new file mode 100644 index 00000000..e6459143 --- /dev/null +++ b/build-config/cppad/include/cppad/core/compound_assign.hpp @@ -0,0 +1,141 @@ +# ifndef CPPAD_CORE_COMPOUND_ASSIGN_HPP +# define CPPAD_CORE_COMPOUND_ASSIGN_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-18 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +/* +------------------------------------------------------------------------------- +$begin compound_assign$$ +$spell + Op + VecAD + const +$$ + +$section AD Compound Assignment Operators$$ + + + + + + +$head Syntax$$ +$icode%x% %Op% %y%$$ + +$head Purpose$$ +Performs compound assignment operations +where either $icode x$$ has type +$codei%AD<%Base%>%$$. + +$head Op$$ +The operator $icode Op$$ is one of the following +$table +$bold Op$$ $cnext $bold Meaning$$ $rnext +$code +=$$ $cnext $icode x$$ is assigned $icode x$$ plus $icode y$$ $rnext +$code -=$$ $cnext $icode x$$ is assigned $icode x$$ minus $icode y$$ $rnext +$code *=$$ $cnext $icode x$$ is assigned $icode x$$ times $icode y$$ $rnext +$code /=$$ $cnext $icode x$$ is assigned $icode x$$ divided by $icode y$$ +$tend + +$head Base$$ +The type $icode Base$$ is determined by the operand $icode x$$. + +$head x$$ +The operand $icode x$$ has the following prototype +$codei% + AD<%Base%> &%x% +%$$ + +$head y$$ +The operand $icode y$$ has the following prototype +$codei% + const %Type% &%y% +%$$ +where $icode Type$$ is +$codei%VecAD<%Base%>::reference%$$, +$codei%AD<%Base%>%$$, +$icode Base$$, or +$code double$$. + +$head Result$$ +The result of this assignment +can be used as a reference to $icode x$$. +For example, if $icode z$$ has the following type +$codei% + AD<%Base%> %z% +%$$ +then the syntax +$codei% + %z% = %x% += %y% +%$$ +will compute $icode x$$ plus $icode y$$ +and then assign this value to both $icode x$$ and $icode z$$. + + +$head Operation Sequence$$ +This is an $cref/atomic_base/glossary/Operation/Atomic/$$ +$cref/AD of Base/glossary/AD of Base/$$ operation +and hence it is part of the current +AD of $icode Base$$ +$cref/operation sequence/glossary/Operation/Sequence/$$. + +$children% + example/general/add_eq.cpp% + example/general/sub_eq.cpp% + example/general/mul_eq.cpp% + example/general/div_eq.cpp +%$$ + +$head Example$$ +The following files contain examples and tests of these functions. +Each test returns true if it succeeds and false otherwise. +$table +$rref AddEq.cpp$$ +$rref sub_eq.cpp$$ +$rref mul_eq.cpp$$ +$rref div_eq.cpp$$ +$tend + +$head Derivative$$ +If $latex f$$ and $latex g$$ are +$cref/Base functions/glossary/Base Function/$$ + +$subhead Addition$$ +$latex \[ + \D{[ f(x) + g(x) ]}{x} = \D{f(x)}{x} + \D{g(x)}{x} +\] $$ + +$subhead Subtraction$$ +$latex \[ + \D{[ f(x) - g(x) ]}{x} = \D{f(x)}{x} - \D{g(x)}{x} +\] $$ + +$subhead Multiplication$$ +$latex \[ + \D{[ f(x) * g(x) ]}{x} = g(x) * \D{f(x)}{x} + f(x) * \D{g(x)}{x} +\] $$ + +$subhead Division$$ +$latex \[ + \D{[ f(x) / g(x) ]}{x} = + [1/g(x)] * \D{f(x)}{x} - [f(x)/g(x)^2] * \D{g(x)}{x} +\] $$ + +$end +----------------------------------------------------------------------------- +*/ +# include +# include +# include +# include + +# endif diff --git a/build-config/cppad/include/cppad/core/con_dyn_var.hpp b/build-config/cppad/include/cppad/core/con_dyn_var.hpp new file mode 100644 index 00000000..b31db282 --- /dev/null +++ b/build-config/cppad/include/cppad/core/con_dyn_var.hpp @@ -0,0 +1,186 @@ +# ifndef CPPAD_CORE_CON_DYN_VAR_HPP +# define CPPAD_CORE_CON_DYN_VAR_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ +/* +--------------------------------------------------------------------------- + +$begin con_dyn_var$$ +$spell + VecAD + const + bool +$$ + +$section Constant, Dynamic, Parameter, and Variable$$ + +$head Syntax$$ +$icode%b% = Constant(%x%) +%$$ +$icode%b% = Dynamic(%x%) +%$$ +$icode%b% = Parameter(%x%) +%$$ +$icode%b% = Variable(%x%) +%$$ + +$head x$$ +The argument $icode x$$ has prototype +$codei% + const AD<%Base%> &%x% + const VecAD<%Base%> &%x% +%$$ + +$head b$$ +The return value $icode b$$ has prototype +$codei% + bool %b% +%$$ + +$head Constant$$ +The return value for $code Constant$$ is true +is true if and only if $icode x$$ is +a $cref/constant/glossary/Parameter/Constant/$$ parameter. +A $cref/VecAD/VecAD/$$ object is a constant parameter +if no element of the vector depends on the independent variables. + +$head Dynamic$$ +The return value for $code Dynamic$$ is true +is true if and only if $icode x$$ is +a $cref/dynamic/glossary/Parameter/Dynamic/$$ parameter. +No element of a $cref/VecAD/VecAD/$$ object +can depend on the dynamic parameters and this function returns false +for these objects. + +$head Parameter$$ +The return value for $code Parameter$$ is true +is true if and only if $icode x$$ is +a $cref/parameter/glossary/Parameter/$$. +A $cref/VecAD/VecAD/$$ object is a parameter +if no element of the vector depends on the independent variables. + +$head Variable$$ +The return value for $code Variable$$ is true +is true if and only if $icode x$$ is +a $cref/variable/glossary/Variable/$$. +A $cref/VecAD/VecAD/$$ object is a variable +if any element of the vector depends on the independent variables. + +$head Operation Sequence$$ +The result of this operation is not an +$cref/AD of Base/glossary/AD of Base/$$ object. +Thus it will not be recorded as part of an +AD of $icode Base$$ +$cref/operation sequence/glossary/Operation/Sequence/$$. + +$head Example$$ +$children% + example/general/con_dyn_var.cpp +%$$ +The file +$cref con_dyn_var.cpp$$ +contains an example and test of these functions. + +$end +----------------------------------------------------------------------------- +*/ + +namespace CppAD { + // ----------------------------------------------------------------------- + // Constant + template + bool Constant(const AD &x) + { CPPAD_ASSERT_UNKNOWN( x.tape_id_== 0 || x.ad_type_ != constant_enum ); + if( x.tape_id_ == 0 ) + return true; + // + size_t thread = size_t(x.tape_id_ % CPPAD_MAX_NUM_THREADS); + return x.tape_id_ != *AD::tape_id_ptr(thread); + } + // + template + bool Constant(const VecAD &x) + { CPPAD_ASSERT_UNKNOWN( x.tape_id_== 0 || x.ad_type_ != constant_enum ); + if( x.tape_id_ == 0 ) + return true; + // + size_t thread = size_t(x.tape_id_ % CPPAD_MAX_NUM_THREADS); + return x.tape_id_ != *AD::tape_id_ptr(thread); + } + // ----------------------------------------------------------------------- + // Dynamic + template + bool Dynamic(const AD &x) + { CPPAD_ASSERT_UNKNOWN( x.tape_id_ == 0 || x.ad_type_ != constant_enum ); + if( (x.tape_id_ == 0) | (x.ad_type_ != dynamic_enum) ) + return false; + // + size_t thread = size_t(x.tape_id_ % CPPAD_MAX_NUM_THREADS); + return x.tape_id_ == *AD::tape_id_ptr(thread); + } + // + template + bool Dynamic(const VecAD &x) + { CPPAD_ASSERT_UNKNOWN( x.tape_id_ == 0 || x.ad_type_ != constant_enum ); + if( (x.tape_id_ == 0) | (x.ad_type_ != dynamic_enum) ) + return false; + // + size_t thread = size_t(x.tape_id_ % CPPAD_MAX_NUM_THREADS); + return x.tape_id_ == *AD::tape_id_ptr(thread); + } + // ----------------------------------------------------------------------- + // Parameter + template + bool Parameter(const AD &x) + { CPPAD_ASSERT_UNKNOWN( x.tape_id_ == 0 || x.ad_type_ != constant_enum ); + if( (x.tape_id_ == 0) | (x.ad_type_ == dynamic_enum) ) + return true; + // + size_t thread = size_t(x.tape_id_ % CPPAD_MAX_NUM_THREADS); + return x.tape_id_ != *AD::tape_id_ptr(thread); + } + // + template + bool Parameter(const VecAD &x) + { CPPAD_ASSERT_UNKNOWN( x.tape_id_ == 0 || x.ad_type_ != constant_enum ); + if( (x.tape_id_ == 0) | (x.ad_type_ == dynamic_enum) ) + return true; + // + size_t thread = size_t(x.tape_id_ % CPPAD_MAX_NUM_THREADS); + return x.tape_id_ != *AD::tape_id_ptr(thread); + } + // ----------------------------------------------------------------------- + // Variable + template + bool Variable(const AD &x) + { CPPAD_ASSERT_UNKNOWN( x.tape_id_ == 0 || x.ad_type_ != constant_enum ); + if( (x.tape_id_ == 0) | (x.ad_type_ != variable_enum) ) + return false; + // + size_t thread = size_t(x.tape_id_ % CPPAD_MAX_NUM_THREADS); + return x.tape_id_ == *AD::tape_id_ptr(thread); + } + // + template + bool Variable(const VecAD &x) + { CPPAD_ASSERT_UNKNOWN( x.tape_id_ == 0 || x.ad_type_ != constant_enum ); + if( (x.tape_id_ == 0) | (x.ad_type_ != variable_enum) ) + return false; + // + size_t thread = size_t(x.tape_id_ % CPPAD_MAX_NUM_THREADS); + return x.tape_id_ == *AD::tape_id_ptr(thread); + } +} +// END CppAD namespace + + +# endif diff --git a/build-config/cppad/include/cppad/core/cond_exp.hpp b/build-config/cppad/include/cppad/core/cond_exp.hpp new file mode 100644 index 00000000..0ee0806b --- /dev/null +++ b/build-config/cppad/include/cppad/core/cond_exp.hpp @@ -0,0 +1,276 @@ +# ifndef CPPAD_CORE_COND_EXP_HPP +# define CPPAD_CORE_COND_EXP_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +/* +------------------------------------------------------------------------------- +$begin CondExp$$ +$spell + Atan2 + CondExp + Taylor + std + Cpp + namespace + inline + const + abs + Rel + bool + Lt + Le + Eq + Ge + Gt +$$ + + +$section AD Conditional Expressions$$ + +$head Syntax$$ +$icode%result% = CondExp%Rel%(%left%, %right%, %if_true%, %if_false%)%$$ + + +$head Purpose$$ +Record, +as part of an AD of $icode Base$$ +$cref/operation sequence/glossary/Operation/Sequence/$$, +the conditional result +$codei% + if( %left% %Cop% %right% ) + %result% = %if_true% + else + %result% = %if_false% +%$$ +The relational $icode Rel$$ and comparison operator $icode Cop$$ +above have the following correspondence: +$codei% + %Rel% Lt Le Eq Ge Gt + %Cop% < <= == >= > +%$$ +If $icode f$$ is the $cref ADFun$$ object corresponding to the +AD operation sequence, +the assignment choice for $icode result$$ +in an AD conditional expression is made each time +$cref/f.Forward/Forward/$$ is used to evaluate the zero order Taylor +coefficients with new values for the +$cref/independent variables/glossary/Tape/Independent Variable/$$. +This is in contrast to the $cref/AD comparison operators/Compare/$$ +which are boolean valued and not included in the AD operation sequence. + +$head Rel$$ +In the syntax above, the relation $icode Rel$$ represents one of the following +two characters: $code Lt$$, $code Le$$, $code Eq$$, $code Ge$$, $code Gt$$. +As in the table above, +$icode Rel$$ determines which comparison operator $icode Cop$$ is used +when comparing $icode left$$ and $icode right$$. + +$head Type$$ +These functions are defined in the CppAD namespace for arguments of +$icode Type$$ is $code float$$ , $code double$$, or any type of the form +$codei%AD<%Base%>%$$. +(Note that all four arguments must have the same type.) + +$head left$$ +The argument $icode left$$ has prototype +$codei% + const %Type%& %left% +%$$ +It specifies the value for the left side of the comparison operator. + +$head right$$ +The argument $icode right$$ has prototype +$codei% + const %Type%& %right% +%$$ +It specifies the value for the right side of the comparison operator. + +$head if_true$$ +The argument $icode if_true$$ has prototype +$codei% + const %Type%& %if_true% +%$$ +It specifies the return value if the result of the comparison is true. + +$head if_false$$ +The argument $icode if_false$$ has prototype +$codei% + const %Type%& %if_false% +%$$ +It specifies the return value if the result of the comparison is false. + +$head result$$ +The $icode result$$ has prototype +$codei% + %Type%& %if_false% +%$$ + +$head Optimize$$ +The $cref optimize$$ method will optimize conditional expressions +in the following way: +During $cref/zero order forward mode/forward_zero/$$, +once the value of the $icode left$$ and $icode right$$ have been determined, +it is known if the true or false case is required. +From this point on, values corresponding to the case that is not required +are not computed. +This optimization is done for the rest of zero order forward mode +as well as forward and reverse derivatives calculations. + +$head Deprecate 2005-08-07$$ +Previous versions of CppAD used +$codei% + CondExp(%flag%, %if_true%, %if_false%) +%$$ +for the same meaning as +$codei% + CondExpGt(%flag%, %Type%(0), %if_true%, %if_false%) +%$$ +Use of $code CondExp$$ is deprecated, but continues to be supported. + +$head Operation Sequence$$ +This is an AD of $icode Base$$ +$cref/atomic operation/glossary/Operation/Atomic/$$ +and hence is part of the current +AD of $icode Base$$ +$cref/operation sequence/glossary/Operation/Sequence/$$. + + +$head Example$$ + +$head Test$$ +$children% + example/general/cond_exp.cpp +%$$ +The file +$cref cond_exp.cpp$$ +contains an example and test of this function. + +$head Atan2$$ +The following implementation of the +AD $cref atan2$$ function is a more complex +example of using conditional expressions: +$srcfile%include/cppad/core/atan2.hpp%0%BEGIN CondExp%// END CondExp%$$ + + +$end +------------------------------------------------------------------------------- +*/ +// BEGIN CppAD namespace +namespace CppAD { + +template +AD CondExpOp( + enum CompareOp cop , + const AD &left , + const AD &right , + const AD &if_true , + const AD &if_false ) +{ + AD result; + CPPAD_ASSERT_UNKNOWN( Parameter(result) ); + + // check first case where do not need to tape + if( IdenticalCon(left) & IdenticalCon(right) ) + { switch( cop ) + { + case CompareLt: + if( left.value_ < right.value_ ) + result = if_true; + else + result = if_false; + break; + + case CompareLe: + if( left.value_ <= right.value_ ) + result = if_true; + else + result = if_false; + break; + + case CompareEq: + if( left.value_ == right.value_ ) + result = if_true; + else + result = if_false; + break; + + case CompareGe: + if( left.value_ >= right.value_ ) + result = if_true; + else + result = if_false; + break; + + case CompareGt: + if( left.value_ > right.value_ ) + result = if_true; + else + result = if_false; + break; + + default: + CPPAD_ASSERT_UNKNOWN(0); + result = if_true; + } + return result; + } + + // must use CondExp in case Base is an AD type and recording + result.value_ = CondExpOp(cop, + left.value_, right.value_, if_true.value_, if_false.value_); + + local::ADTape *tape = AD::tape_ptr(); + + // add this operation to the tape + if( tape != nullptr ) tape->Rec_.cond_exp( + tape->id_, cop, result, left, right, if_true, if_false + ); + + return result; +} + +// ------------ CondExpOp(left, right, if_true, if_false) ---------------- + +# define CPPAD_COND_EXP(Name) \ + template \ + CPPAD_INLINE_FRIEND_TEMPLATE_FUNCTION \ + AD CondExp##Name( \ + const AD &left , \ + const AD &right , \ + const AD &if_true , \ + const AD &if_false ) \ + { \ + return CondExpOp(Compare##Name, \ + left, right, if_true, if_false); \ + } + +// AD +CPPAD_COND_EXP(Lt) +CPPAD_COND_EXP(Le) +CPPAD_COND_EXP(Eq) +CPPAD_COND_EXP(Ge) +CPPAD_COND_EXP(Gt) +template +CPPAD_INLINE_FRIEND_TEMPLATE_FUNCTION +AD CondExp( + const AD &flag , + const AD &if_true , + const AD &if_false ) +{ + return CondExpOp(CompareGt, flag, AD(0), if_true, if_false); +} + +# undef CPPAD_COND_EXP +} // END CppAD namespace + +# endif diff --git a/build-config/cppad/include/cppad/core/convert.hpp b/build-config/cppad/include/cppad/core/convert.hpp new file mode 100644 index 00000000..7ec6815b --- /dev/null +++ b/build-config/cppad/include/cppad/core/convert.hpp @@ -0,0 +1,50 @@ +# ifndef CPPAD_CORE_CONVERT_HPP +# define CPPAD_CORE_CONVERT_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-16 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +/* +$begin Convert$$ +$spell +$$ + + +$section Conversion and I/O of AD Objects$$ + +$children% + include/cppad/core/value.hpp% + include/cppad/core/integer.hpp% + include/cppad/core/ad_to_string.hpp% + include/cppad/core/ad_io.hpp% + include/cppad/core/print_for.hpp% + include/cppad/core/var2par.hpp +%$$ +$table +$rref Value$$ +$rref Integer$$ +$rref ad_output$$ +$rref PrintFor$$ +$rref Var2Par$$ +$tend + + +$end +*/ + +# include +# include +# include +# include +# include +# include + +# endif diff --git a/build-config/cppad/include/cppad/core/cppad_assert.hpp b/build-config/cppad/include/cppad/core/cppad_assert.hpp new file mode 100644 index 00000000..f8c9507a --- /dev/null +++ b/build-config/cppad/include/cppad/core/cppad_assert.hpp @@ -0,0 +1,188 @@ +# ifndef CPPAD_CORE_CPPAD_ASSERT_HPP +# define CPPAD_CORE_CPPAD_ASSERT_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-17 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +/*! +\file cppad_assert.hpp +Define the CppAD error checking macros (all of which begin with CPPAD_ASSERT_) +*/ + +/* +------------------------------------------------------------------------------- +$begin cppad_assert$$ +$spell + CppAD + exp + const + bool +$$ + + +$section CppAD Assertions During Execution$$ + +$head Syntax$$ +$codei%CPPAD_ASSERT_KNOWN(%exp%, %msg%) +%$$ +$codei%CPPAD_ASSERT_UNKNOWN(%exp%)%$$ + + +$head Purpose$$ +These CppAD macros are used to detect and report errors. +They are documented here because they correspond to the C++ +source code that the error is reported at. + +$head NDEBUG$$ +If the preprocessor symbol +$cref/NDEBUG/Faq/Speed/NDEBUG/$$ is defined, +these macros do nothing; i.e., they are optimized out. + +$head Restriction$$ +The CppAD user should not uses these macros. +You can however write your own macros that do not begin with $code CPPAD$$ +and that call the $cref/CppAD error handler/ErrorHandler/$$. + +$head Known$$ +The $code CPPAD_ASSERT_KNOWN$$ macro is used to check for an error +with a known cause. +For example, many CppAD routines uses these macros +to make sure their arguments conform to their specifications. + +$head Unknown$$ +The $code CPPAD_ASSERT_UNKNOWN$$ macro is used to check that the +CppAD internal data structures conform as expected. +If this is not the case, CppAD does not know why the error has +occurred; for example, the user may have written past the end +of an allocated array. + +$head Exp$$ +The argument $icode exp$$ is a C++ source code expression +that results in a $code bool$$ value that should be true. +If it is false, an error has occurred. +This expression may be execute any number of times +(including zero times) so it must have not side effects. + +$head Msg$$ +The argument $icode msg$$ has prototype +$codei% + const char *%msg% +%$$ +and contains a $code '\0'$$ terminated character string. +This string is a description of the error +corresponding to $icode exp$$ being false. + +$head Error Handler$$ +These macros use the +$cref/CppAD error handler/ErrorHandler/$$ to report errors. +This error handler can be replaced by the user. + +$end +------------------------------------------------------------------------------ +*/ + +# include +# include +# include + +/*! +\def CPPAD_ASSERT_KNOWN(exp, msg) +Check that exp is true, if not print msg and terminate execution. + +The C++ expression exp is expected to be true. +If it is false, +the CppAD use has made an error that is described by msg. +If the preprocessor symbol NDEBUG is not defined, +and exp is false, +this macro will report the source code line number at +which this expected result occurred. +In addition, it will print the specified error message msg. +*/ +# ifdef NDEBUG +# define CPPAD_ASSERT_KNOWN(exp, msg) // do nothing +# else +# define CPPAD_ASSERT_KNOWN(exp, msg) \ +{ if( ! ( exp ) ) \ + CppAD::ErrorHandler::Call( \ + true , \ + __LINE__ , \ + __FILE__ , \ + #exp , \ + msg ); \ +} +# endif + +/*! +\def CPPAD_ASSERT_UNKNOWN(exp) +Check that exp is true, if not terminate execution. + +The C++ expression exp is expected to be true. +If it is false, +CppAD has detected an error but does not know the cause of the error. +If the preprocessor symbol NDEBUG is not defined, +and exp is false, +this macro will report the source code line number at +which this expected result occurred. +*/ +# ifdef NDEBUG +# define CPPAD_ASSERT_UNKNOWN(exp) // do nothing +# else +# define CPPAD_ASSERT_UNKNOWN(exp) \ +{ if( ! ( exp ) ) \ + CppAD::ErrorHandler::Call( \ + false , \ + __LINE__ , \ + __FILE__ , \ + #exp , \ + "" ); \ +} +# endif + +/*! +\def CPPAD_ASSERT_NARG_NRES(op, n_arg, n_res) +Check that operator op has the specified number of of arguments and results. + +If NDEBUG is not defined and either the number of arguments +or the number of results are not as expected, +execution is terminated and the source code line number is reported. +*/ +# define CPPAD_ASSERT_NARG_NRES(op, n_arg, n_res) \ + CPPAD_ASSERT_UNKNOWN( NumArg(op) == n_arg ) \ + CPPAD_ASSERT_UNKNOWN( NumRes(op) == n_res ) + +/*! +\def CPPAD_ASSERT_FIRST_CALL_NOT_PARALLEL +Check that the first call to a routine is not during parallel execution mode. + +If NDEBUG is defined, this macro has no effect +(not even the definition of (assert_first_call). +Otherwise, the variable +\code + static bool assert_first_call +\endcode +is defined and if the first call is executed in parallel mode, +execution is terminated and the source code line number is reported. +*/ +# ifdef NDEBUG +# define CPPAD_ASSERT_FIRST_CALL_NOT_PARALLEL +# else +# define CPPAD_ASSERT_FIRST_CALL_NOT_PARALLEL \ + static bool assert_first_call = true; \ + if( assert_first_call ) \ + { CPPAD_ASSERT_KNOWN( \ + ! (CppAD::thread_alloc::in_parallel() ), \ + "In parallel mode and parallel_setup has not been called." \ + ); \ + assert_first_call = false; \ + } +# endif + +# endif diff --git a/build-config/cppad/include/cppad/core/dependent.hpp b/build-config/cppad/include/cppad/core/dependent.hpp new file mode 100644 index 00000000..96d4219d --- /dev/null +++ b/build-config/cppad/include/cppad/core/dependent.hpp @@ -0,0 +1,334 @@ +# ifndef CPPAD_CORE_DEPENDENT_HPP +# define CPPAD_CORE_DEPENDENT_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ +/* +$begin Dependent$$ +$spell + alloc + num + taylor_ + ADvector + const +$$ + +$spell +$$ + +$section Stop Recording and Store Operation Sequence$$ + + +$head Syntax$$ +$icode%f%.Dependent(%x%, %y%)%$$ + +$head Purpose$$ +Stop recording and the AD of $icode Base$$ +$cref/operation sequence/glossary/Operation/Sequence/$$ +that started with the call +$codei% + Independent(%x%) +%$$ +and store the operation sequence in $icode f$$. +The operation sequence defines an +$cref/AD function/glossary/AD Function/$$ +$latex \[ + F : \B{R}^n \rightarrow \B{R}^m +\] $$ +where $latex B$$ is the space corresponding to objects of type $icode Base$$. +The value $latex n$$ is the dimension of the +$cref/domain/seq_property/Domain/$$ space for the operation sequence. +The value $latex m$$ is the dimension of the +$cref/range/seq_property/Range/$$ space for the operation sequence +(which is determined by the size of $icode y$$). + +$head f$$ +The object $icode f$$ has prototype +$codei% + ADFun<%Base%> %f% +%$$ +The AD of $icode Base$$ operation sequence is stored in $icode f$$; i.e., +it becomes the operation sequence corresponding to $icode f$$. +If a previous operation sequence was stored in $icode f$$, +it is deleted. + +$head x$$ +The argument $icode x$$ +must be the vector argument in a previous call to +$cref Independent$$. +Neither its size, or any of its values, are allowed to change +between calling +$codei% + Independent(%x%) +%$$ +and +$codei% + %f%.Dependent(%x%, %y%) +%$$. + +$head y$$ +The vector $icode y$$ has prototype +$codei% + const %ADvector% &%y% +%$$ +(see $cref/ADvector/FunConstruct/$$ below). +The length of $icode y$$ must be greater than zero +and is the dimension of the range space for $icode f$$. + +$head ADvector$$ +The type $icode ADvector$$ must be a $cref SimpleVector$$ class with +$cref/elements of type/SimpleVector/Elements of Specified Type/$$ +$codei%AD<%Base%>%$$. +The routine $cref CheckSimpleVector$$ will generate an error message +if this is not the case. + +$head Taping$$ +The tape, +that was created when $codei%Independent(%x%)%$$ was called, +will stop recording. +The AD operation sequence will be transferred from +the tape to the object $icode f$$ and the tape will then be deleted. + +$head Forward$$ +No $cref Forward$$ calculation is preformed during this operation. +Thus, directly after this operation, +$codei% + %f%.size_order() +%$$ +is zero (see $cref size_order$$). + +$head Parallel Mode$$ +The call to $code Independent$$, +and the corresponding call to +$codei% + ADFun<%Base%> %f%( %x%, %y%) +%$$ +or +$codei% + %f%.Dependent( %x%, %y%) +%$$ +or $cref abort_recording$$, +must be preformed by the same thread; i.e., +$cref/thread_alloc::thread_num/ta_thread_num/$$ must be the same. + +$head Example$$ +The file +$cref fun_check.cpp$$ +contains an example and test of this operation. + +$end +---------------------------------------------------------------------------- +*/ + + +// BEGIN CppAD namespace +namespace CppAD { + +/*! +\file dependent.hpp +Different versions of Dependent function. +*/ + +/*! +Determine the tape corresponding to this exeuction thread and then use +Dependent(tape, y) to store this tapes recording in a function. + +\param y [in] +The dependent variable vector for the corresponding function. +*/ +template +template +void ADFun::Dependent(const ADvector &y) +{ local::ADTape* tape = AD::tape_ptr(); + CPPAD_ASSERT_KNOWN( + tape != nullptr, + "Can't store current operation sequence in this ADFun object" + "\nbecause there is no active tape (for this thread)." + ); + + // code above just determines the tape and checks for errors + Dependent(tape, y); +} + + +/*! +Determine the tape corresponding to this exeuction thread and then use +Dependent(tape, y) to store this tapes recording in a function. + +\param x [in] +The independent variable vector for this tape. This informaiton is +also stored in the tape so a check is done to make sure it is correct +(if NDEBUG is not defined). + +\param y [in] +The dependent variable vector for the corresponding function. +*/ +template +template +void ADFun::Dependent(const ADvector &x, const ADvector &y) +{ + CPPAD_ASSERT_KNOWN( + x.size() > 0, + "Dependent: independent variable vector has size zero." + ); + CPPAD_ASSERT_KNOWN( + Variable(x[0]), + "Dependent: independent variable vector has been changed." + ); + local::ADTape *tape = AD::tape_ptr(x[0].tape_id_); + CPPAD_ASSERT_KNOWN( + tape->size_independent_ == size_t( x.size() ), + "Dependent: independent variable vector has been changed." + ); +# ifndef NDEBUG + size_t i, j; + for(j = 0; j < size_t(x.size()); j++) + { CPPAD_ASSERT_KNOWN( + size_t(x[j].taddr_) == (j+1), + "ADFun: independent variable vector has been changed." + ); + CPPAD_ASSERT_KNOWN( + x[j].tape_id_ == x[0].tape_id_, + "ADFun: independent variable vector has been changed." + ); + } + for(i = 0; i < size_t(y.size()); i++) + { CPPAD_ASSERT_KNOWN( + CppAD::Parameter( y[i] ) | (y[i].tape_id_ == x[0].tape_id_) , + "ADFun: dependent vector contains a variable for" + "\na different tape (thread) than the independent variables." + ); + } +# endif + + // code above just determines the tape and checks for errors + Dependent(tape, y); +} + +/*! +Replace the floationg point operations sequence for this function object. + +\param tape +is a tape that contains the new floating point operation sequence +for this function. +After this operation, all memory allocated for this tape is deleted. + +\param y +The dependent variable vector for the function being stored in this object. + +\par +All of the private member data in ad_fun.hpp is set to correspond to the +new tape except for check_for_nan_. +*/ + +template +template +void ADFun::Dependent(local::ADTape *tape, const ADvector &y) +{ + size_t m = y.size(); + size_t n = tape->size_independent_; + + // check ADvector is Simple Vector class with AD elements + CheckSimpleVector< AD, ADvector>(); + + CPPAD_ASSERT_KNOWN( + y.size() > 0, + "ADFun operation sequence dependent variable size is zero size" + ); + // --------------------------------------------------------------------- + // Begin setting ad_fun.hpp private member data + // --------------------------------------------------------------------- + // dep_parameter_, dep_taddr_ + CPPAD_ASSERT_UNKNOWN( local::NumRes(local::ParOp) == 1 ); + dep_parameter_.resize(m); + dep_taddr_.resize(m); + for(size_t i = 0; i < m; i++) + { dep_parameter_[i] = CppAD::Parameter(y[i]); + addr_t y_taddr; + if( dep_parameter_[i] ) + { // make a tape copy of dependent variables that are parameters, + y_taddr = tape->RecordParOp( y[i] ); + } + else + y_taddr = y[i].taddr_; + + CPPAD_ASSERT_UNKNOWN( y_taddr > 0 ); + dep_taddr_[i] = size_t( y_taddr ); + } + + // put an EndOp at the end of the tape + tape->Rec_.PutOp(local::EndOp); + + // bool values in this object except check_for_nan_ + has_been_optimized_ = false; + // + // size_t values in this object + compare_change_count_ = 1; + compare_change_number_ = 0; + compare_change_op_index_ = 0; + num_order_taylor_ = 0; + cap_order_taylor_ = 0; + num_direction_taylor_ = 0; + num_var_tape_ = tape->Rec_.num_var_rec(); + + // taylor_ + taylor_.resize(0); + + // cskip_op_ + cskip_op_.resize( tape->Rec_.num_op_rec() ); + + // load_op2var_ + load_op2var_.resize( tape->Rec_.num_var_load_rec() ); + + // play_ + // Now that each dependent variable has a place in the tape, + // and there is a EndOp at the end of the tape, we can transfer the + // recording to the player and and erase the recording; i.e. ERASE Rec_. + play_.get_recording(tape->Rec_, n); + + // ind_taddr_ + // Note that play_ has been set, we can use it to check operators + ind_taddr_.resize(n); + CPPAD_ASSERT_UNKNOWN( n < num_var_tape_); + for(size_t j = 0; j < n; j++) + { CPPAD_ASSERT_UNKNOWN( play_.GetOp(j+1) == local::InvOp ); + ind_taddr_[j] = j+1; + } + + // for_jac_sparse_pack_, for_jac_sparse_set_ + for_jac_sparse_pack_.resize(0, 0); + for_jac_sparse_set_.resize(0,0); + + // resize subgraph_info_ + subgraph_info_.resize( + ind_taddr_.size(), // n_dep + dep_taddr_.size(), // n_ind + play_.num_op_rec(), // n_op + play_.num_var_rec() // n_var + ); + // --------------------------------------------------------------------- + // End set ad_fun.hpp private member data + // --------------------------------------------------------------------- + + // now we can delete the tape + AD::tape_manage(delete_tape_manage); + + // total number of varables in this recording + CPPAD_ASSERT_UNKNOWN( num_var_tape_ == play_.num_var_rec() ); + + // used to determine if there is an operation sequence in *this + CPPAD_ASSERT_UNKNOWN( num_var_tape_ > 0 ); + +} + +} // END CppAD namespace + +# endif diff --git a/build-config/cppad/include/cppad/core/discrete/devel.omh b/build-config/cppad/include/cppad/core/discrete/devel.omh new file mode 100644 index 00000000..7ca21274 --- /dev/null +++ b/build-config/cppad/include/cppad/core/discrete/devel.omh @@ -0,0 +1,22 @@ +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ +$begin devel_discrete$$ +$spell +$$ + +$section Developer Documentation for Discrete Function$$ + +$childtable% + include/cppad/core/discrete/discrete.hpp +%$$ + +$end diff --git a/build-config/cppad/include/cppad/core/discrete/discrete.hpp b/build-config/cppad/include/cppad/core/discrete/discrete.hpp new file mode 100644 index 00000000..c64f505a --- /dev/null +++ b/build-config/cppad/include/cppad/core/discrete/discrete.hpp @@ -0,0 +1,334 @@ +# ifndef CPPAD_CORE_DISCRETE_DISCRETE_HPP +# define CPPAD_CORE_DISCRETE_DISCRETE_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ +# include +# include + +// needed before one can use CPPAD_ASSERT_FIRST_CALL_NOT_PARALLEL +# include + +namespace CppAD { // BEGIN_CPPAD_NAMESPACE +/* + ------------------------------------------------------------------------------ +$begin discrete_create$$ +$spell +$$ +$section Create a Discrete AD Function$$ + +$head Syntax$$ +$codei%CPPAD_DISCRETE_FUNCTION(%Base%, %name%) +%$$ +$icode%name(%ax%, %ay%) +%$$ + +$head Base$$ +is the base type for the discrete function. + +$head name$$ +is the name of the user defined function that corresponding to this operation. + +$head ax$$ +Is a $codei%AD<%Base%>%$$ corresponding to the argument for the function. + +$head ay$$ +Is a $codei%AD<%Base%>%$$ corresponding to the result for the function. + +$head fun$$ +The local object $code fun$$ is a member of the $code discrete$$ class. + +$head Source Code$$ +$srccode%hpp% */ +# define CPPAD_DISCRETE_FUNCTION(Base, name) \ +inline CppAD::AD name (const CppAD::AD& ax) \ +{ static CppAD::discrete fun(#name, name); \ + return fun.ad(ax); \ +} +# define CppADCreateDiscrete CPPAD_DISCRETE_FUNCTION +/* %$$ +$end +----------------------------------------------------------------------------- +$begin discrete_class$$ + +$section Declare discrete Class and Member Data$$ + +$head parallel_ad$$ +is a friend of this class so it can call List to initialize +its static data. + +$head F$$ +is the type for the user routine that computes $icode Base$$ function values. + +$head name_$$ +name of this user defined discrete function. + +$head f_$$ +user routine that computes $icode Base$$ function values. + +$head index_$$ +index of this object in $cref discrete_list$$ for this $icode Base$$. + +$head Source Code$$ +$srccode%hpp% */ +template +class discrete { +private: + template friend void parallel_ad(void); + typedef Base (*F) (const Base& x); + const std::string name_; + const F f_; + const size_t index_; +/* %$$ +$end +------------------------------------------------------------------------------ +$begin discrete_list$$ +$spell + alloc + std + CppAD +$$ +$section List of all objects in the discrete class$$ + +$head Syntax$$ +$icode%list% = discrete<%Base%>::List()%$$ + +$head Base$$ +Is the $cref/Base/discrete_create/Base/$$ +type for this list of discrete functions. + +$head list$$ +is a reference to the list of all the +$code discrete$$ object currently defined. + +$subhead std::vector$$ +We use $code std::vector$$ instead of $code CppAD::vector$$ +so it does not appear that there is a $cref memory_leak$$ +this list is not destroyed before +$cref/thread_alloc::free_all/ta_free_all/$$ is called by testing routines. + +$head Source Code$$ +$srccode%hpp% */ +private: + static std::vector& List(void) + { CPPAD_ASSERT_FIRST_CALL_NOT_PARALLEL; + static std::vector list; + return list; + } +/* %$$ +$end + ------------------------------------------------------------------------------ +$begin discrete_list_size$$ +$spell +$$ +$section Size of the Discrete Function List$$ + +$head Syntax$$ +$icode%size% = discrete<%Base%>::list_size()%$$ + +$head Base$$ +Is the $cref/Base/discrete_create/Base/$$ +type for this list of discrete functions. + +$head size$$ +is the number of discrete functions for this $icode Base$$ type. + +$head Source Code$$ +$srccode%hpp% */ +public: + static size_t list_size(void) + { return List().size(); } +/* %$$ +$end + ------------------------------------------------------------------------------ +$begin discrete_ctor$$ +$spell +$$ +$section Constructor Called by each Use of CPPAD_DISCRETE_FUNCTION$$ + +$head Syntax$$ +$codei%discrete<%Base%> %fun%(%name%, %f%)%$$ + +$head name$$ +is the name of this function. + +$head f$$ +user routine that implements this function for Base class. + +$head fun$$ +is the $code discrete$$ object created by this call to the constructor. + +$subhead name_$$ +is set equal to $icode name$$. + +$subhead f_$$ +is set equal to $icode f$$. + +$subhead index_$$ +This object is put at the end of $cref discrete_list$$ and $code index_$$ +is set to the index of this object in the discrete list. + +$head Parallel$$ +This constructor cannot be used in parallel mode because it changes +the static object returned by $cref discrete_list$$. + +$end +*/ +public: + discrete(const char* name, F f) : + name_(name), f_(f) , index_( List().size() ) + { std::string msg = "discrete: first call to the discrete function "; + msg += name; + msg += " is in parallel mode."; + CPPAD_ASSERT_KNOWN( + ! thread_alloc::in_parallel() , + msg.c_str() + ); + List().push_back(this); + } +/* + ------------------------------------------------------------------------------ +$begin discrete_ad$$ +$spell +$$ +$section Implement AD Version of a Discrete Function$$ + +$head Syntax$$ +$icode%ay% = %fun%.ad(%ax)%$$ + +$head ax$$ +is the argument for the AD version of this function. + +$head ay$$ +is the return value for the AD version of this function. + +$head Prototype$$ +$srccode%hpp% */ + AD ad(const AD &ax) const +/* %$$ +$end +*/ + { + CPPAD_ASSERT_KNOWN( + size_t( std::numeric_limits::max() ) >= index_, + "discrete: cppad_tape_addr_type maximum not large enough" + ); + // + AD ay; + ay.value_ = f_(ax.value_); + // + // check if there is a recording in progress + local::ADTape* tape = AD::tape_ptr(); + if( tape == nullptr ) + return ay; + // + // check if argument is a constant parameter + if( ax.tape_id_ != tape->id_ ) + return ay; + // + if( ax.ad_type_ == dynamic_enum ) + { + // tape dynamic paramter operation + ay.taddr_ = tape->Rec_.put_dyn_par( + ay.value_, local::dis_dyn, addr_t(index_), ax.taddr_ + ); + ay.tape_id_ = ax.tape_id_; + ay.ad_type_ = dynamic_enum; + + // make result a dynamic parameter + ay.tape_id_ = tape->id_; + ay.ad_type_ = dynamic_enum; + + CPPAD_ASSERT_UNKNOWN( Dynamic(ay) ); + } + else if( ax.ad_type_ == variable_enum ) + { + CPPAD_ASSERT_UNKNOWN( local::NumRes(local::DisOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( local::NumArg(local::DisOp) == 2 ); + + // put operand addresses in the tape + CPPAD_ASSERT_KNOWN( + size_t( std::numeric_limits::max() ) >= index_, + "discrete: cppad_tape_addr_type maximum not large enough" + ); + tape->Rec_.PutArg(addr_t(index_), ax.taddr_); + // put operator in the tape + ay.taddr_ = tape->Rec_.PutOp(local::DisOp); + // make result a variable + ay.tape_id_ = tape->id_; + ay.ad_type_ = variable_enum; + + CPPAD_ASSERT_UNKNOWN( Variable(ay) ); + } + else + { // other types not yet being used and should have this tape id + CPPAD_ASSERT_UNKNOWN(false); + } + return ay; + } +/* +------------------------------------------------------------------------------ +$begin discrete_name$$ + +$section Name Corresponding to a discrete Function$$ + +$head Syntax$$ +$codei%discrete<%Base%>::name(%index%)%$$ + +$head Base$$ +Is the $cref/Base/discrete_create/Base/$$ +type for this list of discrete functions. + +$head index$$ +Is the index, in the list, for this discrete function. + +$head Source Code$$ +$srccode%hpp% */ + static const char* name(size_t index) + { return List()[index]->name_.c_str(); } +/* %$$ +$end +------------------------------------------------------------------------------ +$begin discrete_eval$$ +$spell + eval +$$ +$section Link From Forward Mode Sweep to Users Routine$$ + +$head Syntax$$ +$icode%y% = discrete<%Base%>::eval(%index%, %x%)%$$ + +$head Base$$ +Is the $cref/Base/discrete_create/Base/$$ +type for this list of discrete functions. + +$head index$$ +index for this function in $cref discrete_list$$. + +$head x$$ +argument at which to evaluate $icode Base$$ version of this function. + +$head y$$ +result for the $icode Base$$ version of this function. + +$head Source Code$$ +$srccode%hpp% */ + static Base eval(size_t index, const Base& x) + { CPPAD_ASSERT_UNKNOWN(index < List().size() ); + return List()[index]->f_(x); + } +/* %$$ +$end +*/ +}; + +} // END_CPPAD_NAMESPACE +# endif diff --git a/build-config/cppad/include/cppad/core/discrete/user.omh b/build-config/cppad/include/cppad/core/discrete/user.omh new file mode 100644 index 00000000..931957bc --- /dev/null +++ b/build-config/cppad/include/cppad/core/discrete/user.omh @@ -0,0 +1,146 @@ +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +/* +$begin Discrete$$ +$spell + retaping + namespace + std + Eq + Cpp + const + inline + Geq +$$ + +$section Discrete AD Functions$$ + + +$head Syntax$$ +$codei%CPPAD_DISCRETE_FUNCTION(%Base%, %name%) +%$$ +$icode%y% = %name%(%x%) +%$$ +$icode%ay% = %name%(%ax%) +%$$ + + +$head Purpose$$ +Record the evaluation of a discrete function as part +of an $codei%AD<%Base%>%$$ +$cref/operation sequence/glossary/Operation/Sequence/$$. +The value of a discrete function can depend on the +$cref/independent variables/glossary/Tape/Independent Variable/$$, +but its derivative is identically zero. +For example, suppose that the integer part of +a $cref/variable/glossary/Variable/$$ $icode x$$ is the +index into an array of values. + +$head Base$$ +This is the +$cref/base type/base_require/$$ +corresponding to the operations sequence; +i.e., use of the $icode name$$ with arguments of type +$codei%AD<%Base%>%$$ can be recorded in an operation sequence. + +$head name$$ +This is the name of the function (as it is used in the source code). +The user must provide a version of $icode name$$ +where the argument has type $icode Base$$. +CppAD uses this to create a version of $icode name$$ +where the argument has type $codei%AD<%Base%>%$$. + +$head x$$ +The argument $icode x$$ has prototype +$codei% + const %Base%& %x% +%$$ +It is the value at which the user provided version of $icode name$$ +is to be evaluated. + +$head y$$ +The result $icode y$$ has prototype +$codei% + %Base% %y% +%$$ +It is the return value for the user provided version of $icode name$$. + +$head ax$$ +The argument $icode ax$$ has prototype +$codei% + const AD<%Base%>& %ax% +%$$ +It is the value at which the CppAD provided version of $icode name$$ +is to be evaluated. + +$head ay$$ +The result $icode ay$$ has prototype +$codei% + AD<%Base%> %ay% +%$$ +It is the return value for the CppAD provided version of $icode name$$. + + +$head Create AD Version$$ +The preprocessor macro invocation +$codei% + CPPAD_DISCRETE_FUNCTION(%Base%, %name%) +%$$ +defines the $codei%AD<%Base%>%$$ version of $icode name$$. +This can be with in a namespace (not the $code CppAD$$ namespace) +but must be outside of any routine. + +$head Operation Sequence$$ +This is an AD of $icode Base$$ +$cref/atomic operation/glossary/Operation/Atomic/$$ +and hence is part of the current +AD of $icode Base$$ +$cref/operation sequence/glossary/Operation/Sequence/$$. + +$head Derivatives$$ +During a zero order $cref Forward$$ operation, +an $cref ADFun$$ object will compute the value of $icode name$$ +using the user provided $icode Base$$ version of this routine. +All the derivatives of $icode name$$ will be evaluated as zero. + +$head Parallel Mode$$ +The first call to +$codei% + %name%(%ax%) +%$$ +must not be in $cref/parallel/ta_in_parallel/$$ execution mode. + +$head Example$$ +$children% + example/general/tape_index.cpp% + example/general/interp_onetape.cpp% + example/general/interp_retape.cpp +%$$ +The file +$cref tape_index.cpp$$ +contains an example and test that uses a discrete function +to vary an array index during $cref Forward$$ mode calculations. +The file +$cref interp_onetape.cpp$$ +contains an example and test that uses discrete +functions to avoid retaping a calculation that requires interpolation. +(The file +$cref interp_retape.cpp$$ +shows how interpolation can be done with retaping.) + +$head CppADCreateDiscrete Deprecated 2007-07-28$$ +The preprocessor symbol $code CppADCreateDiscrete$$ +is defined to be the same as $code CPPAD_DISCRETE_FUNCTION$$ +but its use is deprecated. + +$end diff --git a/build-config/cppad/include/cppad/core/div.hpp b/build-config/cppad/include/cppad/core/div.hpp new file mode 100644 index 00000000..2d36d445 --- /dev/null +++ b/build-config/cppad/include/cppad/core/div.hpp @@ -0,0 +1,130 @@ +# ifndef CPPAD_CORE_DIV_HPP +# define CPPAD_CORE_DIV_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +// BEGIN CppAD namespace +namespace CppAD { + +template +AD operator / (const AD &left , const AD &right) +{ + // compute the Base part + AD result; + result.value_ = left.value_ / right.value_; + CPPAD_ASSERT_UNKNOWN( Parameter(result) ); + + // check if there is a recording in progress + local::ADTape* tape = AD::tape_ptr(); + if( tape == nullptr ) + return result; + tape_id_t tape_id = tape->id_; + // tape_id cannot match the default value for tape_id_; i.e., 0 + CPPAD_ASSERT_UNKNOWN( tape_id > 0 ); + + // check if left and right tapes match + bool match_left = left.tape_id_ == tape_id; + bool match_right = right.tape_id_ == tape_id; + + // check if left and right are dynamic parameters + bool dyn_left = match_left & (left.ad_type_ == dynamic_enum); + bool dyn_right = match_right & (right.ad_type_ == dynamic_enum); + + // check if left and right are variables + bool var_left = match_left & (left.ad_type_ != dynamic_enum); + bool var_right = match_right & (right.ad_type_ != dynamic_enum); + + CPPAD_ASSERT_KNOWN( + left.tape_id_ == right.tape_id_ || ! match_left || ! match_right , + "Divide: AD variables or dynamic parameters on different threads." + ); + if( var_left ) + { if( var_right ) + { // result = variable / variable + CPPAD_ASSERT_UNKNOWN( local::NumRes(local::DivvvOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( local::NumArg(local::DivvvOp) == 2 ); + + // put operand addresses in tape + tape->Rec_.PutArg(left.taddr_, right.taddr_); + // put operator in the tape + result.taddr_ = tape->Rec_.PutOp(local::DivvvOp); + // make result a variable + result.tape_id_ = tape_id; + result.ad_type_ = variable_enum; + } + else if( (! dyn_right) & IdenticalOne(right.value_) ) + { // result = variable / 1 + result.make_variable(left.tape_id_, left.taddr_); + } + else + { // result = variable / parameter + CPPAD_ASSERT_UNKNOWN( local::NumRes(local::DivvpOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( local::NumArg(local::DivvpOp) == 2 ); + + // put operand addresses in tape + addr_t p = right.taddr_; + if( ! dyn_right ) + p = tape->Rec_.put_con_par(right.value_); + tape->Rec_.PutArg(left.taddr_, p); + // put operator in the tape + result.taddr_ = tape->Rec_.PutOp(local::DivvpOp); + // make result a variable + result.tape_id_ = tape_id; + result.ad_type_ = variable_enum; + } + } + else if( var_right ) + { if( (! dyn_left) & IdenticalZero(left.value_) ) + { // result = 0 / variable + } + else + { // result = parameter / variable + CPPAD_ASSERT_UNKNOWN( local::NumRes(local::DivpvOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( local::NumArg(local::DivpvOp) == 2 ); + + // put operand addresses in tape + addr_t p = left.taddr_; + if( ! dyn_left ) + p = tape->Rec_.put_con_par(left.value_); + tape->Rec_.PutArg(p, right.taddr_); + // put operator in the tape + result.taddr_ = tape->Rec_.PutOp(local::DivpvOp); + // make result a variable + result.tape_id_ = tape_id; + result.ad_type_ = variable_enum; + } + } + else if( dyn_left | dyn_right ) + { addr_t arg0 = left.taddr_; + addr_t arg1 = right.taddr_; + if( ! dyn_left ) + arg0 = tape->Rec_.put_con_par(left.value_); + if( ! dyn_right ) + arg1 = tape->Rec_.put_con_par(right.value_); + // + // parameters with a dynamic parameter result + result.taddr_ = tape->Rec_.put_dyn_par( + result.value_, local::div_dyn, arg0, arg1 + ); + result.tape_id_ = tape_id; + result.ad_type_ = dynamic_enum; + } + return result; +} + +// convert other cases into the case above +CPPAD_FOLD_AD_VALUED_BINARY_OPERATOR(/) + + +} // END CppAD namespace + +# endif diff --git a/build-config/cppad/include/cppad/core/div_eq.hpp b/build-config/cppad/include/cppad/core/div_eq.hpp new file mode 100644 index 00000000..00ccc87b --- /dev/null +++ b/build-config/cppad/include/cppad/core/div_eq.hpp @@ -0,0 +1,129 @@ +# ifndef CPPAD_CORE_DIV_EQ_HPP +# define CPPAD_CORE_DIV_EQ_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +// BEGIN CppAD namespace +namespace CppAD { + +template +AD& AD::operator /= (const AD &right) +{ + // compute the Base part + Base left; + left = value_; + value_ /= right.value_; + + // check if there is a recording in progress + local::ADTape* tape = AD::tape_ptr(); + if( tape == nullptr ) + return *this; + tape_id_t tape_id = tape->id_; + // tape_id cannot match the default value for tape_id_; i.e., 0 + CPPAD_ASSERT_UNKNOWN( tape_id > 0 ); + + // check if left and right tapes match + bool match_left = tape_id_ == tape_id; + bool match_right = right.tape_id_ == tape_id; + + // check if left and right are dynamic parameters + bool dyn_left = match_left & (ad_type_ == dynamic_enum); + bool dyn_right = match_right & (right.ad_type_ == dynamic_enum); + + // check if left and right are variables + bool var_left = match_left & (ad_type_ != dynamic_enum); + bool var_right = match_right & (right.ad_type_ != dynamic_enum); + + CPPAD_ASSERT_KNOWN( + tape_id_ == right.tape_id_ || ! match_left || ! match_right , + "/= : AD variables or dynamic parameters on different threads." + ); + if( var_left ) + { if( var_right ) + { // this = variable / variable + CPPAD_ASSERT_UNKNOWN( local::NumRes(local::DivvvOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( local::NumArg(local::DivvvOp) == 2 ); + + // put operand addresses in tape + tape->Rec_.PutArg(taddr_, right.taddr_); + // put operator in the tape + taddr_ = tape->Rec_.PutOp(local::DivvvOp); + // check that this is a variable + CPPAD_ASSERT_UNKNOWN( tape_id_ == tape_id ); + CPPAD_ASSERT_UNKNOWN( ad_type_ == variable_enum); + } + else if( (! dyn_right) & IdenticalOne(right.value_) ) + { // this = variable * 1 + } + else + { // this = variable / parameter + CPPAD_ASSERT_UNKNOWN( local::NumRes(local::DivvpOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( local::NumArg(local::DivvpOp) == 2 ); + + // put operand addresses in tape + addr_t p = right.taddr_; + if( ! dyn_right ) + p = tape->Rec_.put_con_par(right.value_); + tape->Rec_.PutArg(taddr_, p); + // put operator in the tape + taddr_ = tape->Rec_.PutOp(local::DivvpOp); + // check that this is a variable + CPPAD_ASSERT_UNKNOWN( tape_id_ == tape_id ); + CPPAD_ASSERT_UNKNOWN( ad_type_ == variable_enum); + } + } + else if( var_right ) + { if( (! dyn_left) & IdenticalZero(left) ) + { // this = 0 / variable + } + else + { // this = parameter / variable + CPPAD_ASSERT_UNKNOWN( local::NumRes(local::DivpvOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( local::NumArg(local::DivpvOp) == 2 ); + + // put operand addresses in tape + addr_t p = taddr_; + if( ! dyn_left ) + p = tape->Rec_.put_con_par(left); + tape->Rec_.PutArg(p, right.taddr_); + + // put operator in the tape + taddr_ = tape->Rec_.PutOp(local::DivpvOp); + + // make this a variable + tape_id_ = tape_id; + ad_type_ = variable_enum; + } + } + else if( dyn_left | dyn_right ) + { addr_t arg0 = taddr_; + addr_t arg1 = right.taddr_; + if( ! dyn_left ) + arg0 = tape->Rec_.put_con_par(left); + if( ! dyn_right ) + arg1 = tape->Rec_.put_con_par(right.value_); + // + // parameters with a dynamic parameter results + taddr_ = tape->Rec_.put_dyn_par( + value_, local::div_dyn, arg0, arg1 + ); + tape_id_ = tape_id; + ad_type_ = dynamic_enum; + } + return *this; +} + +CPPAD_FOLD_ASSIGNMENT_OPERATOR(/=) + +} // END CppAD namespace + +# endif diff --git a/build-config/cppad/include/cppad/core/drivers.hpp b/build-config/cppad/include/cppad/core/drivers.hpp new file mode 100644 index 00000000..fd0887fd --- /dev/null +++ b/build-config/cppad/include/cppad/core/drivers.hpp @@ -0,0 +1,22 @@ +# ifndef CPPAD_CORE_DRIVERS_HPP +# define CPPAD_CORE_DRIVERS_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-17 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +# include +# include +# include +# include +# include +# include + +# endif diff --git a/build-config/cppad/include/cppad/core/epsilon.hpp b/build-config/cppad/include/cppad/core/epsilon.hpp new file mode 100644 index 00000000..6bc014b8 --- /dev/null +++ b/build-config/cppad/include/cppad/core/epsilon.hpp @@ -0,0 +1,60 @@ +# ifndef CPPAD_CORE_EPSILON_HPP +# define CPPAD_CORE_EPSILON_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-16 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +/* +------------------------------------------------------------------------------ +$begin epsilon$$ +$spell + std + eps + CppAD + namespace + const +$$ + +$section Machine Epsilon For AD Types$$ + +$head Deprecated 2012-06-17$$ +This routine has been deprecated. +You should use the $cref numeric_limits$$ $code epsilon$$ instead. + +$head Syntax$$ +$icode%eps% = epsilon<%Float%>()%$$ + +$head Purpose$$ +Obtain the value of machine epsilon corresponding +to the type $icode%Float%$$. + +$head Float$$ +this type can either be $codei%AD<%Base%>%$$, +or it can be $icode Base$$ for any $codei%AD<%Base%>%$$ type. + +$head eps$$ +The result $icode eps$$ has prototype +$codei% + %Float% eps +%$$ + +$end +------------------------------------------------------------------------------ +*/ + +namespace CppAD { + + template + inline Type epsilon(void) + { return Type ( numeric_limits::epsilon() ); } + +} +# endif diff --git a/build-config/cppad/include/cppad/core/equal_op_seq.hpp b/build-config/cppad/include/cppad/core/equal_op_seq.hpp new file mode 100644 index 00000000..317f7551 --- /dev/null +++ b/build-config/cppad/include/cppad/core/equal_op_seq.hpp @@ -0,0 +1,118 @@ +# ifndef CPPAD_CORE_EQUAL_OP_SEQ_HPP +# define CPPAD_CORE_EQUAL_OP_SEQ_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-17 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +/* +------------------------------------------------------------------------------ +$begin EqualOpSeq$$ +$spell + Op + const + bool +$$ + + +$section Check if Two Value are Identically Equal$$ + +$head Syntax$$ +$icode%b% = EqualOpSeq(%x%, %y%)%$$ + +$head Purpose$$ +Determine if two $icode x$$ and $icode y$$ are identically equal; i.e., +not only is $icode%x% == %y%$$ true, but +if they are $cref/variables/glossary/Variable/$$, +they correspond have the same +$cref/operation sequence/glossary/Operation/Sequence/$$. + +$head Motivation$$ +Sometimes it is useful to cache information +and only recalculate when a function's arguments change. +In the case of AD variables, +it may be important not only when the argument values are equal, +but when they are related to the +$cref/independent variables/glossary/Tape/Independent Variable/$$ +by the same operation sequence. +After the assignment +$codei% + %y% = %x% +%$$ +these two AD objects would not only have equal values, +but would also correspond to the same operation sequence. + +$head x$$ +The argument $icode x$$ has prototype +$codei% + const AD<%Base%> &%x% +%$$ + +$head y$$ +The argument $icode y$$ has prototype +$codei% + const AD<%Base%> &%y% +%$$ + +$head b$$ +The result $icode b$$ has prototype +$codei% + bool %b% +%$$ +The result is true if and only if one of the following cases holds: + +$list number$$ +Both $icode x$$ and $icode y$$ are variables +and correspond to the same operation sequence. +$lnext +Both $icode x$$ and $icode y$$ are parameters, +$icode Base$$ is an AD type, +and $codei%EqualOpSeq( Value(%x%) , Value(%y%) )%$$ is true. +$lnext +Both $icode x$$ and $icode y$$ are parameters, +$icode Base$$ is not an AD type, +and $icode%x% == %y%%$$ is true. +$lend + + +$head Example$$ +$children% + example/general/equal_op_seq.cpp +%$$ +The file +$cref equal_op_seq.cpp$$ +contains an example and test of $code EqualOpSeq$$. + + +$end +------------------------------------------------------------------------------ +*/ + + +namespace CppAD { + template + CPPAD_INLINE_FRIEND_TEMPLATE_FUNCTION + bool EqualOpSeq(const AD &x, const AD &y) + { + if( Parameter(x) ) + { if( Parameter(y) ) + return EqualOpSeq(x.value_, y.value_); + else + return false; + } + else if( Parameter(y) ) + return false; + + return (x.taddr_ == y.taddr_); + } + +} + +# endif diff --git a/build-config/cppad/include/cppad/core/for_hes_sparsity.hpp b/build-config/cppad/include/cppad/core/for_hes_sparsity.hpp new file mode 100644 index 00000000..284e5e1e --- /dev/null +++ b/build-config/cppad/include/cppad/core/for_hes_sparsity.hpp @@ -0,0 +1,287 @@ +# ifndef CPPAD_CORE_FOR_HES_SPARSITY_HPP +# define CPPAD_CORE_FOR_HES_SPARSITY_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ +/* +$begin for_hes_sparsity$$ +$spell + Andrea Walther + Jacobian + Hessian + jac + hes + bool + const + rc + cpp +$$ + +$section Forward Mode Hessian Sparsity Patterns$$ + +$head Syntax$$ +$icode%f%.for_hes_sparsity( + %select_domain%, %select_range%, %internal_bool%, %pattern_out% +)%$$ + +$head Purpose$$ +We use $latex F : \B{R}^n \rightarrow \B{R}^m$$ to denote the +$cref/AD function/glossary/AD Function/$$ corresponding to +the operation sequence stored in $icode f$$. +Fix a diagonal matrix $latex D \in \B{R}^{n \times n}$$, +a vector $latex s \in \B{R}^m$$ and define the function +$latex \[ + H(x) = D ( s^\R{T} F )^{(2)} ( x ) D +\] $$ +Given the sparsity for $latex D$$ and $latex s$$, +$code for_hes_sparsity$$ computes a sparsity pattern for $latex H(x)$$. + +$head x$$ +Note that the sparsity pattern $latex H(x)$$ corresponds to the +operation sequence stored in $icode f$$ and does not depend on +the argument $icode x$$. + +$head BoolVector$$ +The type $icode BoolVector$$ is a $cref SimpleVector$$ class with +$cref/elements of type/SimpleVector/Elements of Specified Type/$$ +$code bool$$. + +$head SizeVector$$ +The type $icode SizeVector$$ is a $cref SimpleVector$$ class with +$cref/elements of type/SimpleVector/Elements of Specified Type/$$ +$code size_t$$. + +$head f$$ +The object $icode f$$ has prototype +$codei% + ADFun<%Base%> %f% +%$$ + +$head select_domain$$ +The argument $icode select_domain$$ has prototype +$codei% + const %BoolVector%& %select_domain% +%$$ +It has size $latex n$$ and specifies which components of the diagonal of +$latex D$$ are non-zero; i.e., $icode%select_domain%[%j%]%$$ is true +if and only if $latex D_{j,j}$$ is possibly non-zero. + + +$head select_range$$ +The argument $icode select_range$$ has prototype +$codei% + const %BoolVector%& %select_range% +%$$ +It has size $latex m$$ and specifies which components of the vector +$latex s$$ are non-zero; i.e., $icode%select_range%[%i%]%$$ is true +if and only if $latex s_i$$ is possibly non-zero. + +$head internal_bool$$ +If this is true, calculations are done with sets represented by a vector +of boolean values. Otherwise, a vector of sets of integers is used. + +$head pattern_out$$ +This argument has prototype +$codei% + sparse_rc<%SizeVector%>& %pattern_out% +%$$ +This input value of $icode pattern_out$$ does not matter. +Upon return $icode pattern_out$$ is a sparsity pattern for $latex H(x)$$. + +$head Sparsity for Entire Hessian$$ +Suppose that $latex R$$ is the $latex n \times n$$ identity matrix. +In this case, $icode pattern_out$$ is a sparsity pattern for +$latex (s^\R{T} F) F^{(2)} ( x )$$. + +$head Algorithm$$ +See Algorithm II in +$italic Computing sparse Hessians with automatic differentiation$$ +by Andrea Walther. +Note that $icode s$$ provides the information so that +'dead ends' are not included in the sparsity pattern. + +$head Example$$ +$children% + example/sparse/for_hes_sparsity.cpp +%$$ +The file $cref for_hes_sparsity.cpp$$ +contains an example and test of this operation. + +$end +----------------------------------------------------------------------------- +*/ +# include +# include + +namespace CppAD { // BEGIN_CPPAD_NAMESPACE + +/*! +Forward Hessian sparsity patterns. + +\tparam Base +is the base type for this recording. + +\tparam BoolVector +is the simple vector with elements of type bool that is used for +sparsity for the vector s. + +\tparam SizeVector +is the simple vector with elements of type size_t that is used for +row, column index sparsity patterns. + +\param select_domain +is a sparsity pattern for for the diagonal of D. + +\param select_range +is a sparsity pattern for for s. + +\param internal_bool +If this is true, calculations are done with sets represented by a vector +of boolean values. Otherwise, a vector of standard sets is used. + +\param pattern_out +The return value is a sparsity pattern for H(x) where +\f[ + H(x) = D * F^{(1)} (x) * D +\f] +Here F is the function corresponding to the operation sequence +and x is any argument value. +*/ +template +template +void ADFun::for_hes_sparsity( + const BoolVector& select_domain , + const BoolVector& select_range , + bool internal_bool , + sparse_rc& pattern_out ) +{ + // used to identify the RecBase type in calls to sweeps + RecBase not_used_rec_base(0.0); + // + size_t n = Domain(); + size_t m = Range(); + // + CPPAD_ASSERT_KNOWN( + size_t( select_domain.size() ) == n, + "for_hes_sparsity: size of select_domain is not equal to " + "number of independent variables" + ); + CPPAD_ASSERT_KNOWN( + size_t( select_range.size() ) == m, + "for_hes_sparsity: size of select_range is not equal to " + "number of dependent variables" + ); + // do not need transpose or depenency + bool transpose = false; + bool dependency = false; + // + local::pod_vector select_domain_pod_vector(n); + for(size_t j = 0; j < n; ++j) + select_domain_pod_vector[j] = select_domain[j]; + // + sparse_rc pattern_tmp; + if( internal_bool ) + { + // reverse Jacobian sparsity pattern for select_range + local::sparse::pack_setvec internal_rev_jac; + internal_rev_jac.resize(num_var_tape_, 1); + for(size_t i = 0; i < m; i++) if( select_range[i] ) + { CPPAD_ASSERT_UNKNOWN( dep_taddr_[i] < num_var_tape_ ); + // Not using post_element because only adding one element per set + internal_rev_jac.add_element( dep_taddr_[i] , 0 ); + } + // reverse Jacobian sparsity for all variables on tape + local::sweep::rev_jac( + &play_, + dependency, + n, + num_var_tape_, + internal_rev_jac, + not_used_rec_base + ); + // internal vector of sets that will hold Hessian + local::sparse::pack_setvec internal_for_hes; + internal_for_hes.resize(n + 1 + num_var_tape_, n + 1); + // + // compute forward Hessian sparsity pattern + local::sweep::for_hes( + &play_, + n, + num_var_tape_, + select_domain_pod_vector, + internal_rev_jac, + internal_for_hes, + not_used_rec_base + ); + // + // put the result in pattern_tmp + local::sparse::get_internal_pattern( + transpose, ind_taddr_, internal_for_hes, pattern_tmp + ); + } + else + { + // reverse Jacobian sparsity pattern for select_range + // (corresponds to s) + local::sparse::list_setvec internal_rev_jac; + internal_rev_jac.resize(num_var_tape_, 1); + for(size_t i = 0; i < m; i++) if( select_range[i] ) + { CPPAD_ASSERT_UNKNOWN( dep_taddr_[i] < num_var_tape_ ); + // Not using post_element because only adding one element per set + internal_rev_jac.add_element( dep_taddr_[i] , 0 ); + } + // reverse Jacobian sparsity for all variables on tape + local::sweep::rev_jac( + &play_, + dependency, + n, + num_var_tape_, + internal_rev_jac, + not_used_rec_base + + ); + // internal vector of sets that will hold Hessian + local::sparse::list_setvec internal_for_hes; + internal_for_hes.resize(n + 1 + num_var_tape_, n + 1); + // + // compute forward Hessian sparsity pattern + local::sweep::for_hes( + &play_, + n, + num_var_tape_, + select_domain_pod_vector, + internal_rev_jac, + internal_for_hes, + not_used_rec_base + ); + // + // put the result in pattern_tmp + local::sparse::get_internal_pattern( + transpose, ind_taddr_, internal_for_hes, pattern_tmp + ); + } + // subtract 1 from all column values + CPPAD_ASSERT_UNKNOWN( pattern_tmp.nr() == n ); + CPPAD_ASSERT_UNKNOWN( pattern_tmp.nc() == n + 1 ); + const SizeVector& row( pattern_tmp.row() ); + const SizeVector& col( pattern_tmp.col() ); + size_t nr = n; + size_t nc = n; + size_t nnz = pattern_tmp.nnz(); + pattern_out.resize(nr, nc, nnz); + for(size_t k = 0; k < nnz; k++) + { CPPAD_ASSERT_UNKNOWN( 0 < col[k] ); + pattern_out.set(k, row[k], col[k] - 1); + } + return; +} +} // END_CPPAD_NAMESPACE +# endif diff --git a/build-config/cppad/include/cppad/core/for_jac_sparsity.hpp b/build-config/cppad/include/cppad/core/for_jac_sparsity.hpp new file mode 100644 index 00000000..c29a0e58 --- /dev/null +++ b/build-config/cppad/include/cppad/core/for_jac_sparsity.hpp @@ -0,0 +1,305 @@ +# ifndef CPPAD_CORE_FOR_JAC_SPARSITY_HPP +# define CPPAD_CORE_FOR_JAC_SPARSITY_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ +/* +$begin for_jac_sparsity$$ +$spell + Jacobian + jac + bool + const + rc + cpp +$$ + +$section Forward Mode Jacobian Sparsity Patterns$$ + +$head Syntax$$ +$icode%f%.for_jac_sparsity( + %pattern_in%, %transpose%, %dependency%, %internal_bool%, %pattern_out% +)%$$ + +$head Purpose$$ +We use $latex F : \B{R}^n \rightarrow \B{R}^m$$ to denote the +$cref/AD function/glossary/AD Function/$$ corresponding to +the operation sequence stored in $icode f$$. +Fix $latex R \in \B{R}^{n \times \ell}$$ and define the function +$latex \[ + J(x) = F^{(1)} ( x ) * R +\] $$ +Given the $cref/sparsity pattern/glossary/Sparsity Pattern/$$ for $latex R$$, +$code for_jac_sparsity$$ computes a sparsity pattern for $latex J(x)$$. + +$head x$$ +Note that the sparsity pattern $latex J(x)$$ corresponds to the +operation sequence stored in $icode f$$ and does not depend on +the argument $icode x$$. +(The operation sequence may contain +$cref CondExp$$ and $cref VecAD$$ operations.) + +$head SizeVector$$ +The type $icode SizeVector$$ is a $cref SimpleVector$$ class with +$cref/elements of type/SimpleVector/Elements of Specified Type/$$ +$code size_t$$. + +$head f$$ +The object $icode f$$ has prototype +$codei% + ADFun<%Base%> %f% +%$$ +The $cref ADFun$$ object $icode f$$ is not $code const$$. +After a call to $code for_jac_sparsity$$, a sparsity pattern +for each of the variables in the operation sequence +is held in $icode f$$ for possible later use during +reverse Hessian sparsity calculations. + +$subhead size_forward_bool$$ +After $code for_jac_sparsity$$, if $icode k$$ is a $code size_t$$ object, +$codei% + %k% = %f%.size_forward_bool() +%$$ +sets $icode k$$ to the amount of memory (in unsigned character units) +used to store the +$cref/boolean vector/glossary/Sparsity Pattern/Boolean Vector/$$ +sparsity patterns. +If $icode internal_bool$$ if false, $icode k$$ will be zero. +Otherwise it will be non-zero. +If you do not need this information for $cref RevSparseHes$$ +calculations, it can be deleted +(and the corresponding memory freed) using +$codei% + %f%.size_forward_bool(0) +%$$ +after which $icode%f%.size_forward_bool()%$$ will return zero. + +$subhead size_forward_set$$ +After $code for_jac_sparsity$$, if $icode k$$ is a $code size_t$$ object, +$codei% + %k% = %f%.size_forward_set() +%$$ +sets $icode k$$ to the amount of memory (in unsigned character units) +used to store the +$cref/vector of sets/glossary/Sparsity Pattern/Vector of Sets/$$ +sparsity patterns. +If $icode internal_bool$$ if true, $icode k$$ will be zero. +Otherwise it will be non-zero. +If you do not need this information for future $cref rev_hes_sparsity$$ +calculations, it can be deleted +(and the corresponding memory freed) using +$codei% + %f%.size_forward_set(0) +%$$ +after which $icode%f%.size_forward_set()%$$ will return zero. + +$head pattern_in$$ +The argument $icode pattern_in$$ has prototype +$codei% + const sparse_rc<%SizeVector%>& %pattern_in% +%$$ +see $cref sparse_rc$$. +If $icode transpose$$ it is false (true), +$icode pattern_in$$ is a sparsity pattern for $latex R$$ ($latex R^\R{T}$$). + +$head transpose$$ +This argument has prototype +$codei% + bool %transpose% +%$$ +See $cref/pattern_in/for_jac_sparsity/pattern_in/$$ above and +$cref/pattern_out/for_jac_sparsity/pattern_out/$$ below. + +$head dependency$$ +This argument has prototype +$codei% + bool %dependency% +%$$ +see $cref/pattern_out/for_jac_sparsity/pattern_out/$$ below. + +$head internal_bool$$ +This argument has prototype +$codei% + bool %internal_bool% +%$$ +If this is true, calculations are done with sets represented by a vector +of boolean values. Otherwise, a vector of sets of integers is used. + +$head pattern_out$$ +This argument has prototype +$codei% + sparse_rc<%SizeVector%>& %pattern_out% +%$$ +This input value of $icode pattern_out$$ does not matter. +If $icode transpose$$ it is false (true), +upon return $icode pattern_out$$ is a sparsity pattern for +$latex J(x)$$ ($latex J(x)^\R{T}$$). +If $icode dependency$$ is true, $icode pattern_out$$ is a +$cref/dependency pattern/dependency.cpp/Dependency Pattern/$$ +instead of sparsity pattern. + +$head Sparsity for Entire Jacobian$$ +Suppose that +$latex R$$ is the $latex n \times n$$ identity matrix. +In this case, $icode pattern_out$$ is a sparsity pattern for +$latex F^{(1)} ( x )$$ ( $latex F^{(1)} (x)^\R{T}$$ ) +if $icode transpose$$ is false (true). + +$head Example$$ +$children% + example/sparse/for_jac_sparsity.cpp +%$$ +The file +$cref for_jac_sparsity.cpp$$ +contains an example and test of this operation. + +$end +----------------------------------------------------------------------------- +*/ +# include +# include + +namespace CppAD { // BEGIN_CPPAD_NAMESPACE + +/*! +Forward Jacobian sparsity patterns. + +\tparam Base +is the base type for this recording. + +\tparam SizeVector +is the simple vector with elements of type size_t that is used for +row, column index sparsity patterns. + +\param pattern_in +is the sparsity pattern for for R or R^T depending on transpose. + +\param transpose +Is the input and returned sparsity pattern transposed. + +\param dependency +Are the derivatives with respect to left and right of the expression below +considered to be non-zero: +\code + CondExpRel(left, right, if_true, if_false) +\endcode +This is used by the optimizer to obtain the correct dependency relations. + +\param internal_bool +If this is true, calculations are done with sets represented by a vector +of boolean values. Othewise, a vector of standard sets is used. + +\param pattern_out +The value of transpose is false (true), +the return value is a sparsity pattern for J(x) ( J(x)^T ) where +\f[ + J(x) = F^{(1)} (x) * R +\f] +Here F is the function corresponding to the operation sequence +and x is any argument value. +*/ +template +template +void ADFun::for_jac_sparsity( + const sparse_rc& pattern_in , + bool transpose , + bool dependency , + bool internal_bool , + sparse_rc& pattern_out ) +{ + // used to identify the RecBase type in calls to sweeps + RecBase not_used_rec_base(0.0); + // + // number or rows, columns, and non-zeros in pattern_in + size_t nr_in = pattern_in.nr(); + size_t nc_in = pattern_in.nc(); + // + size_t n = nr_in; + size_t ell = nc_in; + if( transpose ) + std::swap(n, ell); + // + CPPAD_ASSERT_KNOWN( + n == Domain() , + "for_jac_sparsity: number rows in R " + "is not equal number of independent variables." + ); + bool zero_empty = true; + bool input_empty = true; + if( internal_bool ) + { // allocate memory for bool sparsity calculation + // (sparsity pattern is emtpy after a resize) + for_jac_sparse_pack_.resize(num_var_tape_, ell); + for_jac_sparse_set_.resize(0, 0); + // + // set sparsity patttern for independent variables + local::sparse::set_internal_pattern( + zero_empty , + input_empty , + transpose , + ind_taddr_ , + for_jac_sparse_pack_ , + pattern_in + ); + + // compute sparsity for other variables + local::sweep::for_jac( + &play_, + dependency, + n, + num_var_tape_, + for_jac_sparse_pack_, + not_used_rec_base + + ); + // set the output pattern + local::sparse::get_internal_pattern( + transpose, dep_taddr_, for_jac_sparse_pack_, pattern_out + ); + } + else + { + // allocate memory for set sparsity calculation + // (sparsity pattern is emtpy after a resize) + for_jac_sparse_set_.resize(num_var_tape_, ell); + for_jac_sparse_pack_.resize(0, 0); + // + // set sparsity patttern for independent variables + local::sparse::set_internal_pattern( + zero_empty , + input_empty , + transpose , + ind_taddr_ , + for_jac_sparse_set_ , + pattern_in + ); + + // compute sparsity for other variables + local::sweep::for_jac( + &play_, + dependency, + n, + num_var_tape_, + for_jac_sparse_set_, + not_used_rec_base + + ); + // get the ouput pattern + local::sparse::get_internal_pattern( + transpose, dep_taddr_, for_jac_sparse_set_, pattern_out + ); + } + return; +} + + +} // END_CPPAD_NAMESPACE +# endif diff --git a/build-config/cppad/include/cppad/core/for_one.hpp b/build-config/cppad/include/cppad/core/for_one.hpp new file mode 100644 index 00000000..0162a0a1 --- /dev/null +++ b/build-config/cppad/include/cppad/core/for_one.hpp @@ -0,0 +1,163 @@ +# ifndef CPPAD_CORE_FOR_ONE_HPP +# define CPPAD_CORE_FOR_ONE_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-18 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +/* +$begin ForOne$$ +$spell + dy + typename + Taylor + const +$$ + + + + +$section First Order Partial Derivative: Driver Routine$$ + +$head Syntax$$ +$icode%dy% = %f%.ForOne(%x%, %j%)%$$ + + +$head Purpose$$ +We use $latex F : \B{R}^n \rightarrow \B{R}^m$$ to denote the +$cref/AD function/glossary/AD Function/$$ corresponding to $icode f$$. +The syntax above sets $icode dy$$ to the +partial of $latex F$$ with respect to $latex x_j$$; i.e., +$latex \[ +dy += \D{F}{ x_j } (x) += \left[ + \D{ F_0 }{ x_j } (x) , \cdots , \D{ F_{m-1} }{ x_j } (x) +\right] +\] $$ + +$head f$$ +The object $icode f$$ has prototype +$codei% + ADFun<%Base%> %f% +%$$ +Note that the $cref ADFun$$ object $icode f$$ is not $code const$$ +(see $cref/ForOne Uses Forward/ForOne/ForOne Uses Forward/$$ below). + +$head x$$ +The argument $icode x$$ has prototype +$codei% + const %Vector% &%x% +%$$ +(see $cref/Vector/ForOne/Vector/$$ below) +and its size +must be equal to $icode n$$, the dimension of the +$cref/domain/seq_property/Domain/$$ space for $icode f$$. +It specifies +that point at which to evaluate the partial derivative. + +$head j$$ +The argument $icode j$$ has prototype +$codei% + size_t %j% +%$$ +an is less than $icode n$$, +$cref/domain/seq_property/Domain/$$ space for $icode f$$. +It specifies the component of $icode F$$ +for which we are computing the partial derivative. + +$head dy$$ +The result $icode dy$$ has prototype +$codei% + %Vector% %dy% +%$$ +(see $cref/Vector/ForOne/Vector/$$ below) +and its size is $latex m$$, the dimension of the +$cref/range/seq_property/Range/$$ space for $icode f$$. +The value of $icode dy$$ is the partial of $latex F$$ with respect to +$latex x_j$$ evaluated at $icode x$$; i.e., +for $latex i = 0 , \ldots , m - 1$$ +$latex \[. + dy[i] = \D{ F_i }{ x_j } ( x ) +\] $$ + + +$head Vector$$ +The type $icode Vector$$ must be a $cref SimpleVector$$ class with +$cref/elements of type/SimpleVector/Elements of Specified Type/$$ +$icode Base$$. +The routine $cref CheckSimpleVector$$ will generate an error message +if this is not the case. + +$head ForOne Uses Forward$$ +After each call to $cref Forward$$, +the object $icode f$$ contains the corresponding +$cref/Taylor coefficients/glossary/Taylor Coefficient/$$. +After a call to $code ForOne$$, +the zero order Taylor coefficients correspond to +$icode%f%.Forward(0,%x%)%$$ +and the other coefficients are unspecified. + +$head Example$$ +$children% + example/general/for_one.cpp +%$$ +The routine +$cref/ForOne/for_one.cpp/$$ is both an example and test. +It returns $code true$$, if it succeeds and $code false$$ otherwise. + +$end +----------------------------------------------------------------------------- +*/ + +// BEGIN CppAD namespace +namespace CppAD { + +template +template +Vector ADFun::ForOne(const Vector &x, size_t j) +{ size_t j1; + + size_t n = Domain(); + size_t m = Range(); + + // check Vector is Simple Vector class with Base type elements + CheckSimpleVector(); + + CPPAD_ASSERT_KNOWN( + x.size() == n, + "ForOne: Length of x not equal domain dimension for f" + ); + CPPAD_ASSERT_KNOWN( + j < n, + "ForOne: the index j is not less than domain dimension for f" + ); + + // point at which we are evaluating the second partials + Forward(0, x); + + // direction in which are are taking the derivative + Vector dx(n); + for(j1 = 0; j1 < n; j1++) + dx[j1] = Base(0.0); + dx[j] = Base(1.0); + + // dimension the return value + Vector dy(m); + + // compute the return value + dy = Forward(1, dx); + + return dy; +} + +} // END CppAD namespace + +# endif diff --git a/build-config/cppad/include/cppad/core/for_sparse_hes.hpp b/build-config/cppad/include/cppad/core/for_sparse_hes.hpp new file mode 100644 index 00000000..16811b74 --- /dev/null +++ b/build-config/cppad/include/cppad/core/for_sparse_hes.hpp @@ -0,0 +1,566 @@ +# ifndef CPPAD_CORE_FOR_SPARSE_HES_HPP +# define CPPAD_CORE_FOR_SPARSE_HES_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +/* +$begin ForSparseHes$$ +$spell + Andrea Walther + std + VecAD + Jacobian + Jac + Hessian + Hes + const + Bool + Dep + proportional + var + cpp +$$ + +$section Hessian Sparsity Pattern: Forward Mode$$ + +$head Syntax$$ +$icode%h% = %f%.ForSparseHes(%r%, %s%) +%$$ + +$head Purpose$$ +We use $latex F : \B{R}^n \rightarrow \B{R}^m$$ to denote the +$cref/AD function/glossary/AD Function/$$ corresponding to $icode f$$. +we define +$latex \[ +\begin{array}{rcl} +H(x) +& = & \partial_x \left[ \partial_u S \cdot F[ x + R \cdot u ] \right]_{u=0} +\\ +& = & R^\R{T} \cdot (S \cdot F)^{(2)} ( x ) \cdot R +\end{array} +\] $$ +Where $latex R \in \B{R}^{n \times n}$$ is a diagonal matrix +and $latex S \in \B{R}^{1 \times m}$$ is a row vector. +Given a +$cref/sparsity pattern/glossary/Sparsity Pattern/$$ +for the diagonal of $latex R$$ and the vector $latex S$$, +$code ForSparseHes$$ returns a sparsity pattern for the $latex H(x)$$. + +$head f$$ +The object $icode f$$ has prototype +$codei% + const ADFun<%Base%> %f% +%$$ + +$head x$$ +If the operation sequence in $icode f$$ is +$cref/independent/glossary/Operation/Independent/$$ of +the independent variables in $latex x \in \B{R}^n$$, +the sparsity pattern is valid for all values of +(even if it has $cref CondExp$$ or $cref VecAD$$ operations). + +$head r$$ +The argument $icode r$$ has prototype +$codei% + const %SetVector%& %r% +%$$ +(see $cref/SetVector/ForSparseHes/SetVector/$$ below) +If it has elements of type $code bool$$, +its size is $latex n$$. +If it has elements of type $code std::set$$, +its size is one and all the elements of $icode%s%[0]%$$ +are between zero and $latex n - 1$$. +It specifies a +$cref/sparsity pattern/glossary/Sparsity Pattern/$$ +for the diagonal of $latex R$$. +The fewer non-zero elements in this sparsity pattern, +the faster the calculation should be and the more sparse +$latex H(x)$$ should be. + +$head s$$ +The argument $icode s$$ has prototype +$codei% + const %SetVector%& %s% +%$$ +(see $cref/SetVector/ForSparseHes/SetVector/$$ below) +If it has elements of type $code bool$$, +its size is $latex m$$. +If it has elements of type $code std::set$$, +its size is one and all the elements of $icode%s%[0]%$$ +are between zero and $latex m - 1$$. +It specifies a +$cref/sparsity pattern/glossary/Sparsity Pattern/$$ +for the vector $icode S$$. +The fewer non-zero elements in this sparsity pattern, +the faster the calculation should be and the more sparse +$latex H(x)$$ should be. + +$head h$$ +The result $icode h$$ has prototype +$codei% + %SetVector%& %h% +%$$ +(see $cref/SetVector/ForSparseHes/SetVector/$$ below). +If $icode h$$ has elements of type $code bool$$, +its size is $latex n * n$$. +If it has elements of type $code std::set$$, +its size is $latex n$$ and all the set elements are between +zero and $icode%n%-1%$$ inclusive. +It specifies a +$cref/sparsity pattern/glossary/Sparsity Pattern/$$ +for the matrix $latex H(x)$$. + +$head SetVector$$ +The type $icode SetVector$$ must be a $cref SimpleVector$$ class with +$cref/elements of type/SimpleVector/Elements of Specified Type/$$ +$code bool$$ or $code std::set$$; +see $cref/sparsity pattern/glossary/Sparsity Pattern/$$ for a discussion +of the difference. +The type of the elements of +$cref/SetVector/ForSparseHes/SetVector/$$ must be the +same as the type of the elements of $icode r$$. + +$head Algorithm$$ +See Algorithm II in +$italic Computing sparse Hessians with automatic differentiation$$ +by Andrea Walther. +Note that $icode s$$ provides the information so that +'dead ends' are not included in the sparsity pattern. + +$head Example$$ +$children% + example/sparse/for_sparse_hes.cpp +%$$ +The file +$cref for_sparse_hes.cpp$$ +contains an example and test of this operation. + +$end +----------------------------------------------------------------------------- +*/ +# include +# include +# include + +namespace CppAD { // BEGIN_CPPAD_NAMESPACE +/*! +\file core/for_sparse_hes.hpp +Forward mode Hessian sparsity patterns. +*/ +// =========================================================================== +// ForSparseHesCase +/*! +Private helper function for ForSparseHes(q, s) bool sparsity. + +All of the description in the public member function ForSparseHes(q, s) +applies. + +\param set_type +is a bool value. This argument is used to dispatch to the proper source +code depending on the vlaue of SetVector::value_type. + +\param r +See ForSparseHes(r, s). + +\param s +See ForSparseHes(r, s). + +\param h +is the return value for the corresponging call to ForSparseJac(q, s). +*/ +template +template +void ADFun::ForSparseHesCase( + bool set_type , + const SetVector& r , + const SetVector& s , + SetVector& h ) +{ + // used to identify the RecBase type in calls to sweeps + RecBase not_used_rec_base(0.0); + // + size_t n = Domain(); + size_t m = Range(); + // + // check Vector is Simple SetVector class with bool elements + CheckSimpleVector(); + // + CPPAD_ASSERT_KNOWN( + size_t(r.size()) == n, + "ForSparseHes: size of r is not equal to\n" + "domain dimension for ADFun object." + ); + CPPAD_ASSERT_KNOWN( + size_t(s.size()) == m, + "ForSparseHes: size of s is not equal to\n" + "range dimension for ADFun object." + ); + // + // select_domain corresponding to r + local::pod_vector select_domain(n); + for(size_t j = 0; j < n; ++j) + { select_domain[j] = r[j]; + CPPAD_ASSERT_UNKNOWN( ind_taddr_[j] == j + 1); + CPPAD_ASSERT_UNKNOWN( play_.GetOp(j + 1) == local::InvOp ); + } + // sparsity pattern correspnding to s + local::sparse::pack_setvec rev_jac_pattern; + rev_jac_pattern.resize(num_var_tape_, 1); + for(size_t i = 0; i < m; i++) + { CPPAD_ASSERT_UNKNOWN( dep_taddr_[i] < num_var_tape_ ); + // + // Not using post_element because only adding one element per set + if( s[i] ) + rev_jac_pattern.add_element( dep_taddr_[i], 0); + } + // compute reverse sparsity pattern for dependency analysis + // (note that we are only want non-zero derivatives not true dependency) + bool dependency = false; + local::sweep::rev_jac( + &play_, + dependency, + n, + num_var_tape_, + rev_jac_pattern, + not_used_rec_base + ); + // vector of sets that will hold the forward Hessain values + local::sparse::pack_setvec for_hes_pattern; + for_hes_pattern.resize(n+1+num_var_tape_, n+1); + // + // compute the Hessian sparsity patterns + local::sweep::for_hes( + &play_, + n, + num_var_tape_, + select_domain, + rev_jac_pattern, + for_hes_pattern, + not_used_rec_base + + ); + // initialize return values corresponding to independent variables + h.resize(n * n); + for(size_t i = 0; i < n; i++) + { for(size_t j = 0; j < n; j++) + h[ i * n + j ] = false; + } + // copy to result pattern + CPPAD_ASSERT_UNKNOWN( for_hes_pattern.end() == n+1 ); + for(size_t i = 0; i < n; i++) + { // ind_taddr_[i] is operator taddr for i-th independent variable + CPPAD_ASSERT_UNKNOWN( ind_taddr_[i] == i + 1 ); + CPPAD_ASSERT_UNKNOWN( play_.GetOp( ind_taddr_[i] ) == local::InvOp ); + + // extract the result from for_hes_pattern + local::sparse::pack_setvec::const_iterator itr(for_hes_pattern, ind_taddr_[i] ); + size_t j = *itr; + while( j < for_hes_pattern.end() ) + { CPPAD_ASSERT_UNKNOWN( 0 < j ) + h[ i * n + (j-1) ] = true; + j = *(++itr); + } + } +} +/*! +Private helper function for ForSparseHes(q, s) set sparsity. + +All of the description in the public member function ForSparseHes(q, s) +applies. + +\param set_type +is a std::set value. +This argument is used to dispatch to the proper source +code depending on the vlaue of SetVector::value_type. + +\param r +See ForSparseHes(r, s). + +\param s +See ForSparseHes(q, s). + +\param h +is the return value for the corresponging call to ForSparseJac(q, s). +*/ +template +template +void ADFun::ForSparseHesCase( + const std::set& set_type , + const SetVector& r , + const SetVector& s , + SetVector& h ) +{ + // used to identify the RecBase type in calls to sweeps + RecBase not_used_rec_base(0.0); + // + size_t n = Domain(); +# ifndef NDEBUG + size_t m = Range(); +# endif + std::set::const_iterator itr_1; + // + // check SetVector is Simple Vector class with sets for elements + CheckSimpleVector, SetVector>( + local::one_element_std_set(), local::two_element_std_set() + ); + CPPAD_ASSERT_KNOWN( + r.size() == 1, + "ForSparseHes: size of s is not equal to one." + ); + CPPAD_ASSERT_KNOWN( + s.size() == 1, + "ForSparseHes: size of s is not equal to one." + ); + // + // select_domain corresponding to r + local::pod_vector select_domain(n); + for(size_t j = 0; j < n; ++j) + { select_domain[j] = false; + CPPAD_ASSERT_UNKNOWN( ind_taddr_[j] == j + 1); + CPPAD_ASSERT_UNKNOWN( play_.GetOp(j + 1) == local::InvOp ); + } + itr_1 = r[0].begin(); + while( itr_1 != r[0].end() ) + { size_t j = *itr_1++; + select_domain[j] = true; + } + // sparsity pattern correspnding to s + local::sparse::list_setvec rev_jac_pattern; + rev_jac_pattern.resize(num_var_tape_, 1); + itr_1 = s[0].begin(); + while( itr_1 != s[0].end() ) + { size_t i = *itr_1++; + CPPAD_ASSERT_KNOWN( + i < m, + "ForSparseHes: an element of the set s[0] has value " + "greater than or equal m" + ); + CPPAD_ASSERT_UNKNOWN( dep_taddr_[i] < num_var_tape_ ); + // + // Not using post_element because only adding one element per set + rev_jac_pattern.add_element( dep_taddr_[i], 0); + } + // + // compute reverse sparsity pattern for dependency analysis + // (note that we are only want non-zero derivatives not true dependency) + bool dependency = false; + local::sweep::rev_jac( + &play_, + dependency, + n, + num_var_tape_, + rev_jac_pattern, + not_used_rec_base + ); + // + // vector of sets that will hold reverse Hessain values + local::sparse::list_setvec for_hes_pattern; + for_hes_pattern.resize(n+1+num_var_tape_, n+1); + // + // compute the Hessian sparsity patterns + local::sweep::for_hes( + &play_, + n, + num_var_tape_, + select_domain, + rev_jac_pattern, + for_hes_pattern, + not_used_rec_base + + ); + // return values corresponding to independent variables + // j is index corresponding to reverse mode partial + h.resize(n); + CPPAD_ASSERT_UNKNOWN( for_hes_pattern.end() == n+1 ); + for(size_t i = 0; i < n; i++) + { CPPAD_ASSERT_UNKNOWN( ind_taddr_[i] == i + 1 ); + CPPAD_ASSERT_UNKNOWN( play_.GetOp( ind_taddr_[i] ) == local::InvOp ); + + // extract the result from for_hes_pattern + local::sparse::list_setvec::const_iterator itr_2(for_hes_pattern, ind_taddr_[i] ); + size_t j = *itr_2; + while( j < for_hes_pattern.end() ) + { CPPAD_ASSERT_UNKNOWN( 0 < j ) + h[i].insert(j-1); + j = *(++itr_2); + } + } +} + +// =========================================================================== +// ForSparseHes + +/*! +User API for Hessian sparsity patterns using reverse mode. + +The C++ source code corresponding to this operation is +\verbatim + h = f.ForSparseHes(q, r) +\endverbatim + +\tparam Base +is the base type for this recording. + +\tparam SetVector +is a simple vector with elements of type bool +or std::set. + +\param r +is a vector with size n that specifies the sparsity pattern +for the diagonal of the matrix \f$ R \f$, +where n is the number of independent variables +corresponding to the operation sequence stored in play. + +\param s +is a vector with size m that specifies the sparsity pattern +for the vector \f$ S \f$, +where m is the number of dependent variables +corresponding to the operation sequence stored in play. + +\return +The return vector is a sparsity pattern for \f$ H(x) \f$ +\f[ + H(x) = R^T ( S * F)^{(2)} (x) R +\f] +where \f$ F \f$ is the function corresponding to the operation sequence +and x is any argument value. +*/ + +template +template +SetVector ADFun::ForSparseHes( + const SetVector& r, const SetVector& s +) +{ + SetVector h; + typedef typename SetVector::value_type Set_type; + + // Should check to make sure q is same as in previous call to + // forward sparse Jacobian. + ForSparseHesCase( + Set_type() , + r , + s , + h + ); + + return h; +} +// =========================================================================== +// ForSparseHesCheckpoint +/*! +Hessian sparsity patterns calculation used by checkpoint functions. + +\tparam Base +is the base type for this recording. + +\param r +is a vector with size n that specifies the sparsity pattern +for the diagonal of \f$ R \f$, +where n is the number of independent variables +corresponding to the operation sequence stored in play_. + +\param s +is a vector with size m that specifies the sparsity pattern +for the vector \f$ S \f$, +where m is the number of dependent variables +corresponding to the operation sequence stored in play_. + +\param h +The input size and elements of h do not matter. +On output, h is the sparsity pattern for the matrix \f$ H(x) R \f$. + +\par Assumptions +The forward jacobian sparsity pattern must be currently stored +in this ADFUN object. +*/ + +// The checkpoint class is not yet using forward sparse Hessians. +# ifdef CPPAD_NOT_DEFINED +template +void ADFun::ForSparseHesCheckpoint( + vector& r , + vector& s , + local::sparse::list_setvec& h ) +{ + // used to identify the RecBase type in calls to sweeps + RecBase not_used_rec_base(0.0); + // + + size_t n = Domain(); + size_t m = Range(); + + // checkpoint functions should get this right + CPPAD_ASSERT_UNKNOWN( for_jac_sparse_pack_.n_set() == 0 ); + CPPAD_ASSERT_UNKNOWN( for_jac_sparse_set_.n_set() == 0 ); + CPPAD_ASSERT_UNKNOWN( s.size() == m ); + + // Array that holds the reverse Jacobiain dependcy flags. + // Initialize as true for dependent variables, flase for others. + local::pod_vector RevJac(num_var_tape_); + for(size_t i = 0; i < num_var_tape_; i++) + RevJac[i] = false; + for(size_t i = 0; i < m; i++) + { CPPAD_ASSERT_UNKNOWN( dep_taddr_[i] < num_var_tape_ ) + RevJac[ dep_taddr_[i] ] = s[i]; + } + + // holds forward Hessian sparsity pattern for all variables + local::sparse::list_setvec for_hes_pattern; + for_hes_pattern.resize(n+1+num_var_tape_, n+1); + + // compute Hessian sparsity pattern for all variables + local::sweep::for_hes( + &play_, + n, + num_var_tape_, + for_jac_sparse_set_, + RevJac.data(), + for_hes_pattern, + not_used_rec_base + + ); + + // dimension the return value + if( transpose ) + h.resize(n, n); + else + h.resize(n, n); + + // j is index corresponding to reverse mode partial + for(size_t j = 0; j < n; j++) + { CPPAD_ASSERT_UNKNOWN( ind_taddr_[j] < num_var_tape_ ); + + // ind_taddr_[j] is operator taddr for j-th independent variable + CPPAD_ASSERT_UNKNOWN( ind_taddr_[j] == j + 1 ); + CPPAD_ASSERT_UNKNOWN( play_.GetOp( ind_taddr_[j] ) == local::InvOp ); + + // extract the result from for_hes_pattern + CPPAD_ASSERT_UNKNOWN( for_hes_pattern.end() == q ); + local::sparse::list_setvec::const_iterator itr(for_hes_pattern, .j + 1); + size_t i = *itr; + while( i < q ) + { if( transpose ) + h.post_element(j, i); + else + h.post_element(i, j); + i = *(++itr); + } + } + // process posts + for(size_t i = 0; i < n; ++i) + h.process_post(i); +} +# endif + +} // END_CPPAD_NAMESPACE +# endif diff --git a/build-config/cppad/include/cppad/core/for_sparse_jac.hpp b/build-config/cppad/include/cppad/core/for_sparse_jac.hpp new file mode 100644 index 00000000..991ccfa7 --- /dev/null +++ b/build-config/cppad/include/cppad/core/for_sparse_jac.hpp @@ -0,0 +1,764 @@ +# ifndef CPPAD_CORE_FOR_SPARSE_JAC_HPP +# define CPPAD_CORE_FOR_SPARSE_JAC_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +/* +$begin ForSparseJac$$ +$spell + std + var + Jacobian + Jac + const + Bool + proportional + VecAD + CondExpRel + optimizer + cpp +$$ + +$section Jacobian Sparsity Pattern: Forward Mode$$ + +$head Syntax$$ +$icode%s% = %f%.ForSparseJac(%q%, %r%) +%$$ +$icode%s% = %f%.ForSparseJac(%q%, %r%, %transpose%, %dependency%)%$$ + +$head Purpose$$ +We use $latex F : \B{R}^n \rightarrow \B{R}^m$$ to denote the +$cref/AD function/glossary/AD Function/$$ corresponding to $icode f$$. +For a fixed $latex n \times q$$ matrix $latex R$$, +the Jacobian of $latex F[ x + R * u ]$$ +with respect to $latex u$$ at $latex u = 0$$ is +$latex \[ + S(x) = F^{(1)} ( x ) * R +\] $$ +Given a +$cref/sparsity pattern/glossary/Sparsity Pattern/$$ +for $latex R$$, +$code ForSparseJac$$ returns a sparsity pattern for the $latex S(x)$$. + +$head f$$ +The object $icode f$$ has prototype +$codei% + ADFun<%Base%> %f% +%$$ +Note that the $cref ADFun$$ object $icode f$$ is not $code const$$. +After a call to $code ForSparseJac$$, the sparsity pattern +for each of the variables in the operation sequence +is held in $icode f$$ (for possible later use by $cref RevSparseHes$$). +These sparsity patterns are stored with elements of type $code bool$$ +or elements of type $code std::set$$ +(see $cref/SetVector/ForSparseJac/SetVector/$$ below). + +$subhead size_forward_bool$$ +After $code ForSparseJac$$, if $icode k$$ is a $code size_t$$ object, +$codei% + %k% = %f%.size_forward_bool() +%$$ +sets $icode k$$ to the amount of memory (in unsigned character units) +used to store the sparsity pattern with elements of type $code bool$$ +in the function object $icode f$$. +If the sparsity patterns for the previous $code ForSparseJac$$ used +elements of type $code bool$$, +the return value for $code size_forward_bool$$ will be non-zero. +Otherwise, its return value will be zero. +This sparsity pattern is stored for use by $cref RevSparseHes$$ and +when it is not longer needed, it can be deleted +(and the corresponding memory freed) using +$codei% + %f%.size_forward_bool(0) +%$$ +After this call, $icode%f%.size_forward_bool()%$$ will return zero. + +$subhead size_forward_set$$ +After $code ForSparseJac$$, if $icode k$$ is a $code size_t$$ object, +$codei% + %k% = %f%.size_forward_set() +%$$ +sets $icode k$$ to the amount of memory (in unsigned character units) +used to store the +$cref/vector of sets/glossary/Sparsity Pattern/Vector of Sets/$$ +sparsity patterns. +If the sparsity patterns for this operation use elements of type $code bool$$, +the return value for $code size_forward_set$$ will be zero. +Otherwise, its return value will be non-zero. +This sparsity pattern is stored for use by $cref RevSparseHes$$ and +when it is not longer needed, it can be deleted +(and the corresponding memory freed) using +$codei% + %f%.size_forward_set(0) +%$$ +After this call, $icode%f%.size_forward_set()%$$ will return zero. + +$head x$$ +If the operation sequence in $icode f$$ is +$cref/independent/glossary/Operation/Independent/$$ of +the independent variables in $latex x \in \B{R}^n$$, +the sparsity pattern is valid for all values of +(even if it has $cref CondExp$$ or $cref VecAD$$ operations). + +$head q$$ +The argument $icode q$$ has prototype +$codei% + size_t %q% +%$$ +It specifies the number of columns in +$latex R \in \B{R}^{n \times q}$$ and the Jacobian +$latex S(x) \in \B{R}^{m \times q}$$. + +$head transpose$$ +The argument $icode transpose$$ has prototype +$codei% + bool %transpose% +%$$ +The default value $code false$$ is used when $icode transpose$$ is not present. + +$head dependency$$ +The argument $icode dependency$$ has prototype +$codei% + bool %dependency% +%$$ +If $icode dependency$$ is true, +the $cref/dependency pattern/dependency.cpp/Dependency Pattern/$$ +(instead of sparsity pattern) is computed. + +$head r$$ +The argument $icode r$$ has prototype +$codei% + const %SetVector%& %r% +%$$ +see $cref/SetVector/ForSparseJac/SetVector/$$ below. + +$subhead transpose false$$ +If $icode r$$ has elements of type $code bool$$, +its size is $latex n * q$$. +If it has elements of type $code std::set$$, +its size is $latex n$$ and all the set elements must be between +zero and $icode%q%-1%$$ inclusive. +It specifies a +$cref/sparsity pattern/glossary/Sparsity Pattern/$$ +for the matrix $latex R \in \B{R}^{n \times q}$$. + +$subhead transpose true$$ +If $icode r$$ has elements of type $code bool$$, +its size is $latex q * n$$. +If it has elements of type $code std::set$$, +its size is $latex q$$ and all the set elements must be between +zero and $icode%n%-1%$$ inclusive. +It specifies a +$cref/sparsity pattern/glossary/Sparsity Pattern/$$ +for the matrix $latex R^\R{T} \in \B{R}^{q \times n}$$. + +$head s$$ +The return value $icode s$$ has prototype +$codei% + %SetVector% %s% +%$$ +see $cref/SetVector/ForSparseJac/SetVector/$$ below. + +$subhead transpose false$$ +If $icode s$$ has elements of type $code bool$$, +its size is $latex m * q$$. +If it has elements of type $code std::set$$, +its size is $latex m$$ and all its set elements are between +zero and $icode%q%-1%$$ inclusive. +It specifies a +$cref/sparsity pattern/glossary/Sparsity Pattern/$$ +for the matrix $latex S(x) \in \B{R}^{m \times q}$$. + +$subhead transpose true$$ +If $icode s$$ has elements of type $code bool$$, +its size is $latex q * m$$. +If it has elements of type $code std::set$$, +its size is $latex q$$ and all its set elements are between +zero and $icode%m%-1%$$ inclusive. +It specifies a +$cref/sparsity pattern/glossary/Sparsity Pattern/$$ +for the matrix $latex S(x)^\R{T} \in \B{R}^{q \times m}$$. + +$head SetVector$$ +The type $icode SetVector$$ must be a $cref SimpleVector$$ class with +$cref/elements of type/SimpleVector/Elements of Specified Type/$$ +$code bool$$ or $code std::set$$; +see $cref/sparsity pattern/glossary/Sparsity Pattern/$$ for a discussion +of the difference. + +$head Entire Sparsity Pattern$$ +Suppose that $latex q = n$$ and +$latex R$$ is the $latex n \times n$$ identity matrix. +In this case, +the corresponding value for $icode s$$ is a +sparsity pattern for the Jacobian $latex S(x) = F^{(1)} ( x )$$. + +$head Example$$ +$children% + example/sparse/for_sparse_jac.cpp +%$$ +The file +$cref for_sparse_jac.cpp$$ +contains an example and test of this operation. +The file +$cref/sparsity_sub.cpp/sparsity_sub.cpp/ForSparseJac/$$ +contains an example and test of using $code ForSparseJac$$ +to compute the sparsity pattern for a subset of the Jacobian. + +$end +----------------------------------------------------------------------------- +*/ + +# include + +namespace CppAD { // BEGIN_CPPAD_NAMESPACE +/*! +\file core/for_sparse_jac.hpp +Forward mode Jacobian sparsity patterns. +*/ +// --------------------------------------------------------------------------- +/*! +Private helper function for ForSparseJac(q, r) boolean sparsity patterns. + +All of the description in the public member function ForSparseJac(q, r) +applies. + +\param set_type +is a bool value. This argument is used to dispatch to the proper source +code depending on the value of SetVector::value_type. + +\param transpose +See ForSparseJac(q, r, transpose, dependency). + +\param dependency +See ForSparseJac(q, r, transpose, dependency). + +\param q +See ForSparseJac(q, r, transpose, dependency). + +\param r +See ForSparseJac(q, r, transpose, dependency). + +\param s +is the return value for the corresponding call to ForSparseJac(q, r). +*/ + +template +template +void ADFun::ForSparseJacCase( + bool set_type , + bool transpose , + bool dependency , + size_t q , + const SetVector& r , + SetVector& s ) +{ + // used to identify the RecBase type in calls to sweeps + RecBase not_used_rec_base(0.0); + // + size_t m = Range(); + size_t n = Domain(); + + // check SetVector is Simple Vector class with bool elements + CheckSimpleVector(); + + // dimension size of result vector + s.resize( m * q ); + + CPPAD_ASSERT_KNOWN( + q > 0, + "ForSparseJac: q is not greater than zero" + ); + CPPAD_ASSERT_KNOWN( + size_t(r.size()) == n * q, + "ForSparseJac: size of r is not equal to\n" + "q times domain dimension for ADFun object." + ); + // + // allocate memory for the requested sparsity calculation result + for_jac_sparse_pack_.resize(num_var_tape_, q); + + // set values corresponding to independent variables + for(size_t i = 0; i < n; i++) + { CPPAD_ASSERT_UNKNOWN( ind_taddr_[i] < num_var_tape_ ); + // ind_taddr_[i] is operator taddr for i-th independent variable + CPPAD_ASSERT_UNKNOWN( play_.GetOp( ind_taddr_[i] ) == local::InvOp ); + + // set bits that are true + if( transpose ) + { for(size_t j = 0; j < q; j++) if( r[ j * n + i ] ) + for_jac_sparse_pack_.post_element( ind_taddr_[i], j); + } + else + { for(size_t j = 0; j < q; j++) if( r[ i * q + j ] ) + for_jac_sparse_pack_.post_element( ind_taddr_[i], j); + } + } + // process posts + for(size_t j = 0; j < n; j++) + for_jac_sparse_pack_.process_post( ind_taddr_[j] ); + + // evaluate the sparsity patterns + local::sweep::for_jac( + &play_, + dependency, + n, + num_var_tape_, + for_jac_sparse_pack_, + not_used_rec_base + + ); + + // return values corresponding to dependent variables + CPPAD_ASSERT_UNKNOWN( size_t(s.size()) == m * q ); + for(size_t i = 0; i < m; i++) + { CPPAD_ASSERT_UNKNOWN( dep_taddr_[i] < num_var_tape_ ); + + // extract the result from for_jac_sparse_pack_ + if( transpose ) + { for(size_t j = 0; j < q; j++) + s[ j * m + i ] = false; + } + else + { for(size_t j = 0; j < q; j++) + s[ i * q + j ] = false; + } + CPPAD_ASSERT_UNKNOWN( for_jac_sparse_pack_.end() == q ); + local::sparse::pack_setvec::const_iterator + itr(for_jac_sparse_pack_, dep_taddr_[i] ); + size_t j = *itr; + while( j < q ) + { if( transpose ) + s[j * m + i] = true; + else + s[i * q + j] = true; + j = *(++itr); + } + } +} +// --------------------------------------------------------------------------- +/*! +Private helper function for ForSparseJac(q, r) set sparsity. + +All of the description in the public member function ForSparseJac(q, r) +applies. + +\param set_type +is a std::set object. +This argument is used to dispatch to the proper source +code depending on the value of SetVector::value_type. + +\param transpose +See ForSparseJac(q, r, transpose, dependency). + +\param dependency +See ForSparseJac(q, r, transpose, dependency). + +\param q +See ForSparseJac(q, r, transpose, dependency). + +\param r +See ForSparseJac(q, r, transpose, dependency). + +\param s +is the return value for the corresponding call to ForSparseJac(q, r). +*/ +template +template +void ADFun::ForSparseJacCase( + const std::set& set_type , + bool transpose , + bool dependency , + size_t q , + const SetVector& r , + SetVector& s ) +{ + // used to identify the RecBase type in calls to sweeps + RecBase not_used_rec_base(0.0); + // + size_t m = Range(); + size_t n = Domain(); + + // check SetVector is Simple Vector class with sets for elements + CheckSimpleVector, SetVector>( + local::one_element_std_set(), local::two_element_std_set() + ); + + // dimension size of result vector + if( transpose ) + s.resize(q); + else + s.resize( m ); + + // temporary iterator + std::set::const_iterator itr_1; + + CPPAD_ASSERT_KNOWN( + q > 0, + "ForSparseJac: q is not greater than zero" + ); + CPPAD_ASSERT_KNOWN( + size_t(r.size()) == n || transpose, + "ForSparseJac: size of r is not equal to n and transpose is false." + ); + CPPAD_ASSERT_KNOWN( + size_t(r.size()) == q || ! transpose, + "ForSparseJac: size of r is not equal to q and transpose is true." + ); + // + // allocate memory for the requested sparsity calculation + for_jac_sparse_set_.resize(num_var_tape_, q); + + // set values corresponding to independent variables + if( transpose ) + { for(size_t i = 0; i < q; i++) + { // add the elements that are present + itr_1 = r[i].begin(); + while( itr_1 != r[i].end() ) + { size_t j = *itr_1++; + CPPAD_ASSERT_KNOWN( + j < n, + "ForSparseJac: transpose is true and element of the set\n" + "r[j] has value greater than or equal n." + ); + CPPAD_ASSERT_UNKNOWN( ind_taddr_[j] < num_var_tape_ ); + // operator for j-th independent variable + CPPAD_ASSERT_UNKNOWN( + play_.GetOp( ind_taddr_[j] ) == local::InvOp + ); + for_jac_sparse_set_.post_element( ind_taddr_[j], i); + } + } + } + else + { for(size_t i = 0; i < n; i++) + { CPPAD_ASSERT_UNKNOWN( ind_taddr_[i] < num_var_tape_ ); + // ind_taddr_[i] is operator taddr for i-th independent variable + CPPAD_ASSERT_UNKNOWN( play_.GetOp( ind_taddr_[i] ) == local::InvOp ); + + // add the elements that are present + itr_1 = r[i].begin(); + while( itr_1 != r[i].end() ) + { size_t j = *itr_1++; + CPPAD_ASSERT_KNOWN( + j < q, + "ForSparseJac: an element of the set r[i] " + "has value greater than or equal q." + ); + for_jac_sparse_set_.post_element( ind_taddr_[i], j); + } + } + } + // process posts + for(size_t j = 0; j < n; j++) + for_jac_sparse_set_.process_post( ind_taddr_[j] ); + + // evaluate the sparsity patterns + local::sweep::for_jac( + &play_, + dependency, + n, + num_var_tape_, + for_jac_sparse_set_, + not_used_rec_base + + ); + + // return values corresponding to dependent variables + CPPAD_ASSERT_UNKNOWN( size_t(s.size()) == m || transpose ); + CPPAD_ASSERT_UNKNOWN( size_t(s.size()) == q || ! transpose ); + for(size_t i = 0; i < m; i++) + { CPPAD_ASSERT_UNKNOWN( dep_taddr_[i] < num_var_tape_ ); + + // extract results from for_jac_sparse_set_ + // and add corresponding elements to sets in s + CPPAD_ASSERT_UNKNOWN( for_jac_sparse_set_.end() == q ); + local::sparse::list_setvec::const_iterator + itr_2(for_jac_sparse_set_, dep_taddr_[i] ); + size_t j = *itr_2; + while( j < q ) + { if( transpose ) + s[j].insert(i); + else + s[i].insert(j); + j = *(++itr_2); + } + } +} +// --------------------------------------------------------------------------- + +/*! +User API for Jacobian sparsity patterns using forward mode. + +The C++ source code corresponding to this operation is +\verbatim + s = f.ForSparseJac(q, r, transpose, dependency) +\endverbatim + +\tparam Base +is the base type for this recording. + +\tparam SetVector +is a simple vector with elements of type bool +or std::set. + +\param q +is the number of columns in the matrix \f$ R \f$. + +\param r +is a sparsity pattern for the matrix \f$ R \f$. + +\param transpose +are sparsity patterns for \f$ R \f$ and \f$ S(x) \f$ transposed. + +\param dependency +Are the derivatives with respect to left and right of the expression below +considered to be non-zero: +\code + CondExpRel(left, right, if_true, if_false) +\endcode +This is used by the optimizer to obtain the correct dependency relations. + +\return +The value of transpose is false (true), +the return value is a sparsity pattern for \f$ S(x) \f$ (\f$ S(x)^T \f$) where +\f[ + S(x) = F^{(1)} (x) * R +\f] +where \f$ F \f$ is the function corresponding to the operation sequence +and x is any argument value. +If SetVector::value_type is bool, +the return value has size \f$ m * q \f$ (\f$ q * m \f$). +where m is the number of dependent variables +corresponding to the operation sequence stored in f. +If SetVector::value_type is std::set, +the return value has size \f$ m \f$ ( \f$ q \f$ ) +and with all its elements between zero and +\f$ q - 1 \f$ ( \f$ m - 1 \f$). + +\par Side Effects +If SetVector::value_type is bool, +the forward sparsity pattern for all of the variables on the +tape is stored in for_jac_sparse_pack__. +In this case +\verbatim + for_jac_sparse_pack_.n_set() == num_var_tape_ + for_jac_sparse_pack_.end() == q + for_jac_sparse_set_.n_set() == 0 + for_jac_sparse_set_.end() == 0 +\endverbatim +\n +\n +If SetVector::value_type is std::set, +the forward sparsity pattern for all of the variables on the +tape is stored in for_jac_sparse_set__. +In this case +\verbatim + for_jac_sparse_set_.n_set() == num_var_tape_ + for_jac_sparse_set_.end() == q + for_jac_sparse_pack_.n_set() == 0 + for_jac_sparse_pack_.end() == 0 +\endverbatim +*/ +template +template +SetVector ADFun::ForSparseJac( + size_t q , + const SetVector& r , + bool transpose , + bool dependency ) +{ + SetVector s; + typedef typename SetVector::value_type Set_type; + + // free all memory currently in sparsity patterns + for_jac_sparse_pack_.resize(0, 0); + for_jac_sparse_set_.resize(0, 0); + + ForSparseJacCase( + Set_type() , + transpose , + dependency , + q , + r , + s + ); + + return s; +} +// =========================================================================== +// ForSparseJacCheckpoint +/*! +Forward mode Jacobian sparsity calculation used by checkpoint functions. + +\tparam Base +is the base type for this recording. + +\param transpose +is true (false) s is equal to \f$ S(x) \f$ (\f$ S(x)^T \f$) +where +\f[ + S(x) = F^{(1)} (x) * R +\f] +where \f$ F \f$ is the function corresponding to the operation sequence +and \f$ x \f$ is any argument value. + +\param q +is the number of columns in the matrix \f$ R \f$. + +\param r +is a sparsity pattern for the matrix \f$ R \f$. + +\param transpose +are the sparsity patterns for \f$ R \f$ and \f$ S(x) \f$ transposed. + +\param dependency +Are the derivatives with respect to left and right of the expression below +considered to be non-zero: +\code + CondExpRel(left, right, if_true, if_false) +\endcode +This is used by the optimizer to obtain the correct dependency relations. + +\param s +The input size and elements of s do not matter. +On output, s is the sparsity pattern for the matrix \f$ S(x) \f$ +or \f$ S(x)^T \f$ depending on transpose. + +\par Side Effects +If SetVector::value_type is bool, +the forward sparsity pattern for all of the variables on the +tape is stored in for_jac_sparse_pack__. +In this case +\verbatim + for_jac_sparse_pack_.n_set() == num_var_tape_ + for_jac_sparse_pack_.end() == q + for_jac_sparse_set_.n_set() == 0 + for_jac_sparse_set_.end() == 0 +\endverbatim +\n +\n +If SetVector::value_type is std::set, +the forward sparsity pattern for all of the variables on the +tape is stored in for_jac_sparse_set__. +In this case +\verbatim + for_jac_sparse_set_.n_set() == num_var_tape_ + for_jac_sparse_set_.end() == q + for_jac_sparse_pack_.n_set() == 0 + for_jac_sparse_pack_.end() == 0 +\endverbatim +*/ +template +void ADFun::ForSparseJacCheckpoint( + size_t q , + const local::sparse::list_setvec& r , + bool transpose , + bool dependency , + local::sparse::list_setvec& s ) +{ + // used to identify the RecBase type in calls to sweeps + RecBase not_used_rec_base(0.0); + // + size_t n = Domain(); + size_t m = Range(); + +# ifndef NDEBUG + if( transpose ) + { CPPAD_ASSERT_UNKNOWN( r.n_set() == q ); + CPPAD_ASSERT_UNKNOWN( r.end() == n ); + } + else + { CPPAD_ASSERT_UNKNOWN( r.n_set() == n ); + CPPAD_ASSERT_UNKNOWN( r.end() == q ); + } + for(size_t j = 0; j < n; j++) + { CPPAD_ASSERT_UNKNOWN( ind_taddr_[j] == (j+1) ); + CPPAD_ASSERT_UNKNOWN( play_.GetOp( ind_taddr_[j] ) == local::InvOp ); + } +# endif + + // free all memory currently in sparsity patterns + for_jac_sparse_pack_.resize(0, 0); + for_jac_sparse_set_.resize(0, 0); + + // allocate new sparsity pattern + for_jac_sparse_set_.resize(num_var_tape_, q); + + // set sparsity pattern for dependent variables + if( transpose ) + { for(size_t i = 0; i < q; i++) + { local::sparse::list_setvec::const_iterator itr(r, i); + size_t j = *itr; + while( j < n ) + { for_jac_sparse_set_.post_element( ind_taddr_[j], i ); + j = *(++itr); + } + } + } + else + { for(size_t j = 0; j < n; j++) + { local::sparse::list_setvec::const_iterator itr(r, j); + size_t i = *itr; + while( i < q ) + { for_jac_sparse_set_.post_element( ind_taddr_[j], i ); + i = *(++itr); + } + } + } + // process posts + for(size_t j = 0; j < n; j++) + for_jac_sparse_set_.process_post( ind_taddr_[j] ); + + // evaluate the sparsity pattern for all variables + local::sweep::for_jac( + &play_, + dependency, + n, + num_var_tape_, + for_jac_sparse_set_, + not_used_rec_base + + ); + + // dimension the return value + if( transpose ) + s.resize(q, m); + else + s.resize(m, q); + + // return values corresponding to dependent variables + for(size_t i = 0; i < m; i++) + { CPPAD_ASSERT_UNKNOWN( dep_taddr_[i] < num_var_tape_ ); + + // extract the result from for_jac_sparse_set_ + CPPAD_ASSERT_UNKNOWN( for_jac_sparse_set_.end() == q ); + local::sparse::list_setvec::const_iterator + itr(for_jac_sparse_set_, dep_taddr_[i] ); + size_t j = *itr; + while( j < q ) + { if( transpose ) + s.post_element(j, i); + else + s.post_element(i, j); + j = *(++itr); + } + } + // process posts + for(size_t i = 0; i < s.n_set(); ++i) + s.process_post(i); + +} + + +} // END_CPPAD_NAMESPACE +# endif diff --git a/build-config/cppad/include/cppad/core/for_two.hpp b/build-config/cppad/include/cppad/core/for_two.hpp new file mode 100644 index 00000000..677266cf --- /dev/null +++ b/build-config/cppad/include/cppad/core/for_two.hpp @@ -0,0 +1,254 @@ +# ifndef CPPAD_CORE_FOR_TWO_HPP +# define CPPAD_CORE_FOR_TWO_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-18 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +/* +$begin ForTwo$$ +$spell + ddy + typename + Taylor + const +$$ + + + + + +$section Forward Mode Second Partial Derivative Driver$$ + +$head Syntax$$ +$icode%ddy% = %f%.ForTwo(%x%, %j%, %k%)%$$ + + +$head Purpose$$ +We use $latex F : \B{R}^n \rightarrow \B{R}^m$$ to denote the +$cref/AD function/glossary/AD Function/$$ corresponding to $icode f$$. +The syntax above sets +$latex \[ + ddy [ i * p + \ell ] + = + \DD{ F_i }{ x_{j[ \ell ]} }{ x_{k[ \ell ]} } (x) +\] $$ +for $latex i = 0 , \ldots , m-1$$ +and $latex \ell = 0 , \ldots , p$$, +where $latex p$$ is the size of the vectors $icode j$$ and $icode k$$. + +$head f$$ +The object $icode f$$ has prototype +$codei% + ADFun<%Base%> %f% +%$$ +Note that the $cref ADFun$$ object $icode f$$ is not $code const$$ +(see $cref/ForTwo Uses Forward/ForTwo/ForTwo Uses Forward/$$ below). + +$head x$$ +The argument $icode x$$ has prototype +$codei% + const %BaseVector% &%x% +%$$ +(see $cref/BaseVector/ForTwo/BaseVector/$$ below) +and its size +must be equal to $icode n$$, the dimension of the +$cref/domain/seq_property/Domain/$$ space for $icode f$$. +It specifies +that point at which to evaluate the partial derivatives listed above. + +$head j$$ +The argument $icode j$$ has prototype +$codei% + const %SizeVector_t% &%j% +%$$ +(see $cref/SizeVector_t/ForTwo/SizeVector_t/$$ below) +We use $icode p$$ to denote the size of the vector $icode j$$. +All of the indices in $icode j$$ +must be less than $icode n$$; i.e., +for $latex \ell = 0 , \ldots , p-1$$, $latex j[ \ell ] < n$$. + +$head k$$ +The argument $icode k$$ has prototype +$codei% + const %SizeVector_t% &%k% +%$$ +(see $cref/SizeVector_t/ForTwo/SizeVector_t/$$ below) +and its size must be equal to $icode p$$, +the size of the vector $icode j$$. +All of the indices in $icode k$$ +must be less than $icode n$$; i.e., +for $latex \ell = 0 , \ldots , p-1$$, $latex k[ \ell ] < n$$. + +$head ddy$$ +The result $icode ddy$$ has prototype +$codei% + %BaseVector% %ddy% +%$$ +(see $cref/BaseVector/ForTwo/BaseVector/$$ below) +and its size is $latex m * p$$. +It contains the requested partial derivatives; to be specific, +for $latex i = 0 , \ldots , m - 1 $$ +and $latex \ell = 0 , \ldots , p - 1$$ +$latex \[ + ddy [ i * p + \ell ] + = + \DD{ F_i }{ x_{j[ \ell ]} }{ x_{k[ \ell ]} } (x) +\] $$ + +$head BaseVector$$ +The type $icode BaseVector$$ must be a $cref SimpleVector$$ class with +$cref/elements of type Base/SimpleVector/Elements of Specified Type/$$. +The routine $cref CheckSimpleVector$$ will generate an error message +if this is not the case. + +$head SizeVector_t$$ +The type $icode SizeVector_t$$ must be a $cref SimpleVector$$ class with +$cref/elements of type size_t/SimpleVector/Elements of Specified Type/$$. +The routine $cref CheckSimpleVector$$ will generate an error message +if this is not the case. + +$head ForTwo Uses Forward$$ +After each call to $cref Forward$$, +the object $icode f$$ contains the corresponding +$cref/Taylor coefficients/glossary/Taylor Coefficient/$$. +After a call to $code ForTwo$$, +the zero order Taylor coefficients correspond to +$icode%f%.Forward(0, %x%)%$$ +and the other coefficients are unspecified. + +$head Examples$$ +$children% + example/general/for_two.cpp +%$$ +The routine +$cref/ForTwo/for_two.cpp/$$ is both an example and test. +It returns $code true$$, if it succeeds and $code false$$ otherwise. + +$end +----------------------------------------------------------------------------- +*/ + +// BEGIN CppAD namespace +namespace CppAD { + +template +template +BaseVector ADFun::ForTwo( + const BaseVector &x, + const SizeVector_t &j, + const SizeVector_t &k) +{ size_t i; + size_t j1; + size_t k1; + size_t l; + + size_t n = Domain(); + size_t m = Range(); + size_t p = j.size(); + + // check BaseVector is Simple Vector class with Base type elements + CheckSimpleVector(); + + // check SizeVector_t is Simple Vector class with size_t elements + CheckSimpleVector(); + + CPPAD_ASSERT_KNOWN( + x.size() == n, + "ForTwo: Length of x not equal domain dimension for f." + ); + CPPAD_ASSERT_KNOWN( + j.size() == k.size(), + "ForTwo: Lenght of the j and k vectors are not equal." + ); + // point at which we are evaluating the second partials + Forward(0, x); + + + // dimension the return value + BaseVector ddy(m * p); + + // allocate memory to hold all possible diagonal Taylor coefficients + // (for large sparse cases, this is not efficient) + BaseVector D(m * n); + + // boolean flag for which diagonal coefficients are computed + CppAD::vector c(n); + for(j1 = 0; j1 < n; j1++) + c[j1] = false; + + // direction vector in argument space + BaseVector dx(n); + for(j1 = 0; j1 < n; j1++) + dx[j1] = Base(0.0); + + // result vector in range space + BaseVector dy(m); + + // compute the diagonal coefficients that are needed + for(l = 0; l < p; l++) + { j1 = j[l]; + k1 = k[l]; + CPPAD_ASSERT_KNOWN( + j1 < n, + "ForTwo: an element of j not less than domain dimension for f." + ); + CPPAD_ASSERT_KNOWN( + k1 < n, + "ForTwo: an element of k not less than domain dimension for f." + ); + size_t count = 2; + while(count) + { count--; + if( ! c[j1] ) + { // diagonal term in j1 direction + c[j1] = true; + dx[j1] = Base(1.0); + Forward(1, dx); + + dx[j1] = Base(0.0); + dy = Forward(2, dx); + for(i = 0; i < m; i++) + D[i * n + j1 ] = dy[i]; + } + j1 = k1; + } + } + // compute all the requested cross partials + for(l = 0; l < p; l++) + { j1 = j[l]; + k1 = k[l]; + if( j1 == k1 ) + { for(i = 0; i < m; i++) + ddy[i * p + l] = Base(2.0) * D[i * n + j1]; + } + else + { + // cross term in j1 and k1 directions + dx[j1] = Base(1.0); + dx[k1] = Base(1.0); + Forward(1, dx); + + dx[j1] = Base(0.0); + dx[k1] = Base(0.0); + dy = Forward(2, dx); + + // place result in return value + for(i = 0; i < m; i++) + ddy[i * p + l] = dy[i] - D[i*n+j1] - D[i*n+k1]; + + } + } + return ddy; +} + +} // END CppAD namespace + +# endif diff --git a/build-config/cppad/include/cppad/core/forward/compare_change.omh b/build-config/cppad/include/cppad/core/forward/compare_change.omh new file mode 100644 index 00000000..42cf778d --- /dev/null +++ b/build-config/cppad/include/cppad/core/forward/compare_change.omh @@ -0,0 +1,156 @@ +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 Bradley M. Bell + + CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + + This Source Code may also be made available under the following + Secondary License when the conditions for such availability set forth + in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +-------------------------------------------------------------------------- */ +$begin compare_change$$ +$spell + op + const +$$ + +$section Comparison Changes Between Taping and Zero Order Forward$$ + + +$head Syntax$$ +$icode%f%.compare_change_count(%count%) +%$$ +$icode%number% = %f%.compare_change_number() +%$$ +$icode%op_index% = %f%.compare_change_op_index() + +%$$ +$bold See Also$$ +$cref FunCheck$$ + + +$head Purpose$$ +We use $latex F : \B{R}^n \rightarrow \B{R}^m$$ to denote the +$cref/AD function/glossary/AD Function/$$ corresponding to $icode f$$; i.e, +given $latex x \in \B{R}^n$$, $latex F(x)$$ is defined by +$codei% + %F%(%x%) = %f%.Forward(0, %x%) +%$$ +see $cref forward_zero$$. +If $latex x$$ is such that +all the algorithm $cref/comparison/Compare/$$ operations +have the same result as when the algorithm was taped, +The function $latex F(x)$$ and the algorithm will have the same values. +(This is a sufficient, but not necessary condition). + + + + + +$head f$$ +In the $code compare_change_number$$ and $code compare_change_op_index$$ +syntax, the object $icode f$$ has prototype +$codei% + const ADFun<%Base%> %f% +%$$ +In the $code compare_change_count$$ +syntax, the object $icode f$$ has prototype +$codei% + ADFun<%Base%> %f% +%$$ + +$head count$$ +The argument $icode count$$ has prototype +$icode% + size_t %count% +%$$ +It specifies which comparison change should correspond to the +information stored in $icode f$$ during subsequent calls to +$cref forward_zero$$; i.e., +$codei% + %f%.Forward(0, %x%) +%$$ +For example, if $icode%count% == 1%$$, +the operator index corresponding to the first comparison change +will be stored. +This is the default value used if $icode count$$ is not specified. + +$subhead Speed$$ +The special case where $icode count == 0$$, should be faster because +the comparisons are not checked during +$codei% + %f%.Forward(0, %x%) +%$$ + +$head number$$ +The return value $icode number$$ has prototype +$codei% + size_t %number% +%$$ +If $icode count$$ is non-zero, +$icode number$$ is the number of +$codei%AD<%Base%>%$$ $cref/comparison/Compare/$$ operations, +corresponding to the previous call to +$codei% + %f%.Forward(0, %x%) +%$$ +that have a different result for this value of $icode x$$ +than the value used when $icode f$$ was created by taping an algorithm. +If $icode count$$ is zero, +or if no calls to $icode%f%.Forward(0, %x%)%$$ follow the previous +setting of $icode count$$, +$icode number$$ is zero. + +$subhead Discussion$$ +If $icode count$$ and $icode number$$ are non-zero, +you may want to re-tape the algorithm with the +$cref/independent variables/glossary/Tape/Independent Variable/$$ +equal to the values in $icode x$$, +so the AD operation sequence properly represents the algorithm +for this value of independent variables. +On the other hand, re-taping the AD operation sequence usually takes +significantly more time than evaluation using $cref forward_zero$$. +If the functions values have not changed (see $cref FunCheck$$) +it may not be worth re-taping a new AD operation sequence. + +$head op_index$$ +The return value $icode op_index$$ has prototype +$codei% + size_t %op_index% +%$$ +If $icode count$$ is non-zero, +$icode op_index$$ is the operator index corresponding the +$icode count$$-th comparison change during the previous call to +$codei% + %f%.Forward(0, %x%) +%$$ +If $icode count$$ is greater than the corresponding +$icode number$$, there is no such comparison change and $icode op_index$$ +will also be zero. +If $icode count$$ is zero, +if the function $icode f$$ has been $cref/optimized/optimize/$$, +or if no calls to $icode%f%.Forward(0, %x%)%$$ follow the previous +setting of $icode count$$, +$icode op_index$$ is zero. + +$subhead Purpose$$ +The operator index can be used to generate an error during the taping +process so that the corresponding algorithm can be inspected. +In some cases, it is possible to re-design this part of the +algorithm to avoid the particular comparison operation. +For example, using an $cref/conditional expression/CondExp/$$ +may be appropriate in some cases. +See $cref/abort_op_index/Independent/abort_op_index/$$ in the syntax +$codei% + Independent(%x%, %abort_op_index%) +%$$ + +$children% + example/general/compare_change.cpp +%$$ +$head Example$$ +$cref compare_change.cpp$$ +contains an example and test of this operation. + +$end diff --git a/build-config/cppad/include/cppad/core/forward/devel.omh b/build-config/cppad/include/cppad/core/forward/devel.omh new file mode 100644 index 00000000..3d41dcd2 --- /dev/null +++ b/build-config/cppad/include/cppad/core/forward/devel.omh @@ -0,0 +1,23 @@ +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 Bradley M. Bell + + CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + + This Source Code may also be made available under the following + Secondary License when the conditions for such availability set forth + in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +-------------------------------------------------------------------------- */ +$begin devel_forward$$ +$spell + Devel +$$ + +$section Devel: Forward Mode$$ + +$childtable% + include/cppad/core/forward/forward.hpp +%$$ + +$end diff --git a/build-config/cppad/include/cppad/core/forward/forward.hpp b/build-config/cppad/include/cppad/core/forward/forward.hpp new file mode 100644 index 00000000..3becb72a --- /dev/null +++ b/build-config/cppad/include/cppad/core/forward/forward.hpp @@ -0,0 +1,490 @@ +# ifndef CPPAD_CORE_FORWARD_FORWARD_HPP +# define CPPAD_CORE_FORWARD_FORWARD_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +// documened after Forward but included here so easy to see +# include +# include +# include + +namespace CppAD { // BEGIN_CPPAD_NAMESPACE + +/* +--------------------------------------- --------------------------------------- +$begin devel_forward_order$$ +$spell + yq + xq + Taylor + num_var + PriOp + dyn_ind +$$ + +$section Multiple orders, one direction, forward mode Taylor coefficients$$ + +$head Syntax$$ +$icode%yq% = %f%.Forward(%q%, %xq%, %s% ) +%$$ + +$head Prototype$$ +$srcthisfile% + 0%// BEGIN_FORWARD_ORDER%// END_FORWARD_ORDER%1 +%$$ + +$head Base$$ +The type used during the forward mode computations; i.e., the corresponding +recording of operations used the type AD. + +$head BaseVector$$ +is a Simple Vector class with elements of type Base. + +$head q$$ +is the highest order for this forward mode computation; i.e., +after this calculation there will be $icode%q%+1%$$ +Taylor coefficients per variable. + +$head xq$$ +contains Taylor coefficients for the independent variables. +The size of $icode xq$$ must either be $icode n$$ or $icode (q+1)*n$$, +We define $icode p = q + 1 - xq.size()/n$$. +For $icode j = 0 , ... , n-1$$, +$icode k = 0, ... , q$$, +$icode xq[ (q+1)*j + k - p ]$$ +is the k-th order coefficient for the j-th independent variable. + +$head s$$ +Is the stream where output corresponding to PriOp operations will written. + +$head yq$$ +contains Taylor coefficients for the dependent variables. +The size of the return value $icode yq$$ +has size $icode m*(q+1-p)$$. +For $icode i = 0, ... , m-1$$, +$icode k = p, ..., q$$, +$icode yq[(q+1-p)*i + (k-p)]$$ +is the k-th order coefficient for the i-th dependent variable. + +$head taylor_$$ +The Taylor coefficients up to order $icode p-1$$ are inputs +and the coefficients from order $icode p$$ through $icode q$$ are outputs. +Let $icode N = num_var_tape_$$, and +$icode C = cap_order_taylor_$$. +Note that for +$icode i = 1 , ..., N-1$$, +$icode k = 0 , ..., q$$, +$icode taylor_[ C*i + k ]$$ +is the k-th order coefficient, +for the i-th variable on the tape. +(The first independent variable has index one on the tape +and there is no variable with index zero.) + +$end +*/ +// BEGIN_FORWARD_ORDER +template +template +BaseVector ADFun::Forward( + size_t q , + const BaseVector& xq , + std::ostream& s ) +// END_FORWARD_ORDER +{ + // used to identify the RecBase type in calls to sweeps + RecBase not_used_rec_base(0.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(); + + // check Vector is Simple Vector class with Base type elements + CheckSimpleVector(); + + // check size of xq + CPPAD_ASSERT_KNOWN( + size_t(xq.size()) == n || size_t(xq.size()) == n*(q+1), + "Forward(q, xq): xq.size() is not equal n or n*(q+1)" + ); + + // p = lowest order we are computing + size_t p = q + 1 - size_t(xq.size()) / n; + CPPAD_ASSERT_UNKNOWN( p == 0 || p == q ); + + // check one order case + CPPAD_ASSERT_KNOWN( + q <= num_order_taylor_ || p == 0, + "Forward(q, xq): Number of Taylor coefficient orders stored in this" + " ADFun\nis less than q and xq.size() != n*(q+1)." + ); + + // if p > 1, the previous number of directions must be one + CPPAD_ASSERT_KNOWN( + p <= 1 || num_direction_taylor_ == 1, + "Forward(q, xq): computing order q >= 2" + " and number of directions is not one." + "\nMust use Forward(q, r, xq) for this case" + ); + + // does taylor_ need more orders or fewer directions + if( (cap_order_taylor_ <= q) | (num_direction_taylor_ != 1) ) + { if( p == 0 ) + { // no need to copy old values during capacity_order + num_order_taylor_ = 0; + } + else + num_order_taylor_ = q; + size_t c = std::max(q + 1, cap_order_taylor_); + size_t r = 1; + capacity_order(c, r); + } + CPPAD_ASSERT_UNKNOWN( cap_order_taylor_ > q ); + CPPAD_ASSERT_UNKNOWN( num_direction_taylor_ == 1 ); + + // short hand notation for order capacity + size_t C = cap_order_taylor_; + + // The optimizer may skip a step that does not affect dependent variables. + // Initilaizing zero order coefficients avoids following valgrind warning: + // "Conditional jump or move depends on uninitialised value(s)". + for(j = 0; j < num_var_tape_; j++) + { for(k = p; k <= q; k++) + taylor_[C * j + k] = CppAD::numeric_limits::quiet_NaN(); + } + + // set Taylor coefficients for independent variables + for(j = 0; j < n; j++) + { CPPAD_ASSERT_UNKNOWN( ind_taddr_[j] < num_var_tape_ ); + + // ind_taddr_[j] is operator taddr for j-th independent variable + CPPAD_ASSERT_UNKNOWN( play_.GetOp( ind_taddr_[j] ) == local::InvOp ); + + if( p == q ) + taylor_[ C * ind_taddr_[j] + q] = xq[j]; + else + { for(k = 0; k <= q; k++) + taylor_[ C * ind_taddr_[j] + k] = xq[ (q+1)*j + k]; + } + } + + // evaluate the derivatives + CPPAD_ASSERT_UNKNOWN( cskip_op_.size() == play_.num_op_rec() ); + CPPAD_ASSERT_UNKNOWN( load_op2var_.size() == play_.num_var_load_rec() ); + if( q == 0 ) + { + local::sweep::forward0(&play_, s, true, + n, num_var_tape_, C, + taylor_.data(), cskip_op_.data(), load_op2var_, + compare_change_count_, + compare_change_number_, + compare_change_op_index_, + not_used_rec_base + ); + } + else + { local::sweep::forward1(&play_, s, true, p, q, + n, num_var_tape_, C, + taylor_.data(), cskip_op_.data(), load_op2var_, + compare_change_count_, + compare_change_number_, + compare_change_op_index_, + not_used_rec_base + ); + } + + // return Taylor coefficients for dependent variables + BaseVector yq; + if( p == q ) + { yq.resize(m); + for(i = 0; i < m; i++) + { CPPAD_ASSERT_UNKNOWN( dep_taddr_[i] < num_var_tape_ ); + yq[i] = taylor_[ C * dep_taddr_[i] + q]; + } + } + else + { yq.resize(m * (q+1) ); + for(i = 0; i < m; i++) + { for(k = 0; k <= q; k++) + yq[ (q+1) * i + k] = + taylor_[ C * dep_taddr_[i] + k ]; + } + } +# ifndef NDEBUG + if( check_for_nan_ ) + { bool ok = true; + size_t index = m; + if( p == 0 ) + { for(i = 0; i < m; i++) + { // Visual Studio 2012, CppAD required in front of isnan ? + if( CppAD::isnan( yq[ (q+1) * i + 0 ] ) ) + { ok = false; + if( index == m ) + index = i; + } + } + } + if( ! ok ) + { CPPAD_ASSERT_UNKNOWN( index < m ); + // + CppAD::vector x0(n); + for(j = 0; j < n; j++) + x0[j] = taylor_[ C * ind_taddr_[j] + 0 ]; + std::string file_name; + put_check_for_nan(x0, file_name); + std::stringstream ss; + ss << + "yq = f.Forward(q, xq): a zero order Taylor coefficient is nan.\n" + "Corresponding independent variables vector was written " + "to binary a file.\n" + "vector_size = " << n << "\n" << + "file_name = " << file_name << "\n" << + "index = " << index << "\n"; + // ss.str() returns a string object with a copy of the current + // contents in the stream buffer. + std::string msg_str = ss.str(); + // msg_str.c_str() returns a pointer to the c-string + // representation of the string object's value. + const char* msg_char_star = msg_str.c_str(); + ErrorHandler::Call( + true, + __LINE__, + __FILE__, + "if( CppAD::isnan( yq[ (q+1) * index + 0 ] )", + msg_char_star + ); + } + CPPAD_ASSERT_KNOWN(ok, + "with the value nan." + ); + if( 0 < q ) + { for(i = 0; i < m; i++) + { for(k = p; k <= q; k++) + { // Studio 2012, CppAD required in front of isnan ? + ok &= ! CppAD::isnan( yq[ (q+1-p)*i + k-p ] ); + } + } + } + CPPAD_ASSERT_KNOWN(ok, + "yq = f.Forward(q, xq): has a non-zero order Taylor coefficient\n" + "with the value nan (but zero order coefficients are not nan)." + ); + } +# endif + + // now we have q + 1 taylor_ coefficient orders per variable + num_order_taylor_ = q + 1; + + return yq; +} +/* +--------------------------------------- --------------------------------------- +$begin devel_forward_dir$$ +$spell + yq + xq + Taylor + num_var +$$ + +$section One order, multiple directions, forward mode Taylor coefficients$$ + +$head Syntax$$ +$icode%yq% = %f%.Forward(%q%, %r%, %xq%) +%$$ + +$head Prototype$$ +$srcthisfile% + 0%// BEGIN_FORWARD_DIR%// END_FORWARD_DIR%1 +%$$ + +$head Base$$ +The type used during the forward mode computations; i.e., the corresponding +recording of operations used the type AD. + +$head BaseVector$$ +is a Simple Vector class with elements of type Base. + +$head q$$ +is the order for this forward mode computation, +$icode q > 0$$. +There must be at least $icode q$$ Taylor coefficients +per variable before this call. +After this call there will be $icode q+1$$ +Taylor coefficients per variable. + +$head r$$ +is the number of directions for this calculation. +If $icode q != 1$$, r must be the same as in the previous +call to Forward where q was equal to one. + +$head xq$$ +contains Taylor coefficients for the independent variables. +The size of xq must either be $icode r*n$$, +For $icode j = 0 , ... , n-1$$, +$icode ell = 0, ... , r-1$$, +$icode xq[ ( r*j + ell ]$$ +is the q-th order coefficient for the j-th independent variable +and the ell-th direction. + +$head yq$$ +contains Taylor coefficients for the dependent variables. +The size of $icode y$$ is $icode r*m$$. +For $icode i = 0, ... , m-1$$, +$icode ell = 0, ... , r-1$$, +$icode yq[ r*i + ell ]$$ +is the q-th order coefficient for the i-th dependent variable +and the ell-th direction. + +$head taylor_$$ +The Taylor coefficients up to order $icode q-1$$ are inputs +and the coefficients of order q are outputs. +Let $icode N = num_var_tape_$$, and +$icode C = cap_order_taylor_$$. +Note that for +$icode i = 1 , ..., N-1$$, +$icode taylor_[ (C-1)*r*i + i + 0 ]$$ +is the zero order coefficient, +for the i-th variable, and all directions. +For $icode i = 1 , ..., N-1$$, +$icode k = 1 , ..., q$$, +$icode ell = 0 , ..., r-1$$, +$icode taylor_[ (C-1)*r*i + i + (k-1)*r + ell + 1 ]$$ +is the k-th order coefficient, +for the i-th variable, and ell-th direction. +(The first independent variable has index one on the tape +and there is no variable with index zero.) + +$end +*/ +// BEGIN_FORWARD_DIR +template +template +BaseVector ADFun::Forward( + size_t q , + size_t r , + const BaseVector& xq ) +// END_FORWARD_DIR +{ + // used to identify the RecBase type in calls to sweeps + RecBase not_used_rec_base(0.0); + + // temporary indices + size_t i, j, ell; + + // 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(); + + CPPAD_ASSERT_KNOWN( q > 0, "Forward(q, r, xq): q == 0" ); + CPPAD_ASSERT_KNOWN( + size_t(xq.size()) == r * n, + "Forward(q, r, xq): xq.size() is not equal r * n" + ); + CPPAD_ASSERT_KNOWN( + q <= num_order_taylor_ , + "Forward(q, r, xq): Number of Taylor coefficient orders stored in" + " this ADFun is less than q" + ); + CPPAD_ASSERT_KNOWN( + q == 1 || num_direction_taylor_ == r , + "Forward(q, r, xq): q > 1 and number of Taylor directions r" + " is not same as previous Forward(1, r, xq)" + ); + + // does taylor_ need more orders or new number of directions + if( cap_order_taylor_ <= q || num_direction_taylor_ != r ) + { if( num_direction_taylor_ != r ) + num_order_taylor_ = 1; + + size_t c = std::max(q + 1, cap_order_taylor_); + capacity_order(c, r); + } + CPPAD_ASSERT_UNKNOWN( cap_order_taylor_ > q ); + CPPAD_ASSERT_UNKNOWN( num_direction_taylor_ == r ) + + // short hand notation for order capacity + size_t c = cap_order_taylor_; + + // set Taylor coefficients for independent variables + for(j = 0; j < n; j++) + { CPPAD_ASSERT_UNKNOWN( ind_taddr_[j] < num_var_tape_ ); + + // ind_taddr_[j] is operator taddr for j-th independent variable + CPPAD_ASSERT_UNKNOWN( play_.GetOp( ind_taddr_[j] ) == local::InvOp ); + + for(ell = 0; ell < r; ell++) + { size_t index = ((c-1)*r + 1)*ind_taddr_[j] + (q-1)*r + ell + 1; + taylor_[ index ] = xq[ r * j + ell ]; + } + } + + // evaluate the derivatives + CPPAD_ASSERT_UNKNOWN( cskip_op_.size() == play_.num_op_rec() ); + CPPAD_ASSERT_UNKNOWN( load_op2var_.size() == play_.num_var_load_rec() ); + local::sweep::forward2( + &play_, + q, + r, + n, + num_var_tape_, + c, + taylor_.data(), + cskip_op_.data(), + load_op2var_, + not_used_rec_base + ); + + // return Taylor coefficients for dependent variables + BaseVector yq; + yq.resize(r * m); + for(i = 0; i < m; i++) + { CPPAD_ASSERT_UNKNOWN( dep_taddr_[i] < num_var_tape_ ); + for(ell = 0; ell < r; ell++) + { size_t index = ((c-1)*r + 1)*dep_taddr_[i] + (q-1)*r + ell + 1; + yq[ r * i + ell ] = taylor_[ index ]; + } + } +# ifndef NDEBUG + if( check_for_nan_ ) + { bool ok = true; + for(i = 0; i < m; i++) + { for(ell = 0; ell < r; ell++) + { // Studio 2012, CppAD required in front of isnan ? + ok &= ! CppAD::isnan( yq[ r * i + ell ] ); + } + } + CPPAD_ASSERT_KNOWN(ok, + "yq = f.Forward(q, r, xq): has a non-zero order Taylor coefficient\n" + "with the value nan (but zero order coefficients are not nan)." + ); + } +# endif + + // now we have q + 1 taylor_ coefficient orders per variable + num_order_taylor_ = q + 1; + + return yq; +} + + +} // END_CPPAD_NAMESPACE +# endif diff --git a/build-config/cppad/include/cppad/core/forward/forward.omh b/build-config/cppad/include/cppad/core/forward/forward.omh new file mode 100644 index 00000000..f5a64fa3 --- /dev/null +++ b/build-config/cppad/include/cppad/core/forward/forward.omh @@ -0,0 +1,28 @@ +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 Bradley M. Bell + + CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + + This Source Code may also be made available under the following + Secondary License when the conditions for such availability set forth + in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +-------------------------------------------------------------------------- */ +$begin Forward$$ + +$section Forward Mode$$ + +$childtable% + include/cppad/core/forward/forward_zero.omh% + include/cppad/core/forward/forward_one.omh% + include/cppad/core/forward/forward_two.omh% + include/cppad/core/forward/forward_order.omh% + include/cppad/core/forward/forward_dir.omh% + include/cppad/core/forward/size_order.omh% + include/cppad/core/forward/compare_change.omh% + include/cppad/core/capacity_order.hpp% + include/cppad/core/num_skip.hpp +%$$ + +$end diff --git a/build-config/cppad/include/cppad/core/forward/forward_dir.omh b/build-config/cppad/include/cppad/core/forward/forward_dir.omh new file mode 100644 index 00000000..c76c4f1a --- /dev/null +++ b/build-config/cppad/include/cppad/core/forward/forward_dir.omh @@ -0,0 +1,206 @@ +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 Bradley M. Bell + + CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + + This Source Code may also be made available under the following + Secondary License when the conditions for such availability set forth + in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +-------------------------------------------------------------------------- */ +$begin forward_dir$$ +$spell + Taylor + const + dir + cpp + yq + xq + xk + std::cout + ostream +$$ + +$section Multiple Directions Forward Mode$$ + + +$head Syntax$$ +$icode%yq% = %f%.Forward(%q%, %r%, %xq%) +%$$ + +$head Purpose$$ +We use $latex F : \B{R}^n \rightarrow \B{R}^m$$ to denote the +$cref/AD function/glossary/AD Function/$$ corresponding to $icode f$$. +Given a function $latex X : \B{R} \rightarrow \B{R}^n$$, +defined by its +$cref/Taylor coefficients/glossary/Taylor Coefficient/$$, +forward mode computes the Taylor coefficients for the function +$latex \[ + Y (t) = F [ X(t) ] +\]$$ +This version of forward mode computes multiple directions as the same +time (reducing the number of passes through the tape). This requires more +memory, but might be faster in some cases. + +$head Reverse Mode$$ +Reverse mode for multiple directions has not yet been implemented. +If you have speed tests that indicate that multiple direction forward +mode is faster, and you want to try multiple direction reverse mode, +contact the CppAD project manager. + +$head Notation$$ + +$subhead n$$ +We use $icode n$$ to denote the dimension of the +$cref/domain/seq_property/Domain/$$ space for $icode f$$. + +$subhead m$$ +We use $icode m$$ to denote the dimension of the +$cref/range/seq_property/Range/$$ space for $icode f$$. + +$head f$$ +The $cref ADFun$$ object $icode f$$ has prototype +$codei% + ADFun<%Base%> %f% +%$$ +Note that the $cref ADFun$$ object $icode f$$ is not $code const$$. +After this call we will have +$codei% + %f%.size_order() == %q% + 1 + %f%.size_direction() == %r% +%$$ + +$head q$$ +This argument has prototype +$codei% + size_t %q% +%$$ +It specifies the order of Taylor Coefficient that we are calculating +and must be greater than zero. +The zero order coefficients can only have one direction computed +and stored in $icode f$$ so use $cref forward_zero$$ +to compute the zero order coefficients. + +$head r$$ +This argument has prototype +$codei% + size_t %r% +%$$ +It specifies the number of directions that are computed together. +If ($icode%r% == 1%$$), you are only using one direction and +$cref forward_order$$ is simpler, and should be faster, +than this more general case. + +$head xq$$ +The argument $icode xq$$ has prototype +$codei% + const %Vector%& %xq% +%$$ +and its size must be $icode%n%*%r%$$ +(see $cref/Vector/forward_dir/Vector/$$ below). +For $latex \ell = 0 , \ldots , r-1$$, +$latex j = 0 , \ldots , n-1$$, +the $th j$$ component of the $th q$$ order Taylor coefficient +for $latex X_\ell (t)$$ is defined by +$pre + $$ $latex x_j^{(q),\ell} = $$ $icode%xq%[ %r% * %j% + %ell% ]%$$ + +$head Zero Order$$ +For $latex j = 0 , \ldots , n-1$$, +the $th j$$ component of the zero order Taylor coefficient +for $latex X_\ell (t)$$ is defined by +$pre + $$ $latex x_j^{(0)} = $$ $icode%xk%[ %j% ]%$$ +where $icode xk$$ corresponds to the previous call +$codei% + %f%.Forward(%k%, %xk%) +%$$ +with $icode%k% = 0%$$. + +$head Non-Zero Lower Orders$$ +For $latex \ell = 0 , \ldots , r-1$$, +$latex j = 0 , \ldots , n-1$$, +$latex k = 1, \ldots , q-1$$, +the $th j$$ component of the $th k$$ order Taylor coefficient +for $latex X_\ell (t)$$ is defined by +$pre + $$ $latex x_j^{(k),\ell} = $$ $icode%xk%[ %r% * %j% + %ell% ]%$$ +where $icode xk$$ corresponds to the previous call +$codei% + %f%.Forward(%k%, %r%, %xk%) +%$$ +Note that $icode r$$ must have the same value in this previous call. + +$head X(t)$$ +For $latex \ell = 0 , \ldots , r-1$$, the function +$latex X_\ell : \B{R} \rightarrow \B{R}^n$$ is defined using +the Taylor coefficients $latex x^{(k),\ell} \in \B{R}^n$$: +$latex \[ +X_\ell (t) = x^{(0)} + x^{(1),\ell} * t^1 + \cdots + x^{(q),\ell} t^q +\] $$ +Note that the $th k$$ derivative of $latex X_\ell (t)$$ is related to +its Taylor coefficients by +$latex \[ +\begin{array}{rcl} + x^{(0)} & = & X_\ell (0) + \\ + x^{(k), \ell} & = & \frac{1}{k !} X_\ell^{(k)} (0) +\end{array} +\] $$ +for $latex k = 1 , \ldots , q$$. + +$head Y(t)$$ +For $latex \ell = 0 , \ldots , r-1$$, the function +$latex Y_\ell : \B{R} \rightarrow \B{R}^m$$ is defined by +$latex Y_\ell (t) = F[ X_\ell (t) ] $$. +We use $latex y^{(0)}$$ for the zero order coefficient +and $latex y^{(k),\ell} \in \B{R}^m$$ to denote the +hight order coefficients; i.e., +$latex \[ +Y_\ell (t) = y^{(0)} + y^{(1),\ell} * t^1 + \cdots + y^{(q),\ell} * t^q ++ o( t^q ) +\] $$ +where $latex o( t^q ) * t^{-q} \rightarrow 0$$ as $latex t \rightarrow 0$$. +Note that the $th k$$ derivative of $latex Y_\ell (t)$$ is related to +its Taylor coefficients by +$latex \[ +\begin{array}{rcl} + y^{(0)} & = & Y_\ell (0) + \\ + y^{(k), \ell} & = & \frac{1}{k !} Y_\ell^{(k)} (0) +\end{array} +\] $$ +for $latex k = 1 , \ldots , q$$. + +$head yq$$ +The argument $icode yq$$ has prototype +$codei% + %Vector% %yq% +%$$ +and its size is $icode%m%*%r%$$ +(see $cref/Vector/forward_dir/Vector/$$ below). +For $latex \ell = 0 , \ldots , r-1$$, +$latex i = 0 , \ldots , m-1$$, +the $th i$$ component of the $th q$$ order Taylor coefficient +for $latex Y_\ell (t)$$ is given by +$pre + $$ $latex y_i^{(q),\ell} = $$ $icode%yq%[ %r% * %i% + %ell% ]%$$ + +$head Vector$$ +The type $icode Vector$$ must be a $cref SimpleVector$$ class with +$cref/elements of type/SimpleVector/Elements of Specified Type/$$ +$icode Base$$. +The routine $cref CheckSimpleVector$$ will generate an error message +if this is not the case. + +$children% + example/general/forward_dir.cpp +%$$ +$head Example$$ +The file +$cref forward_dir.cpp$$ +contains an example and test using one order (multiple orders). +They return true if they succeed and false otherwise. + +$end diff --git a/build-config/cppad/include/cppad/core/forward/forward_one.omh b/build-config/cppad/include/cppad/core/forward/forward_one.omh new file mode 100644 index 00000000..1be1c550 --- /dev/null +++ b/build-config/cppad/include/cppad/core/forward/forward_one.omh @@ -0,0 +1,111 @@ +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 Bradley M. Bell + + CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + + This Source Code may also be made available under the following + Secondary License when the conditions for such availability set forth + in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +-------------------------------------------------------------------------- */ +$begin forward_one$$ +$spell + Jacobian + Taylor + const +$$ + +$section First Order Forward Mode: Derivative Values$$ + + +$head Syntax$$ +$icode%y1% = %f%.Forward(1, %x1%)%$$ + +$head Purpose$$ +We use $latex F : \B{R}^n \rightarrow \B{R}^m$$ to denote the +$cref/AD function/glossary/AD Function/$$ corresponding to $icode f$$. +The result of the syntax above is +$latex \[ + y1 = F^{(1)} (x0) * x1 +\] $$ +where $latex F^{(1)} (x0)$$ is the Jacobian of $latex F$$ +evaluated at $icode x0$$. + +$head f$$ +The object $icode f$$ has prototype +$codei% + ADFun<%Base%> %f% +%$$ +Note that the $cref ADFun$$ object $icode f$$ is not $code const$$. +Before this call to $code Forward$$, the value returned by +$codei% + %f%.size_order() +%$$ +must be greater than or equal one. +After this call it will be will be two (see $cref size_order$$). + +$head x0$$ +The vector $icode x0$$ in the formula +$latex \[ + y1 = F^{(1)} (x0) * x1 +\] $$ +corresponds to the previous call to $cref forward_zero$$ +using this ADFun object $icode f$$; i.e., +$codei% + %f%.Forward(0, %x0%) +%$$ +If there is no previous call with the first argument zero, +the value of the $cref/independent/Independent/$$ variables +during the recording of the AD sequence of operations is used +for $icode x0$$. + +$head x1$$ +The argument $icode x1$$ has prototype +$codei% + const %Vector%& %x1% +%$$ +(see $cref/Vector/forward_one/Vector/$$ below) +and its size must be equal to $icode n$$, the dimension of the +$cref/domain/seq_property/Domain/$$ space for $icode f$$. + +$head Vector$$ +The type $icode Vector$$ must be a $cref SimpleVector$$ class with +$cref/elements of type/SimpleVector/Elements of Specified Type/$$ +$icode Base$$. +The routine $cref CheckSimpleVector$$ will generate an error message +if this is not the case. + +$head Example$$ +The file +$cref forward.cpp$$ +contains an example and test of this operation. + +$head Special Case$$ +This is special case of $cref forward_order$$ where +$latex \[ +\begin{array}{rcl} +Y(t) & = & F[ X(t) ] +\\ +X(t) & = & x^{(0)} t^0 + x^{(1)} * t^1 + \cdots, + x^{(q)} * t^q + o( t^q ) +\\ +Y(t) & = & y^{(0)} t^0 + y^{(1)} * t^1 + \cdots, + y^{(q)} * t^q + o( t^q ) +\end{array} +\] $$ +and $latex o( t^q ) * t^{-q} \rightarrow 0$$ as $latex t \rightarrow 0$$. +For this special case, $latex q = 1$$, +$latex x^{(0)}$$ $codei%= %x0%$$, +$latex x^{(1)}$$ $codei%= %x1%$$, +$latex X(t) = x^{(0)} + x^{(1)} t$$, and +$latex \[ + y^{(0)} + y^{(1)} t = F [ x^{(0)} + x^{(1)} t ] + o(t) +\] $$ +Taking the derivative with respect to $latex t$$, at $latex t = 0$$, +we obtain +$latex \[ + y^{(1)} = F^{(1)} [ x^{(0)} ] x^{(1)} +\] $$ +which agrees with the specifications for +$icode y1$$ in the $cref/purpose/forward_one/Purpose/$$ above. + +$end diff --git a/build-config/cppad/include/cppad/core/forward/forward_order.omh b/build-config/cppad/include/cppad/core/forward/forward_order.omh new file mode 100644 index 00000000..07e29700 --- /dev/null +++ b/build-config/cppad/include/cppad/core/forward/forward_order.omh @@ -0,0 +1,243 @@ +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 Bradley M. Bell + + CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + + This Source Code may also be made available under the following + Secondary License when the conditions for such availability set forth + in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +-------------------------------------------------------------------------- */ +$begin forward_order$$ +$spell + std::cout + ostream + xk + xp + yp + Ind + vp + uj + Taylor + const + xq + yq +$$ + +$section Multiple Order Forward Mode$$ + + +$head Syntax$$ +$icode%yq% = %f%.Forward(%q%, %xq% ) +%$$ +$icode%yq% = %f%.Forward(%q%, %xq%, %s%) +%$$ + + +$head Purpose$$ +We use $latex F : \B{R}^n \rightarrow \B{R}^m$$ to denote the +$cref/AD function/glossary/AD Function/$$ corresponding to $icode f$$. +Given a function $latex X : \B{R} \rightarrow \B{R}^n$$, +defined by its +$cref/Taylor coefficients/glossary/Taylor Coefficient/$$, +forward mode computes the Taylor coefficients for the function +$latex \[ + Y (t) = F [ X(t) ] +\]$$ + +$subhead Function Values$$ +If you are using forward mode to compute values for $latex F(x)$$, +$cref forward_zero$$ is simpler to understand +than this explanation of the general case. + +$subhead Derivative Values$$ +If you are using forward mode to compute values for $latex F^{(1)} (x) * dx$$, +$cref forward_one$$ is simpler to understand +than this explanation of the general case. + +$head Notation$$ + +$subhead n$$ +We use $icode n$$ to denote the dimension of the +$cref/domain/seq_property/Domain/$$ space for $icode f$$. + +$subhead m$$ +We use $icode m$$ to denote the dimension of the +$cref/range/seq_property/Range/$$ space for $icode f$$. + +$head f$$ +The $cref ADFun$$ object $icode f$$ has prototype +$codei% + ADFun<%Base%> %f% +%$$ +Note that the $cref ADFun$$ object $icode f$$ is not $code const$$. +After this call we will have +$codei% + %f%.size_order() == %q% + 1 + %f%.size_direction() == 1 +%$$ + +$head One Order$$ +If $icode%xq%.size() == %n%$$, +then we are only computing one order. +In this case, before this call we must have +$codei% + %f%.size_order() >= %q% + %f%.size_direction() == 1 +%$$ + + +$head q$$ +The argument $icode q$$ has prototype +$codei% + size_t %q% +%$$ +and specifies the highest order of the Taylor coefficients to be calculated. + +$head xq$$ +The argument $icode xq$$ has prototype +$codei% + const %BaseVector%& %xq% +%$$ +(see $cref/BaseVector/forward_order/BaseVector/$$ below). +As above, we use $icode n$$ to denote the dimension of the +$cref/domain/seq_property/Domain/$$ space for $icode f$$. +The size of $icode xq$$ must be either $icode n$$ or +$icode%n%*(%q%+1)%$$. +After this call we will have +$codei% + %f%.size_order() == %q% + 1 +%$$ + +$subhead One Order$$ +If $icode%xq%.size() == %n%$$, +the $th q$$ order Taylor coefficient for $latex X(t)$$ +is defined by +$pre + $$ $latex x^{(q)} = $$ $icode xq$$. +For $latex k = 0 , \ldots , q-1$$, +the Taylor coefficient $latex x^{(k)}$$ +is defined by $icode xk$$ in the previous call to +$codei% + %f%.Forward(%k%, %xk%) +%$$ + +$subhead Multiple Orders$$ +If $icode%xq%.size() == %n%*(%q%+1)%$$, +For $latex k = 0 , \ldots , q$$, +$latex j = 0 , \ldots , n-1$$, +the $th j$$ component of the $th k$$ order Taylor coefficient +for $latex X(t)$$ is defined by +$pre + $$ $latex x_j^{(k)} = $$ $icode%xq%[ (%q%+1) * %j% + %k% ]%$$ + +$subhead Restrictions$$ +Note if $icode f$$ uses $cref atomic_one$$ functions, +the size of $icode xq$$ must be $icode n$$. + +$head s$$ +If the argument $icode s$$ is not present, $code std::cout$$ +is used in its place. +Otherwise, this argument has prototype +$codei% + std::ostream& %s% +%$$ +If order zero is begin calculated, +$icode s$$ specifies where the output corresponding to $cref PrintFor$$ +will be written. +If order zero is not being calculated, +$icode s$$ is not used + +$head X(t)$$ +The function +$latex X : \B{R} \rightarrow \B{R}^n$$ is defined using +the Taylor coefficients $latex x^{(k)} \in \B{R}^n$$: +$latex \[ + X(t) = x^{(0)} * t^0 + x^{(1)} * t^1 + \cdots + x^{(q)} * t^q +\] $$ +Note that for $latex k = 0 , \ldots , q$$, +the $th k$$ derivative of $latex X(t)$$ is related to the +Taylor coefficients by the equation +$latex \[ + x^{(k)} = \frac{1}{k !} X^{(k)} (0) +\] $$ + +$head Y(t)$$ +The function +$latex Y : \B{R} \rightarrow \B{R}^m$$ is defined by +$latex Y(t) = F[ X(t) ] $$. +We use $latex y^{(k)} \in \B{R}^m$$ +to denote the $th k$$ order Taylor coefficient of $latex Y(t)$$; i.e., +$latex \[ + Y(t) = y^{(0)} * t^0 + y^{(1)} * t^1 + \cdots + y^{(q)} * t^q + o( t^q ) +\] $$ +where $latex o( t^q ) * t^{-q} \rightarrow 0$$ as $latex t \rightarrow 0$$. +Note that $latex y^{(k)}$$ is related to +the $th k$$ derivative of $latex Y(t)$$ by the equation +$latex \[ + y^{(k)} = \frac{1}{k !} Y^{(k)} (0) +\] $$ + +$head yq$$ +The return value $icode yq$$ has prototype +$codei% + %BaseVector% %yq% +%$$ +(see $cref/BaseVector/forward_order/BaseVector/$$ below). + +$subhead One Order$$ +If $icode%xq%.size() == %n%$$, +the vector $icode yq$$ has size $icode m$$. +The $th q$$ order Taylor coefficient for $latex Y(t)$$ +is returned as +$codei% + %yq%$$ $latex = y^{(q)}$$. + +$subhead Multiple Orders$$ +If $icode%xq%.size() == %n%*(%q%+1)%$$, +the vector $icode yq$$ has size $icode%m%*(%q%+1)%$$. +For $latex k = 0 , \ldots , q$$, +for $latex i = 0 , \ldots , m-1$$, +the $th i$$ component of the $th k$$ order Taylor coefficient +for $latex Y(t)$$ is returned as +$codei% + %yq%[ (%q%+1) * %i% + %k% ]%$$ $latex = y_i^{(k)}$$ + +$head BaseVector$$ +The type $icode BaseVector$$ must be a $cref SimpleVector$$ class with +$cref/elements of type/SimpleVector/Elements of Specified Type/$$ +$icode Base$$. +The routine $cref CheckSimpleVector$$ will generate an error message +if this is not the case. + +$head Zero Order$$ +The case where +$latex q = 0$$ and $icode%xq%.size() == %n%$$, +corresponds to the zero order +$cref/special case/forward_zero/Special Case/$$. + +$head First Order$$ +The case where +$latex q = 1$$ and $icode%xq%.size() == %n%$$, +corresponds to the first order +$cref/special case/forward_one/Special Case/$$. + +$head Second Order$$ +The case where +$latex q = 2$$ and $icode%xq%.size() == %n%$$, +corresponds to the second order +$cref/special case/forward_two/Special Case/$$. + +$children% + example/general/forward.cpp% + example/general/forward_order.cpp +%$$ +$head Example$$ +The files +$cref forward.cpp$$ and $cref forward_order.cpp$$ +contain examples and tests of using forward mode with +one order and multiple orders respectively. +They return true if they succeed and false otherwise. + +$end diff --git a/build-config/cppad/include/cppad/core/forward/forward_two.omh b/build-config/cppad/include/cppad/core/forward/forward_two.omh new file mode 100644 index 00000000..782aa864 --- /dev/null +++ b/build-config/cppad/include/cppad/core/forward/forward_two.omh @@ -0,0 +1,148 @@ +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 Bradley M. Bell + + CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + + This Source Code may also be made available under the following + Secondary License when the conditions for such availability set forth + in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +-------------------------------------------------------------------------- */ +$begin forward_two$$ +$spell + Jacobian + Taylor + const +$$ + +$section Second Order Forward Mode: Derivative Values$$ + + + +$head Syntax$$ +$icode%y2% = %f%.Forward(1, %x2%)%$$ + +$head Purpose$$ +We use $latex F : \B{R}^n \rightarrow \B{R}^m$$ to denote the +$cref/AD function/glossary/AD Function/$$ corresponding to $icode f$$. +The result of the syntax above is that for +$icode%i% = 0 , %...% , %m%-1%$$, +$codei% + %y2%[%i%]%$$ + $latex = F_i^{(1)} (x0) * x2 + \frac{1}{2} x1^T * F_i^{(2)} (x0) * x1$$ +$pre +$$ +where +$latex F^{(1)} (x0)$$ is the Jacobian of $latex F$$, and +$latex F_i^{(2)} (x0)$$ is the Hessian of th $th i$$ component of $latex F$$, +evaluated at $icode x0$$. + +$head f$$ +The object $icode f$$ has prototype +$codei% + ADFun<%Base%> %f% +%$$ +Note that the $cref ADFun$$ object $icode f$$ is not $code const$$. +Before this call to $code Forward$$, the value returned by +$codei% + %f%.size_order() +%$$ +must be greater than or equal two. +After this call it will be will be three (see $cref size_order$$). + +$head x0$$ +The vector $icode x0$$ in the formula for $icode%y2%[%i%]%$$ +corresponds to the previous call to $cref forward_zero$$ +using this ADFun object $icode f$$; i.e., +$codei% + %f%.Forward(0, %x0%) +%$$ +If there is no previous call with the first argument zero, +the value of the $cref/independent/Independent/$$ variables +during the recording of the AD sequence of operations is used +for $icode x0$$. + +$head x1$$ +The vector $icode x1$$ in the formula for $icode%y2%[%i%]%$$ +corresponds to the previous call to $cref forward_one$$ +using this ADFun object $icode f$$; i.e., +$codei% + %f%.Forward(1, %x1%) +%$$ + +$head x2$$ +The argument $icode x2$$ has prototype +$codei% + const %Vector%& %x2% +%$$ +(see $cref/Vector/forward_two/Vector/$$ below) +and its size must be equal to $icode n$$, the dimension of the +$cref/domain/seq_property/Domain/$$ space for $icode f$$. + +$head y2$$ +The result $icode y2$$ has prototype +$codei% + %Vector% %y2% +%$$ +(see $cref/Vector/forward_two/Vector/$$ below) +The size of $icode y1$$ is equal to $icode m$$, the dimension of the +$cref/range/seq_property/Range/$$ space for $icode f$$. +Its value is given element-wise by the formula in the +$cref/purpose/forward_two/Purpose/$$ above. + +$head Vector$$ +The type $icode Vector$$ must be a $cref SimpleVector$$ class with +$cref/elements of type/SimpleVector/Elements of Specified Type/$$ +$icode Base$$. +The routine $cref CheckSimpleVector$$ will generate an error message +if this is not the case. + +$head Example$$ +The file +$cref forward.cpp$$ +contains an example and test of this operation. + +$head Special Case$$ +This is special case of $cref forward_order$$ where +$latex \[ +\begin{array}{rcl} +Y(t) & = F[ X(t) ] +\\ +X(t) & = & x^{(0)} t^0 + x^{(1)} * t^1 + \cdots, + x^{(q)} * t^q + o( t^q ) +\\ +Y(t) & = & y^{(0)} t^0 + y^{(1)} * t^1 + \cdots, + y^{(q)} * t^q + o( t^q ) +\end{array} +\] $$ +and $latex o( t^q ) * t^{-q} \rightarrow 0$$ as $latex t \rightarrow 0$$. +For this special case, $latex q = 2$$, +$latex x^{(0)}$$ $codei%= %x0%$$, +$latex x^{(1)}$$ $codei%= %x1%$$, +$latex X(t) = x^{(0)} + x^{(1)} t + x^{(2)} t^2$$, and +$latex \[ +y^{(0)} + y^{(1)} t + y^{(2)} t^2 += +F [ x^{(0)} + x^{(1)} t + x^{(2)} t^2 ] + o(t^2) +\] $$ +Restricting our attention to the $th i$$ component, and +taking the derivative with respect to $latex t$$, we obtain +$latex \[ +y_i^{(1)} + 2 y_i^{(2)} t += +F_i^{(1)} [ x^{(0)} + x^{(1)} t + x^{(2)} t^2 ] [ x^{(1)} + 2 x^{(2)} t ] ++ +o(t) +\] $$ +Taking a second derivative with respect to $latex t$$, +and evaluating at $latex t = 0$$, we obtain +$latex \[ +2 y_i^{(2)} += +[ x^{(1)} ]^T F_i^{(2)} [ x^{(0)} ] x^{(1)} ++ +F_i^{(1)} [ x^{(0)} ] 2 x^{(2)} +\] $$ +which agrees with the specification for $icode%y2%[%i%]%$$ in the +$cref/purpose/forward_two/Purpose/$$ above. + +$end diff --git a/build-config/cppad/include/cppad/core/forward/forward_zero.omh b/build-config/cppad/include/cppad/core/forward/forward_zero.omh new file mode 100644 index 00000000..8b3dc64c --- /dev/null +++ b/build-config/cppad/include/cppad/core/forward/forward_zero.omh @@ -0,0 +1,116 @@ +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 Bradley M. Bell + + CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + + This Source Code may also be made available under the following + Secondary License when the conditions for such availability set forth + in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +-------------------------------------------------------------------------- */ +$begin forward_zero$$ +$spell + std::cout + ostream + const + Taylor + dy + Jacobian +$$ + +$section Zero Order Forward Mode: Function Values$$ + +$head Syntax$$ +$icode%y0% = %f%.Forward(0, %x0%) +%$$ +$icode%y0% = %f%.Forward(0, %x0%, %s%)%$$ + +$head Purpose$$ +We use $latex F : \B{R}^n \rightarrow \B{R}^m$$ to denote the +$cref/AD function/glossary/AD Function/$$ corresponding to $icode f$$. +The result of the syntax above is +$latex \[ + y0 = F(x0) +\] $$ +See the $cref/FunCheck discussion/FunCheck/Discussion/$$ for +possible differences between $latex F(x)$$ and the algorithm that defined +the operation sequence. + +$head f$$ +The object $icode f$$ has prototype +$codei% + ADFun<%Base%> %f% +%$$ +Note that the $cref ADFun$$ object $icode f$$ is not $code const$$. +After this call to $code Forward$$, the value returned by +$codei% + %f%.size_order() +%$$ +will be equal to one (see $cref size_order$$). + +$head x0$$ +The argument $icode x0$$ has prototype +$codei% + const %Vector%& %x0% +%$$ +(see $cref/Vector/forward_zero/Vector/$$ below) +and its size must be equal to $icode n$$, the dimension of the +$cref/domain/seq_property/Domain/$$ space for $icode f$$. + +$head s$$ +If the argument $icode s$$ is not present, $code std::cout$$ +is used in its place. +Otherwise, this argument has prototype +$codei% + std::ostream& %s% +%$$ +It specifies where the output corresponding to $cref PrintFor$$, +and this zero order forward mode call, will be written. + +$head y0$$ +The result $icode y0$$ has prototype +$codei% + %Vector% %y0% +%$$ +(see $cref/Vector/forward_zero/Vector/$$ below) +and its value is $latex F(x)$$ at $icode%x% = %x0%$$. +The size of $icode y0$$ is equal to $icode m$$, the dimension of the +$cref/range/seq_property/Range/$$ space for $icode f$$. + +$head Vector$$ +The type $icode Vector$$ must be a $cref SimpleVector$$ class with +$cref/elements of type/SimpleVector/Elements of Specified Type/$$ +$icode Base$$. +The routine $cref CheckSimpleVector$$ will generate an error message +if this is not the case. + +$head Example$$ +The file +$cref forward.cpp$$ +contains an example and test of this operation. + +$head Special Case$$ +This is special case of $cref forward_order$$ where +$latex \[ +\begin{array}{rcl} +Y(t) & = & F[ X(t) ] +\\ +X(t) & = & x^{(0)} t^0 + x^{(1)} * t^1 + \cdots, + x^{(q)} * t^q + o( t^q ) +\\ +Y(t) & = & y^{(0)} t^0 + y^{(1)} * t^1 + \cdots, + y^{(q)} * t^q + o( t^q ) +\end{array} +\] $$ +and $latex o( t^q ) * t^{-q} \rightarrow 0$$ as $latex t \rightarrow 0$$. +For this special case, $latex q = 0$$, +$latex x^{(0)}$$ $codei%= %x0%$$, +$latex X(t) = x^{(0)}$$, and +$latex \[ + y^{(0)} = Y(t) = F[ X(t) ] = F( x^{(0)} ) +\] $$ +which agrees with the specifications for +$icode y0$$ in the $cref/purpose/forward_zero/Purpose/$$ above. + + + +$end diff --git a/build-config/cppad/include/cppad/core/forward/size_order.omh b/build-config/cppad/include/cppad/core/forward/size_order.omh new file mode 100644 index 00000000..29d5480e --- /dev/null +++ b/build-config/cppad/include/cppad/core/forward/size_order.omh @@ -0,0 +1,97 @@ +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 Bradley M. Bell + + CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + + This Source Code may also be made available under the following + Secondary License when the conditions for such availability set forth + in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +-------------------------------------------------------------------------- */ +$begin size_order$$ +$spell + var + Taylor + const +$$ + +$section Number Taylor Coefficient Orders Currently Stored$$ + +$head Syntax$$ +$icode%s% = %f%.size_order()%$$ + +$subhead See Also$$ +$cref seq_property$$ + +$head Purpose$$ +Determine the number of Taylor coefficient orders, per variable,direction, +currently calculated and stored in the ADFun object $icode f$$. +See the discussion under +$cref/Constructor/size_order/Constructor/$$, +$cref/Forward/size_order/Forward/$$, and +$cref/capacity_order/size_order/capacity_order/$$ +for a description of when this value can change. + + +$head f$$ +The object $icode f$$ has prototype +$codei% + const ADFun<%Base%> %f% +%$$ + +$head s$$ +The result $icode s$$ has prototype +$codei% + size_t %s% +%$$ +and is the number of Taylor coefficient orders, +per variable,direction in the AD operation sequence, +currently calculated and stored in the ADFun object $icode f$$. + +$head Constructor$$ +Directly after the $cref FunConstruct$$ syntax +$codei% + ADFun<%Base%> %f%(%x%, %y%) +%$$ +the value of $icode s$$ returned by $code size_order$$ is one. +This is because +there is an implicit call to $code Forward$$ that computes +the zero order Taylor coefficients during this constructor. + +$head Forward$$ +After a call to $cref/Forward/forward_order/$$ with the syntax +$codei% + %f%.Forward(%q%, %x_q%) +%$$ +the value of $icode s$$ returned by $code size_order$$ +would be $latex q + 1$$. +The call to $code Forward$$ above +uses the lower order Taylor coefficients to compute and store +the $th q$$ order Taylor coefficients for all +the variables in the operation sequence corresponding to $icode f$$. +Thus there are $latex q + 1$$ (order zero through $icode q$$) +Taylor coefficients per variable,direction. +(You can determine the number of variables in the operation sequence +using the $cref/size_var/seq_property/size_var/$$ function.) + +$head capacity_order$$ +If the number of Taylor coefficient orders +currently stored in $icode f$$ is less than or equal $icode c$$, +a call to $cref capacity_order$$ with the syntax +$codei% + %f%.capacity_order(%c%) +%$$ +does not affect the value $icode s$$ returned by $code size_order$$. +Otherwise, +the value $icode s$$ returned by $code size_order$$ +is equal to $icode c$$ +(only Taylor coefficients of order zero through $latex c-1$$ +have been retained). + +$head Example$$ +The file +$cref forward.cpp$$ +contains an example and test of this operation. + +$end diff --git a/build-config/cppad/include/cppad/core/fun_check.hpp b/build-config/cppad/include/cppad/core/fun_check.hpp new file mode 100644 index 00000000..ebf60d8a --- /dev/null +++ b/build-config/cppad/include/cppad/core/fun_check.hpp @@ -0,0 +1,210 @@ +# ifndef CPPAD_CORE_FUN_CHECK_HPP +# define CPPAD_CORE_FUN_CHECK_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-18 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +/* +$begin FunCheck$$ +$spell + exp + bool + const + Taylor +$$ + + +$section Check an ADFun Sequence of Operations$$ + +$head Syntax$$ +$icode%ok% = FunCheck(%f%, %g%, %x%, %r%, %a%)%$$ +$pre +$$ +$bold See Also$$ +$cref CompareChange$$ + + +$head Purpose$$ +We use $latex F : \B{R}^n \rightarrow \B{R}^m$$ to denote the +$cref/AD function/glossary/AD Function/$$ corresponding to $icode f$$. +We use $latex G : \B{R}^n \rightarrow \B{R}^m$$ to denote the +function corresponding to the C++ function object $icode g$$. +This routine check if +$latex \[ + F(x) = G(x) +\]$$ +If $latex F(x) \neq G(x)$$, the +$cref/operation sequence/glossary/Operation/Sequence/$$ +corresponding to $icode f$$ does not represents the algorithm used +by $icode g$$ to calculate values for $latex G$$ +(see $cref/Discussion/FunCheck/Discussion/$$ below). + +$head f$$ +The $code FunCheck$$ argument $icode f$$ has prototype +$codei% + ADFun<%Base%> %f% +%$$ +Note that the $cref ADFun$$ object $icode f$$ is not $code const$$ +(see $cref/Forward/FunCheck/FunCheck Uses Forward/$$ below). + +$head g$$ +The $code FunCheck$$ argument $icode g$$ has prototype +$codei% + %Fun% &%g% +%$$ +($icode Fun$$ is defined the properties of $icode g$$). +The C++ function object $icode g$$ supports the syntax +$codei% + %y% = %g%(%x%) +%$$ +which computes $latex y = G(x)$$. + +$subhead x$$ +The $icode g$$ argument $icode x$$ has prototype +$codei% + const %Vector% &%x% +%$$ +(see $cref/Vector/FunCheck/Vector/$$ below) +and its size +must be equal to $icode n$$, the dimension of the +$cref/domain/seq_property/Domain/$$ space for $icode f$$. + +$head y$$ +The $icode g$$ result $icode y$$ has prototype +$codei% + %Vector% %y% +%$$ +and its value is $latex G(x)$$. +The size of $icode y$$ +is equal to $icode m$$, the dimension of the +$cref/range/seq_property/Range/$$ space for $icode f$$. + +$head x$$ +The $code FunCheck$$ argument $icode x$$ has prototype +$codei% + const %Vector% &%x% +%$$ +and its size +must be equal to $icode n$$, the dimension of the +$cref/domain/seq_property/Domain/$$ space for $icode f$$. +This specifies that point at which to compare the values +calculated by $icode f$$ and $icode G$$. + +$head r$$ +The $code FunCheck$$ argument $icode r$$ has prototype +$codei% + const %Base% &%r% +%$$ +It specifies the relative error the element by element +comparison of the value of $latex F(x)$$ and $latex G(x)$$. + +$head a$$ +The $code FunCheck$$ argument $icode a$$ has prototype +$codei% + const %Base% &%a% +%$$ +It specifies the absolute error the element by element +comparison of the value of $latex F(x)$$ and $latex G(x)$$. + +$head ok$$ +The $code FunCheck$$ result $icode ok$$ has prototype +$codei% + bool %ok% +%$$ +It is true, if for $latex i = 0 , \ldots , m-1$$ +either the relative error bound is satisfied +$latex \[ +| F_i (x) - G_i (x) | +\leq +r ( | F_i (x) | + | G_i (x) | ) +\] $$ +or the absolute error bound is satisfied +$latex \[ + | F_i (x) - G_i (x) | \leq a +\] $$ +It is false if for some $latex (i, j)$$ neither +of these bounds is satisfied. + +$head Vector$$ +The type $icode Vector$$ must be a $cref SimpleVector$$ class with +$cref/elements of type/SimpleVector/Elements of Specified Type/$$ +$icode Base$$. +The routine $cref CheckSimpleVector$$ will generate an error message +if this is not the case. + +$head FunCheck Uses Forward$$ +After each call to $cref Forward$$, +the object $icode f$$ contains the corresponding +$cref/Taylor coefficients/glossary/Taylor Coefficient/$$. +After $code FunCheck$$, +the previous calls to $cref Forward$$ are undefined. + +$head Discussion$$ +Suppose that the algorithm corresponding to $icode g$$ contains +$codei% + if( %x% >= 0 ) + %y% = exp(%x%) + else + %y% = exp(-%x%) +%$$ +where $icode x$$ and $icode y$$ are $codei%AD%$$ objects. +It follows that the +AD of $code double$$ $cref/operation sequence/glossary/Operation/Sequence/$$ +depends on the value of $icode x$$. +If the sequence of operations stored in $icode f$$ corresponds to +$icode g$$ with $latex x \geq 0$$, +the function values computed using $icode f$$ when $latex x < 0$$ +will not agree with the function values computed by $latex g$$. +This is because the operation sequence corresponding to $icode g$$ changed +(and hence the object $icode f$$ does not represent the function +$latex G$$ for this value of $icode x$$). +In this case, you probably want to re-tape the calculations +performed by $icode g$$ with the +$cref/independent variables/glossary/Tape/Independent Variable/$$ +equal to the values in $icode x$$ +(so AD operation sequence properly represents the algorithm +for this value of independent variables). + + +$head Example$$ +$children% + example/general/fun_check.cpp +%$$ +The file +$cref fun_check.cpp$$ +contains an example and test of this function. + +$end +--------------------------------------------------------------------------- +*/ + +namespace CppAD { + template + bool FunCheck( + ADFun &f , + Fun &g , + const Vector &x , + const Base &r , + const Base &a ) + { bool ok = true; + + size_t m = f.Range(); + Vector yf = f.Forward(0, x); + Vector yg = g(x); + + size_t i; + for(i = 0; i < m; i++) + ok &= NearEqual(yf[i], yg[i], r, a); + return ok; + } +} + +# endif diff --git a/build-config/cppad/include/cppad/core/fun_construct.hpp b/build-config/cppad/include/cppad/core/fun_construct.hpp new file mode 100644 index 00000000..0ffd988b --- /dev/null +++ b/build-config/cppad/include/cppad/core/fun_construct.hpp @@ -0,0 +1,542 @@ +# ifndef CPPAD_CORE_FUN_CONSTRUCT_HPP +# define CPPAD_CORE_FUN_CONSTRUCT_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ +/* +$begin FunConstruct$$ +$spell + alloc + num + Jac + bool + taylor + var + ADvector + const + Jacobian +$$ + +$spell +$$ + +$section Construct an ADFun Object and Stop Recording$$ + + +$head Syntax$$ +$codei%ADFun<%Base%> %f%(%x%, %y%); +%$$ +$codei%ADFun<%Base%> %f% +%$$ +$icode%f%.swap(%g%) +%$$ +$icode%f% = %g +%$$ + +$head Purpose$$ +The $codei%ADFun<%Base%>%$$ object $icode f$$ +stores an AD of $icode Base$$ +$cref/operation sequence/glossary/Operation/Sequence/$$. +It can then be used to calculate derivatives of the corresponding +$cref/AD function/glossary/AD Function/$$ +$latex \[ + F : \B{R}^n \rightarrow \B{R}^m +\] $$ +where $latex B$$ is the space corresponding to objects of type $icode Base$$. + +$head x$$ +If the argument $icode x$$ is present, it has prototype +$codei% + const %ADVector% &%x% +%$$ +It must be the vector argument in the previous call to +$cref Independent$$. +Neither its size, or any of its values, are allowed to change +between calling +$codei% + Independent(%x%) +%$$ +and +$codei% + ADFun<%Base%> %f%(%x%, %y%) +%$$ + +$head y$$ +If the argument $icode y$$ is present, it has prototype +$codei% + const %ADVector% &%y% +%$$ +The sequence of operations that map $icode x$$ +to $icode y$$ are stored in the ADFun object $icode f$$. + +$head ADVector$$ +The type $icode ADVector$$ must be a $cref SimpleVector$$ class with +$cref/elements of type/SimpleVector/Elements of Specified Type/$$ +$codei%AD<%Base%>%$$. +The routine $cref CheckSimpleVector$$ will generate an error message +if this is not the case. + +$head Default Constructor$$ +The default constructor +$codei% + ADFun<%Base%> %g% +%$$ +creates an +$codei%AD<%Base%>%$$ object with no corresponding operation sequence; i.e., +$codei% + %g%.size_var() +%$$ +returns the value zero (see $cref/size_var/seq_property/size_var/$$). + +$head Sequence Constructor$$ +The sequence constructor +$codei% + ADFun<%Base%> %f%(%x%, %y%) +%$$ +creates the $codei%AD<%Base%>%$$ object $icode f$$, +stops the recording of AD of $icode Base$$ operations +corresponding to the call +$codei% + Independent(%x%) +%$$ +and stores the corresponding operation sequence in the object $icode f$$. +It then stores the zero order Taylor coefficients +(corresponding to the value of $icode x$$) in $icode f$$. +This is equivalent to the following steps using the default constructor: + +$list number$$ +Create $icode f$$ with the default constructor +$codei% + ADFun<%Base%> %f%; +%$$ +$lnext +Stop the tape and storing the operation sequence using +$codei% + %f%.Dependent(%x%, %y%); +%$$ +(see $cref Dependent$$). +$lnext +Calculate the zero order Taylor coefficients for all +the variables in the operation sequence using +$codei% + %f%.Forward(%p%, %x_p%) +%$$ +with $icode p$$ equal to zero and the elements of $icode x_p$$ +equal to the corresponding elements of $icode x$$ +(see $cref Forward$$). +$lend + +$head Copy Constructor$$ +It is an error to attempt to use the $codei%ADFun<%Base%>%$$ copy constructor; +i.e., the following syntax is not allowed: +$codei% + ADFun<%Base%> %g%(%f%) +%$$ +where $icode f$$ is an $codei%ADFun<%Base%>%$$ object. +Use its $cref/default constructor/FunConstruct/Default Constructor/$$ instead +and its assignment operator. + +$head swap$$ +The swap operation $code%f%.swap(%g%)%$$ exchanges the contents of +the two $codei%ADFun<%Base%>%$$ functions; i.e., +$icode f$$ ($icode g$$) before the swap is identical to +$icode g$$ ($icode f$$) after the swap. + +$head Assignment Operator$$ +The $codei%ADFun<%Base%>%$$ assignment operation +$codei% + %g% = %f% +%$$ +makes a copy of the operation sequence currently stored in $icode f$$ +in the object $icode g$$. +The object $icode f$$ is not affected by this operation and +can be $code const$$. +All of information (state) stored in $icode f$$ is copied to $icode g$$ +and any information originally in $icode g$$ is lost. + +$subhead Move Semantics$$ +In the special case where $icode f$$ is a temporary object +(and enough C++11 features are supported by the compiler) +this assignment will use move semantics. +This avoids the overhead of the copying all the information from +$icode f$$ to $icode g$$. + +$subhead Taylor Coefficients$$ +The Taylor coefficient information currently stored in $icode f$$ +(computed by $cref/f.Forward/Forward/$$) is +copied to $icode g$$. +Hence, directly after this operation +$codei% + %g%.size_order() == %f%.size_order() +%$$ + +$subhead Sparsity Patterns$$ +The forward Jacobian sparsity pattern currently stored in $icode f$$ +(computed by $cref/f.ForSparseJac/ForSparseJac/$$) is +copied to $icode g$$. +Hence, directly after this operation +$codei% + %g%.size_forward_bool() == %f%.size_forward_bool() + %g%.size_forward_set() == %f%.size_forward_set() +%$$ + +$head Parallel Mode$$ +The call to $code Independent$$, +and the corresponding call to +$codei% + ADFun<%Base%> %f%( %x%, %y%) +%$$ +or +$codei% + %f%.Dependent( %x%, %y%) +%$$ +or $cref abort_recording$$, +must be preformed by the same thread; i.e., +$cref/thread_alloc::thread_num/ta_thread_num/$$ must be the same. + +$head Example$$ + +$subhead Sequence Constructor$$ +The file +$cref independent.cpp$$ +contains an example and test of the sequence constructor. + +$subhead Default Constructor$$ +The files +$cref fun_check.cpp$$ +and +$cref hes_lagrangian.cpp$$ +contain an examples and tests using the default constructor. +They return true if they succeed and false otherwise. + +$children% + example/general/fun_assign.cpp +%$$ +$subhead Assignment Operator$$ +The file +$cref fun_assign.cpp$$ +contains an example and test of the $codei%ADFun<%Base%>%$$ +assignment operator. + +$end +---------------------------------------------------------------------------- +*/ + +namespace CppAD { // BEGIN_CPPAD_NAMESPACE +/*! +\file fun_construct.hpp +ADFun function constructors and assignment operator. +*/ + +/*! +ADFun default constructor + +The C++ syntax for this operation is +\verbatim + ADFun f +\endverbatim +An empty ADFun object is created. +The Dependent member function, +or the ADFun assingment operator, +can then be used to put an operation sequence in this ADFun object. + +\tparam Base +is the base for the recording that can be stored in this ADFun object; +i.e., operation sequences that were recorded using the type AD. +*/ +template +ADFun::ADFun(void) : +function_name_(""), +exceed_collision_limit_(false), +has_been_optimized_(false), +check_for_nan_(true) , +compare_change_count_(0), +compare_change_number_(0), +compare_change_op_index_(0), +num_order_taylor_(0), +cap_order_taylor_(0), +num_direction_taylor_(0), +num_var_tape_(0) +{ } +// +// move semantics version of constructor +// (none of the defualt constructor values matter to the destructor) +template +ADFun::ADFun(ADFun&& f) +{ swap(f); } +// +// destructor +template +ADFun::~ADFun(void) +{ } +/*! +ADFun assignment operator + +The C++ syntax for this operation is +\verbatim + g = f +\endverbatim +where g and f are ADFun ADFun objects. +A copy of the the operation sequence currently stored in f +is placed in this ADFun object (called g above). +Any information currently stored in this ADFun object is lost. + +\tparam Base +is the base for the recording that can be stored in this ADFun object; +i.e., operation sequences that were recorded using the type AD. + +\param f +ADFun object containing the operation sequence to be copied. +*/ +template +void ADFun::operator=(const ADFun& f) +{ + // go through member variables in ad_fun.hpp order + // + // string objects + function_name_ = f.function_name_; + // + // bool objects + exceed_collision_limit_ = f.exceed_collision_limit_; + has_been_optimized_ = f.has_been_optimized_; + check_for_nan_ = f.check_for_nan_; + // + // size_t objects + compare_change_count_ = f.compare_change_count_; + compare_change_number_ = f.compare_change_number_; + compare_change_op_index_ = f.compare_change_op_index_; + num_order_taylor_ = f.num_order_taylor_; + cap_order_taylor_ = f.cap_order_taylor_; + num_direction_taylor_ = f.num_direction_taylor_; + num_var_tape_ = f.num_var_tape_; + // + // pod_vector objects + ind_taddr_ = f.ind_taddr_; + dep_taddr_ = f.dep_taddr_; + dep_parameter_ = f.dep_parameter_; + cskip_op_ = f.cskip_op_; + load_op2var_ = f.load_op2var_; + // + // pod_vector_maybe_vectors + taylor_ = f.taylor_; + subgraph_partial_ = f.subgraph_partial_; + // + // player + play_ = f.play_; + // + // subgraph + subgraph_info_ = f.subgraph_info_; + // + // sparse_pack + for_jac_sparse_pack_ = f.for_jac_sparse_pack_; + // + // sparse_list + for_jac_sparse_set_ = f.for_jac_sparse_set_; +} +/// swap +template +void ADFun::swap(ADFun& f) +{ + // string objects + function_name_.swap( f.function_name_ ); + // + // bool objects + std::swap( exceed_collision_limit_ , f.exceed_collision_limit_); + std::swap( has_been_optimized_ , f.has_been_optimized_); + std::swap( check_for_nan_ , f.check_for_nan_); + // + // size_t objects + std::swap( compare_change_count_ , f.compare_change_count_); + std::swap( compare_change_number_ , f.compare_change_number_); + std::swap( compare_change_op_index_ , f.compare_change_op_index_); + std::swap( num_order_taylor_ , f.num_order_taylor_); + std::swap( cap_order_taylor_ , f.cap_order_taylor_); + std::swap( num_direction_taylor_ , f.num_direction_taylor_); + std::swap( num_var_tape_ , f.num_var_tape_); + // + // pod_vector objects + ind_taddr_.swap( f.ind_taddr_); + dep_taddr_.swap( f.dep_taddr_); + dep_parameter_.swap( f.dep_parameter_); + taylor_.swap( f.taylor_); + cskip_op_.swap( f.cskip_op_); + load_op2var_.swap( f.load_op2var_); + // + // player + play_.swap(f.play_); + // + // subgraph_info + subgraph_info_.swap(f.subgraph_info_); + // + // sparse_pack + for_jac_sparse_pack_.swap( f.for_jac_sparse_pack_); + // + // sparse_list + for_jac_sparse_set_.swap( f.for_jac_sparse_set_); +} +/// Move semantics version of constructor and assignment +template +void ADFun::operator=(ADFun&& f) +{ swap(f); } + + +/*! +ADFun constructor from an operation sequence. + +The C++ syntax for this operation is +\verbatim + ADFun f(x, y) +\endverbatim +The operation sequence that started with the previous call + Independent(x), and that ends with this operation, is stored +in this ADFun object f. + +\tparam Base +is the base for the recording that will be stored in the object f; +i.e., the operations were recorded using the type AD. + +\tparam ADVector +is a simple vector class with elements of typea AD. + +\param x +is the independent variable vector for this ADFun object. +The domain dimension of this object will be the size of x. + +\param y +is the dependent variable vector for this ADFun object. +The range dimension of this object will be the size of y. + +\par Taylor Coefficients +A zero order forward mode sweep is done, +and if NDEBUG is not defined the resulting values for the +depenedent variables are checked against the values in y. +Thus, the zero order Taylor coefficients +corresponding to the value of the x vector +are stored in this ADFun object. +*/ +template +template +ADFun::ADFun(const ADVector &x, const ADVector &y) +{ + // used to identify the RecBase type in calls to sweeps + RecBase not_used_rec_base(0.0); + + CPPAD_ASSERT_KNOWN( + x.size() > 0, + "ADFun: independent variable vector has size zero." + ); + CPPAD_ASSERT_KNOWN( + Variable(x[0]), + "ADFun: independent variable vector has been changed." + ); + local::ADTape* tape = AD::tape_ptr(x[0].tape_id_); + CPPAD_ASSERT_KNOWN( + tape->size_independent_ == size_t ( x.size() ), + "ADFun: independent variable vector has been changed." + ); + size_t j, n = x.size(); +# ifndef NDEBUG + size_t i, m = y.size(); + for(j = 0; j < n; j++) + { CPPAD_ASSERT_KNOWN( + size_t(x[j].taddr_) == (j+1), + "ADFun: independent variable vector has been changed." + ); + CPPAD_ASSERT_KNOWN( + x[j].tape_id_ == x[0].tape_id_, + "ADFun: independent variable vector has been changed." + ); + } + for(i = 0; i < m; i++) + { CPPAD_ASSERT_KNOWN( + CppAD::Parameter( y[i] ) | (y[i].tape_id_ == x[0].tape_id_) , + "ADFun: dependent vector contains variables for" + "\na different tape than the independent variables." + ); + } +# endif + + // stop the tape and store the operation sequence + Dependent(tape, y); + + // This function has not yet been optimized + exceed_collision_limit_ = false; + + // ad_fun.hpp member values not set by dependent + check_for_nan_ = true; + + // allocate memory for one zero order taylor_ coefficient + CPPAD_ASSERT_UNKNOWN( num_order_taylor_ == 0 ); + CPPAD_ASSERT_UNKNOWN( num_direction_taylor_ == 0 ); + size_t c = 1; + size_t r = 1; + capacity_order(c, r); + CPPAD_ASSERT_UNKNOWN( cap_order_taylor_ == c ); + CPPAD_ASSERT_UNKNOWN( num_direction_taylor_ == r ); + + // set zero order coefficients corresponding to indpendent variables + CPPAD_ASSERT_UNKNOWN( n == ind_taddr_.size() ); + for(j = 0; j < n; j++) + { CPPAD_ASSERT_UNKNOWN( ind_taddr_[j] == (j+1) ); + CPPAD_ASSERT_UNKNOWN( size_t(x[j].taddr_) == (j+1) ); + taylor_[ ind_taddr_[j] ] = x[j].value_; + } + + // use independent variable values to fill in values for others + CPPAD_ASSERT_UNKNOWN( cskip_op_.size() == play_.num_op_rec() ); + CPPAD_ASSERT_UNKNOWN( load_op2var_.size() == play_.num_var_load_rec() ); + local::sweep::forward0(&play_, std::cout, false, + n, num_var_tape_, cap_order_taylor_, taylor_.data(), + cskip_op_.data(), load_op2var_, + compare_change_count_, + compare_change_number_, + compare_change_op_index_, + not_used_rec_base + ); + CPPAD_ASSERT_UNKNOWN( compare_change_count_ == 1 ); + CPPAD_ASSERT_UNKNOWN( compare_change_number_ == 0 ); + CPPAD_ASSERT_UNKNOWN( compare_change_op_index_ == 0 ); + + // now set the number of orders stored + num_order_taylor_ = 1; + +# ifndef NDEBUG + // on MS Visual Studio 2012, CppAD required in front of isnan ? + for(i = 0; i < m; i++) + if( taylor_[dep_taddr_[i]] != y[i].value_ || CppAD::isnan( y[i].value_ ) ) + { using std::endl; + std::ostringstream buf; + buf << "A dependent variable value is not equal to " + << "its tape evaluation value," << endl + << "perhaps it is nan." << endl + << "Dependent variable value = " + << y[i].value_ << endl + << "Tape evaluation value = " + << taylor_[dep_taddr_[i]] << endl + << "Difference = " + << y[i].value_ - taylor_[dep_taddr_[i]] << endl + ; + // buf.str() returns a string object with a copy of the current + // contents in the stream buffer. + std::string msg_str = buf.str(); + // msg_str.c_str() returns a pointer to the c-string + // representation of the string object's value. + const char* msg_char_star = msg_str.c_str(); + CPPAD_ASSERT_KNOWN( + 0, + msg_char_star + ); + } +# endif +} + +} // END_CPPAD_NAMESPACE +# endif diff --git a/build-config/cppad/include/cppad/core/fun_eval.hpp b/build-config/cppad/include/cppad/core/fun_eval.hpp new file mode 100644 index 00000000..3a67efa5 --- /dev/null +++ b/build-config/cppad/include/cppad/core/fun_eval.hpp @@ -0,0 +1,20 @@ +# ifndef CPPAD_CORE_FUN_EVAL_HPP +# define CPPAD_CORE_FUN_EVAL_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +# include +# include +# include +# include + +# endif diff --git a/build-config/cppad/include/cppad/core/graph/cpp_ad_graph.omh b/build-config/cppad/include/cppad/core/graph/cpp_ad_graph.omh new file mode 100644 index 00000000..b9f83878 --- /dev/null +++ b/build-config/cppad/include/cppad/core/graph/cpp_ad_graph.omh @@ -0,0 +1,227 @@ +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 Bradley M. Bell + + CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + + This Source Code may also be made available under the following + Secondary License when the conditions for such availability set forth + in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +-------------------------------------------------------------------------- */ +$begin cpp_ad_graph$$ +$spell + std + arg + asinh + acosh + atanh + erf + erfc + expm + ind + vec + np + nx + nc + op + struct + enum + cpp + Heaviside +$$ + +$section C++ Representation of an AD Graph$$ + +$head See Also$$ +$tref json_ad_graph$$ + +$head function$$ +This section defines a computational graph representation of a function +$latex y = f(x, p)$$. +The vector $icode x$$ is called the independent variable vector, +$icode p$$ is called the independent dynamic parameter vector, +and $icode y$$ is called the dependent variable vector. + +$head Node Indices$$ +The nodes in an AD graph have the following order: +$pre + p_0 , ... , p_{np-1} , + x_0 , ... , x_{nx-1} , + c_0 , ... , c_{nc-1} , + r_0 , ... , r_{no-1} +$$ + +$subhead p$$ +The sub-vector +$pre p_0, ... , p_{np-1}$$ is the independent dynamic parameter vector; +see $cref/n_dynamic_ind/cpp_ad_graph/n_dynamic_ind/$$. +The node index corresponding to $icode p_0$$ is $code 1$$. + +$subhead x$$ +The sub-vector +$pre x_1, ... , x_nx$$ is the independent variable vector; +see $cref/n_variable_ind/cpp_ad_graph/n_variable_ind/$$. +The node index corresponding to $icode x_0$$ is +the index corresponding to $icode p_0$$ plus $icode np$$. + +$subhead c$$ +The sub-vector +$pre c_1, ... , c_nc$$ is the constant parameter vector; +see $cref/constant_vec/cpp_ad_graph/constant_vec/$$. +The node index corresponding to $icode c_0$$ is +the index corresponding to $icode x_0$$ plus $icode nx$$. + +$subhead r$$ +The sub-vector +$pre r_i$$ for $icode%i%=0,%...%,%no%-1%$$ is the result vector +for the $th i$$ operator; +see $cref/operator_vec/cpp_ad_graph/operator_vec/$$. +All of the node arguments for an the $th i$$ operator are nodes +that come before the first element of $icode r_i$$. +The node index corresponding to the first element of $icode r_0$$ is +the index corresponding to $icode c_0$$ plus $icode nc$$. +For $icode%i% > 0%$$, +The node index corresponding to the first element of $icode r_i$$ is +the index corresponding to the first element of $icode r_{i-1}$$ plus +the number of results for the $th i-1$$ operator. + +$head function_name$$ +is a $code std::string$$ containing the name for the function +corresponding to this graph. + +$head discrete_name_vec$$ +is a vector with elements of type $code std::string$$. +A discrete function has one argument, one result, and it derivative +is always zero; e.g., the Heaviside function. +Calls by this function to discrete functions use the index in this +vector to identify the discrete functions; see +$cref/dis_graph_op/cpp_ad_graph/operator_arg/dis_graph_op/$$ below. +If there are no calls to discrete functions, this vector can be empty. + +$head atomic_name_vec$$ +is a vector with elements of type $code std::string$$. +An atomic function can have any number of arguments and results +and non-zero derivatives. +Calls by this function to other functions use the index in this +vector to identify the other functions; see +$cref/atom_graph_op/cpp_ad_graph/operator_arg/atom_graph_op/$$ below. +If there are no calls to other functions, this vector can be empty. +Discrete functions are faster, and simpler to create and use +than atomic functions. + +$head print_text_vec$$ +is a vector with elements of type $code std::string$$. +The $cref/print/graph_op_enum/Print/$$ operators uses indices +in this vector for the corresponding +$cref/before/PrintFor/before/$$ and $cref/after/PrintFor/after/$$ values. +If there are no print operators, this vector can be empty. + +$head n_dynamic_ind$$ +is the number of independent dynamic parameters in the function +(called $icode np$$ above); see +$cref/dynamic/Independent/dynamic/$$. + +$head n_variable_ind$$ +is the number of independent variables in the function +(called $icode nx$$ above); see +$cref/x/Independent/x/$$. + +$head constant_vec$$ +is a vector of with elements of type +$code double$$ and size $icode nc$$ that can be used to define this function. + +$head operator_vec$$ +is a vector with elements of type $code graph_op_enum$$ +and size $icode no$$ (the number of operators in the graph). +For $icode%i%= 0, %...%, %no%-1%$$ +$icode%operator_vec%[%i%]%$$ contains the instructions +for computing the result vector $icode r_i$$. + +$subhead C++11$$ +If the c++ compiler being used does not support c++11, +it is assumed that operators that +$cref/require c++11/graph_op_enum/Unary/Require C++11/$$ +are $bold not$$ used. + +$head operator_arg$$ +is a vector with size equal to the sum of the size of each +of its sub-vectors (which are described below). +For $icode%i%= 0, %...%, %no%-1%$$, we use +$icode%first_node%[%i%]%$$ to denote the index in $icode operator_arg$$ +of the first node argument to the $th i$$ operator. +We use $icode%n_node_arg%[%i%]%$$ to denote the number of node arguments +for the $th i$$ operator. +For $icode%j% = 0 , %...%, %n_node_arg%[%i%]-1%$$, +the $th j$$ node argument for the $th i$$ operator has node index +$codei% + %operator_arg%[ %first_node%[%i%] + %j% ] +%$$ +Except for the +$code dis_graph_op$$, $code atom_graph_op$$, and $code sum_graph_op$$ cases, +the $icode operator_arg$$ sub-vector for the $th i$$ operator starts are +$icode%first_node%[%i%]%$$ and has $icode%n_node_arg%[%i%]%$$ elements. + +$subhead dis_graph_op$$ +In the case where $icode%operator_vec%[%i%].op_enum%$$ is +$code dis_graph_op$$: +$codei% + %name_index%[%i%] = %operator_arg%[ %first_node%[%i%] - 1 ] +%$$ +is the index in $cref/discrete_name_vec/cpp_ad_graph/discrete_name_vec/$$ +of the function being called by this operator. +For this operator, +the $icode operator_arg$$ sub-vector for the $th i$$ operator +starts at index $icode%first_node%[%i%]-1%$$ +and has $codei%2 = %n_node_arg%[%i%]+1%$$ elements. + +$subhead atom_graph_op$$ +In the case where $icode%operator_vec%[%i%].op_enum%$$ is +$code atom_graph_op$$: +$codei% + %name_index%[%i%] = %operator_arg%[ %first_node%[%i%] - 3 ] +%$$ +is the index in $cref/atomic_name_vec/cpp_ad_graph/atomic_name_vec/$$ +of the function being called by this operator. +$codei% + %n_result%[%i%] = %operator_arg%[ %first_node%[%i%] - 2 ] +%$$ +is the number of result nodes for this operator. +$codei% + %n_node_arg%[%i%] = %operator_arg%[ %first_node%[%i%] - 1 ] +%$$ +is the number of node arguments for this operator. +For this operator, +the $icode operator_arg$$ sub-vector for the $th i$$ operator +starts at index $icode%first_node%[%i%]-3%$$ +and has $icode%n_node_arg%[%i%]+3%$$ elements. + +$subhead sum_graph_op$$ +In the case where $icode%operator_vec%[%i%].op_enum%$$ is +$code sum_graph_op$$: +$codei% + %n_node_arg%[%i%] = %operator_arg%[ %first_node%[%i%] - 1 ] +%$$ +is the number of node arguments for this operator. +For this operator, +the $icode operator_arg$$ sub-vector for the $th i$$ operator +starts at index $icode%first_node%[%i%]-1%$$ +and has $icode%n_node_arg%[%i%]+1%$$ elements. + +$head dependent_vec$$ +is a vector with size equal to the number element in $icode y$$. +The $th i$$ element of $icode y$$ corresponds to the node index +$icode%dependent_vec%[%i%]%$$. + +$head cpp_graph$$ +The $code cpp_graph$$ class implements the data structure above. +It is defined by the documentation sections under Contents below: + +$childtable% + include/cppad/core/graph/graph_op_enum.hpp% + include/cppad/core/graph/cpp_graph.omh% + include/cppad/core/graph/from_graph.hpp% + include/cppad/core/graph/to_graph.hpp +%$$ + +$end diff --git a/build-config/cppad/include/cppad/core/graph/cpp_graph.hpp b/build-config/cppad/include/cppad/core/graph/cpp_graph.hpp new file mode 100644 index 00000000..c259d888 --- /dev/null +++ b/build-config/cppad/include/cppad/core/graph/cpp_graph.hpp @@ -0,0 +1,404 @@ +# ifndef CPPAD_CORE_GRAPH_CPP_GRAPH_HPP +# define CPPAD_CORE_GRAPH_CPP_GRAPH_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ +# include +# include +# include +# include + +namespace CppAD { // BEGIN_CPPAD_NAMESPACE + +class cpp_graph { // BEGIN_CPP_GRAPH_CLASS +public: + typedef CppAD::graph::graph_op_enum graph_op_enum; +private: + // + std::string function_name_; + vector discrete_name_vec_; + vector atomic_name_vec_; + vector print_text_vec_; + size_t n_dynamic_ind_; + size_t n_variable_ind_; + vector constant_vec_; + vector operator_vec_; + vector operator_arg_; + vector dependent_vec_; +public: + typedef local::graph::cpp_graph_itr const_iterator; + // + const_iterator begin(void) const + { size_t op_index = 0; + return const_iterator(operator_vec_, operator_arg_, op_index); + } + const_iterator end(void) + { size_t op_index = operator_vec_.size(); + return const_iterator(operator_vec_, operator_arg_, op_index); + } +/* +------------------------------------------------------------------------------- +$begin cpp_graph_ctor$$ +$spell + obj + cpp + ind + vec + arg +$$ + +$section C++ AD Graph Constructor$$ + +$head Syntax$$ +$codei%cpp_graph %graph_obj% +%$$ +$icode%graph_obj%.initialize() +%$$ + +$head function_name$$ +$cref/function_name/cpp_ad_graph/function_name/$$ +is initialized to the empty string. + +$head n_dynamic_ind$$ +$cref/n_dynamic_ind/cpp_ad_graph/n_dynamic_ind/$$ is initialized as zero. + +$head n_variable_ind$$ +$cref/n_variable_ind/cpp_ad_graph/n_variable_ind/$$ is initialized as zero. + +$head constant_vec$$ +$cref/constant_vec/cpp_ad_graph/constant_vec/$$ is initialized as empty. + +$head operator_vec$$ +$cref/operator_vec/cpp_ad_graph/operator_vec/$$ is initialized as empty. + +$head operator_arg$$ +$cref/operator_arg/cpp_ad_graph/operator_arg/$$ is initialized as empty. + +$head dependent_vec$$ +$cref/dependent_vec/cpp_ad_graph/dependent_vec/$$ is initialized as empty. + +$end +-------------------------------------------------------------------------------- +*/ +public: + void initialize(void) + { function_name_ = ""; + n_dynamic_ind_ = 0; + n_variable_ind_ = 0; + discrete_name_vec_.resize(0); + atomic_name_vec_.resize(0); + print_text_vec_.resize(0); + constant_vec_.resize(0); + operator_vec_.resize(0); + operator_arg_.resize(0); + dependent_vec_.resize(0); + return; + } + cpp_graph(void) + { initialize(); } +/* +--------------------------------------------------------------------------------- +$begin cpp_graph_scalar$$ +$spell + obj + cpp + ind + std + const +$$ + +$section C++ AD Graph Scalar Values$$ + +$head Syntax$$ + +$subhead Get$$ +$icode%function_name% = %graph_obj%.function_name_get() +%$$ +$icode%n_dynamic_ind% = %graph_obj%.n_dynamic_ind_get() +%$$ +$icode%n_variable_ind% = %graph_obj%.n_variable_ind_get() +%$$ + +$subhead Set$$ +$icode%graph_obj%.function_name_set(%function_name%) +%$$ +$icode%graph_obj%.n_dynamic_ind_set(%n_dynamic_ind%) +%$$ +$icode%graph_obj%.n_variable_ind_set(%n_variable_ind%) +%$$ + +$head Set$$ +The argument for all the set operations is const. + +$head graph_obj$$ +is an $code cpp_graph$$ object. +It is const for all the get functions. + +$head function_name$$ +is a $code std::string&$$ specifying the name of the function +for this graph. + +$head n_dynamic_ind$$ +is a $code size_t$$ specifying the number of independent dynamic parameters. + +$head n_variable_ind$$ +is a $code size_t$$ specifying the number of independent variables. + +$end +*/ + // function_name + const std::string& function_name_get(void) const + { return function_name_; } + void function_name_set(const std::string& function_name) + { function_name_ = function_name; } + // + // n_dynamic_ind + const size_t& n_dynamic_ind_get(void) const + { return n_dynamic_ind_; } + void n_dynamic_ind_set(const size_t n_dynamic_ind) + { n_dynamic_ind_ = n_dynamic_ind; } + // + // n_variable_ind + const size_t& n_variable_ind_get(void) const + { return n_variable_ind_; } + void n_variable_ind_set(const size_t n_variable_ind) + { n_variable_ind_ = n_variable_ind; } +/* +--------------------------------------------------------------------------------- +$begin cpp_graph_vector$$ +$spell + obj + cpp + ind + std + const + vec + arg + op_enum +$$ + +$section C++ AD Graph Vector Values$$ + +$head Syntax$$ + +$subhead Size$$ +$icode%size% = %graph_obj%.discrete_name_vec_size() +%$$ +$icode%size% = %graph_obj%.atomic_name_vec_size() +%$$ +$icode%size% = %graph_obj%.print_text_vec_size() +%$$ +$icode%size% = %graph_obj%.constant_vec_size() +%$$ +$icode%size% = %graph_obj%.operator_vec_size() +%$$ +$icode%size% = %graph_obj%.operator_arg_size() +%$$ +$icode%size% = %graph_obj%.dependent_vec_size() +%$$ + +$subhead Get$$ +$icode%discrete_name% = %graph_obj%.discrete_name_vec_get(%index%) +%$$ +$icode%atomic_name% = %graph_obj%.atomic_name_vec_get(%index%) +%$$ +$icode%print_text% = %graph_obj%.print_text_vec_get(%index%) +%$$ +$icode%constant% = %graph_obj%.constant_vec_get(%index%) +%$$ +$icode%op_enum% = %graph_obj%.operator_vec_get(%index%) +%$$ +$icode%argument% = %graph_obj%.operator_arg_get(%index%) +%$$ +$icode%node_index% = %graph_obj%.dependent_vec_get(%index%) +%$$ + +$subhead Push Back$$ +$icode%graph_obj%.discrete_name_vec_push_back(%discrete_name%) +%$$ +$icode%graph_obj%.atomic_name_vec_push_back(%atomic_name%) +%$$ +$icode%graph_obj%.print_text_vec_push_back(%print_text%) +%$$ +$icode%graph_obj%.constant_vec_push_back(%constant%) +%$$ +$icode%graph_obj%.operator_vec_push_back(%op_enum%) +%$$ +$icode%graph_obj%.operator_arg_push_back(%argument%) +%$$ +$icode%graph_obj%.dependent_vec_get(%node_index%) +%$$ + +$subhead Find$$ +$icode%discrete_index% = %graph_obj%.discrete_name_vec_find(%discrete_name%) +%$$ +$icode%atomic_index% = %graph_obj%.atomic_name_vec_find(%atomic_name%) +%$$ +$icode%print_index% = %graph_obj%.print_text_vec_find(%print_text%) +%$$ + +$head Arguments$$ +All of the member function arguments are either call by value or const. + +$head size$$ +is a $code size_t$$ value equal to the current size of the specified vector. + +$head index$$ +is a $code size_t$$ value that must be less than the current size +of the specified vector. + +$head push_back$$ +The arguments for all the push_back functions are const. +The size of the specified vector before a push_back, +is the index in the vector corresponding to the argument value. +The size of the vector after the push_back is the size before plus one. + +$head graph_obj$$ +is an $code cpp_graph$$ object. +It is const for the size, get, and find functions and +not const for the push_back functions. + +$head discrete_name$$ +is a $code std::string$$ equal to the name of a $cref discrete$$ function. + +$head atomic_name$$ +is a $code std::string$$ equal to the name of an $cref atomic_three$$ function. + +$head print_text$$ +is a $code std::string$$ equal to the text to be printed. + +$head constant$$ +is a $code double$$ equal to the constant with the corresponding +index in $code constant_vec$$. + +$head op_enum$$ +is the $cref graph_op_enum$$ for corresponding operator. + +$head argument$$ +is the $code size_t$$ value for corresponding operator argument. + +$head node_index$$ +is the node index for the corresponding dependent variable with +the corresponding index in +$cref/dependent_vec/cpp_ad_graph/dependent_vec/$$. + +$head discrete_index$$ +is the index such that +$codei% + %discrete_name% == %graph_obj%.discrete_name_vec_get(%discrete_index%) +%$$ +If there is no such index, +$codei% + %discrete_index% == %graph_obj%.discrete_name_vec_size() +%$$ + +$head atomic_index$$ +is the index such that +$codei% + %atomic_name% == %graph_obj%.atomic_name_vec_get(%atomic_index%) +%$$ +If there is no such index, +$codei% + %atomic_index% == %graph_obj%.atomic_name_vec_size() +%$$ + +$head print_index$$ +is the index such that +$codei% + %print_text% == %graph_obj%.print_text_vec_get(%print_index%) +%$$ +If there is no such index, +$codei% + %print_index% == %graph_obj%.print_text_vec_size() +%$$ + + +$end +*/ + // discrete_name_vec + const std::string& discrete_name_vec_get(size_t index) const + { return discrete_name_vec_[index]; } + size_t discrete_name_vec_size(void) const + { return discrete_name_vec_.size(); } + void discrete_name_vec_push_back(const std::string& discrete_name) + { discrete_name_vec_.push_back(discrete_name); } + size_t discrete_name_vec_find(const std::string& discrete_name) const + { for(size_t i = 0; i < discrete_name_vec_.size(); ++i) + if( discrete_name == discrete_name_vec_[i] ) + return i; + return discrete_name_vec_.size(); + } + // + // atomic_name_vec + const std::string& atomic_name_vec_get(size_t index) const + { return atomic_name_vec_[index]; } + size_t atomic_name_vec_size(void) const + { return atomic_name_vec_.size(); } + void atomic_name_vec_push_back(const std::string& atomic_name) + { atomic_name_vec_.push_back(atomic_name); } + size_t atomic_name_vec_find(const std::string& atomic_name) const + { for(size_t i = 0; i < atomic_name_vec_.size(); ++i) + if( atomic_name == atomic_name_vec_[i] ) + return i; + return atomic_name_vec_.size(); + } + // + // print_text_vec + const std::string& print_text_vec_get(size_t index) const + { return print_text_vec_[index]; } + size_t print_text_vec_size(void) const + { return print_text_vec_.size(); } + void print_text_vec_push_back(const std::string& atomic_name) + { print_text_vec_.push_back(atomic_name); } + size_t print_text_vec_find(const std::string& print_text) const + { for(size_t i = 0; i < print_text_vec_.size(); ++i) + if( print_text == print_text_vec_[i] ) + return i; + return print_text_vec_.size(); + } + // + // constant_vec + const double& constant_vec_get(size_t index) const + { return constant_vec_[index]; } + size_t constant_vec_size(void) const + { return constant_vec_.size(); } + void constant_vec_push_back(const double& constant) + { constant_vec_.push_back(constant); } + // + // oerator_vec + const graph_op_enum& operator_vec_get(size_t index) const + { return operator_vec_[index]; } + size_t operator_vec_size(void) const + { return operator_vec_.size(); } + void operator_vec_push_back(const graph_op_enum op_enum) + { operator_vec_.push_back(op_enum); } + // + // operator_arg + const size_t& operator_arg_get(size_t index) const + { return operator_arg_[index]; } + size_t operator_arg_size(void) const + { return operator_arg_.size(); } + void operator_arg_push_back(const size_t argument) + { operator_arg_.push_back(argument); } + // + // dependent_vec + const size_t& dependent_vec_get(size_t index) const + { return dependent_vec_[index]; } + size_t dependent_vec_size(void) const + { return dependent_vec_.size(); } + void dependent_vec_push_back(const size_t node_index) + { dependent_vec_.push_back(node_index); } + +}; // END CPP_GRAPH_CLASS + +} // END_CPPAD_NAMESPACE + +# endif diff --git a/build-config/cppad/include/cppad/core/graph/cpp_graph.omh b/build-config/cppad/include/cppad/core/graph/cpp_graph.omh new file mode 100644 index 00000000..d20dc2fb --- /dev/null +++ b/build-config/cppad/include/cppad/core/graph/cpp_graph.omh @@ -0,0 +1,20 @@ +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 Bradley M. Bell + + CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + + This Source Code may also be made available under the following + Secondary License when the conditions for such availability set forth + in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +-------------------------------------------------------------------------- */ +$begin cpp_graph$$ + +$section A C++ AD Graph Class$$ + +$childtable% + include/cppad/core/graph/cpp_graph.hpp +%$$ + +$end diff --git a/build-config/cppad/include/cppad/core/graph/from_graph.hpp b/build-config/cppad/include/cppad/core/graph/from_graph.hpp new file mode 100644 index 00000000..85ce50a8 --- /dev/null +++ b/build-config/cppad/include/cppad/core/graph/from_graph.hpp @@ -0,0 +1,1498 @@ +# ifndef CPPAD_CORE_GRAPH_FROM_GRAPH_HPP +# define CPPAD_CORE_GRAPH_FROM_GRAPH_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +# include +# include +# include + +namespace CppAD { // BEGIN_CPPAD_NAMESPACE +/* +$begin from_graph$$ +$spell + CppAD + ind + vec + arg + obj + op_enum + dyn2var +$$ + +$section ADFun Object Corresponding to a CppAD Graph$$ + +$head Syntax$$ +$codei% + ADFun<%Base%> %fun% + %fun%.from_graph(%graph_obj%) + %fun%.from_graph(%graph_obj%, %dyn2var%, %var2dyn%) +%$$ + +$head Prototype$$ +$srcthisfile% + 0%// BEGIN_ONE_ARGUMENT%// END_ONE_ARGUMENT%1 +%$$ +$srcthisfile% + 0%// BEGIN_WITH_IS_DYNAMIC%// END_WITH_IS_DYNAMIC%1 +%$$ + +$head Base$$ +is the type corresponding to this $cref/ADFun/adfun/$$ object; +i.e., its calculations are done using the type $icode Base$$. + +$head RecBase$$ +in the prototype above, $icode RecBase$$ is the same type as $icode Base$$. + +$head graph_obj$$ +is a $cref cpp_ad_graph$$ representation of this function. + +$head dyn2var$$ +is a vector with size equal to the number of independent dynamic parameters +in the graph; i.e., the size of $cref/p/cpp_ad_graph/Node Indices/p/$$. +It specifies which independent dynamic parameters in the graph are +independent variables in the function $icode fun$$. + +$head var2dyn$$ +is a vector with size equal to the number of independent variables +in the graph; i.e., the size of $cref/x/cpp_ad_graph/Node Indices/x/$$. +It specifies which independent variables in the graph are +independent dynamic parameters in the function $icode fun$$. + +$head fun$$ +It $icode dyn2var$$ and $icode var2dyn$$ are not present, +the independent dynamic parameters and independent variables in $icode fun$$ +are the same as for the graph. +Otherwise, they are described below. + +$subhead m_true, m_false$$ +Let $icode m_true$$ ($icode m_false$$) be the number of true (false) +elements of $icode dyn2var$$. + +$subhead n_true, n_false$$ +Let $icode n_true$$ ($icode n_false$$) be the number of true (false) +elements of $icode var2dyn$$. + +$subhead Independent Dynamic Parameters$$ +The first $icode m_false$$ independent dynamic parameters in $icode fun$$ +correspond to the false components of $icode dyn2var$$ +and have the same order as in the graph. +The next $icode n_true$$ independent dynamic parameters in $icode fun$$ +correspond to the true components of $icode var2dyn$$ +and have the same order as in the graph. + +$subhead Independent Variables$$ +The first $icode m_true$$ independent variables in $icode fun$$ +correspond to the true components of $icode dyn2var$$ +and have the same order as in the graph. +The next $icode n_false$$ independent variables in $icode fun$$ +correspond to the false components of $icode var2dyn$$ +and have the same order as in the graph. + +$children% + example/graph/switch_var_dyn.cpp +%$$ +$head Examples$$ +The file $cref switch_var_dyn.cpp$$ contains an example and test +of this routine. +For simpler examples, that do not change the dynamic parameters and variables; +see $cref/graph_op_enum examples/graph_op_enum/Examples/$$. + +$end +*/ +// BEGIN_WITH_IS_DYNAMIC +template +void CppAD::ADFun::from_graph( + const CppAD::cpp_graph& graph_obj , + const CppAD::vector& dyn2var , + const CppAD::vector& var2dyn ) +// END_WITH_IS_DYNAMIC +{ using CppAD::isnan; + using namespace CppAD::graph; + // + // some sizes + const std::string function_name = graph_obj.function_name_get(); + const size_t n_dynamic_ind = graph_obj.n_dynamic_ind_get(); + const size_t n_variable_ind = graph_obj.n_variable_ind_get(); + const size_t n_constant = graph_obj.constant_vec_size(); + const size_t n_usage = graph_obj.operator_vec_size(); + const size_t n_dependent = graph_obj.dependent_vec_size(); + // + // n_dynamic_ind_fun + // n_variable_ind_fun + CPPAD_ASSERT_KNOWN( + n_variable_ind == var2dyn.size(), + "from_graph: size of var2dyn not equal " + "number of independent variables in graph" + ); + CPPAD_ASSERT_KNOWN( + n_dynamic_ind == dyn2var.size(), + "from_graph: size of dyn2val not equal " + "number of independent dynamic parameters in graph" + ); + size_t n_dynamic_ind_fun = 0; + size_t n_variable_ind_fun = 0; + for(size_t i = 0; i < n_dynamic_ind; ++i) + { if( dyn2var[i] ) + ++n_variable_ind_fun; + else + ++n_dynamic_ind_fun; + } + for(size_t i = 0; i < n_variable_ind; ++i) + { if( var2dyn[i] ) + ++n_dynamic_ind_fun; + else + ++n_variable_ind_fun; + } + // + // Start of node indices + size_t start_dynamic_ind = 1; + size_t start_independent = start_dynamic_ind + n_dynamic_ind; + size_t start_constant = start_independent + n_variable_ind; + size_t start_operator = start_constant + n_constant; + // + // initialize mappings from node index as empty + // (there is no node zero) + vector node_type( 1 ); + local::pod_vector node2fun( 1 ); + node_type[0] = number_ad_type_enum; // invalid value + node2fun[0] = 0; // invalid value + // + // discrete_index + // mapping from index in discrete_name_vec to discrete index + size_t n_list_discrete = discrete::list_size(); + size_t n_graph_discrete = graph_obj.discrete_name_vec_size(); + vector discrete_index( n_graph_discrete ); + for(size_t i = 0; i < n_graph_discrete; ++i) + discrete_index[i] = n_list_discrete; // invalid discrete index + for(size_t index = 0; index < n_list_discrete; ++index) + { const char* name( discrete::name(index) ); + size_t graph_index = graph_obj.discrete_name_vec_find(name); + if( graph_index != n_graph_discrete ) + { if( discrete_index[graph_index] != n_list_discrete ) + { std::string msg = "from_graph: error in call to "; + msg += name; + msg += ".\nThere is mor than one discrete "; + msg += "function with this name"; + // + // use this source code as point of detection + bool known = true; + int line = __LINE__; + const char* file = __FILE__; + const char* exp = "discrete_index[i] == n_list_discrete"; + // + // CppAD error handler + ErrorHandler::Call( known, line, file, exp, msg.c_str() ); + } + discrete_index[graph_index] = index; + } + } + // + // atomic_three_index + // mapping from index in atomic_name_vec to atomic three index + size_t n_graph_atomic = graph_obj.atomic_name_vec_size(); + vector atomic_three_index( n_graph_atomic ); + for(size_t index = 0; index < n_graph_atomic; ++index) + atomic_three_index[index] = 0; // invalid atomic index + + { bool set_null = true; + size_t index_in = 0; + size_t type; + std::string name; + void* ptr; + size_t n_atomic = CppAD::local::atomic_index( + set_null, index_in, type, &name, ptr + ); + set_null = false; + for(index_in = 1; index_in <= n_atomic; ++index_in) + { CppAD::local::atomic_index( + set_null, index_in, type, &name, ptr + ); + if( type == 3 ) + { size_t graph_index = graph_obj.atomic_name_vec_find(name); + if( graph_index != n_graph_atomic ) + { if( atomic_three_index[graph_index] != 0 ) + { std::string msg = "from_graph: error in call to "; + msg += name + ".\n"; + msg += "There is more than one atomic_three "; + msg += "function with this name"; + // + // use this source code as point of detection + bool known = true; + int line = __LINE__; + const char* file = __FILE__; + const char* exp = "atomic_index[index] == 0"; + // + // CppAD error handler + ErrorHandler::Call( + known, line, file, exp, msg.c_str() + ); + } + atomic_three_index[graph_index] = index_in; + } + } + } + } + // ---------------------------------------------------------------------- + // Create a recording for this function + // ---------------------------------------------------------------------- + + // start a recording + local::recorder rec; + CPPAD_ASSERT_UNKNOWN( rec.num_op_rec() == 0 ); + rec.set_num_dynamic_ind(n_dynamic_ind_fun); + rec.set_abort_op_index(0); + rec.set_record_compare(false); + + // rec_text_index + // mapping from print_text_vec index to recording index + vector rec_text_index( graph_obj.print_text_vec_size() ); + for(size_t i = 0; i < graph_obj.print_text_vec_size(); ++i) + { const std::string& text = graph_obj.print_text_vec_get(i); + rec_text_index[i] = rec.PutTxt( text.c_str() ); + } + + // nan + Base nan = CppAD::numeric_limits::quiet_NaN(); + + // Place the parameter with index 0 in the tape + const local::pod_vector_maybe& parameter( rec.all_par_vec()); + CPPAD_ASSERT_UNKNOWN( parameter.size() == 0 ); + addr_t i_par = rec.put_con_par(nan); + CPPAD_ASSERT_UNKNOWN( i_par == 0 ); + CPPAD_ASSERT_UNKNOWN( isnan( parameter[i_par] ) ); + // + // Place the variable with index 0 in the tape + CPPAD_ASSERT_NARG_NRES(local::BeginOp, 1, 1); + rec.PutOp(local::BeginOp); + rec.PutArg(0); + // + // Next come the independent dynamic parameters in the graph + addr_t i_var = 0; + for(size_t i = 0; i < n_dynamic_ind; ++i) + { + if( dyn2var[i] ) + { i_var = rec.PutOp( local::InvOp ); + node_type.push_back(variable_enum);; + node2fun.push_back(i_var); + } + else + { i_par = rec.put_dyn_par(nan, local::ind_dyn ); + CPPAD_ASSERT_UNKNOWN( isnan( parameter[i_par] ) ); + node_type.push_back(dynamic_enum); + node2fun.push_back(i_par); + } + } + + // Next come the independent variables in the graph + CPPAD_ASSERT_NARG_NRES(local::InvOp, 0, 1); + for(size_t i = 0; i < n_variable_ind; ++i) + { if( var2dyn[i] ) + { i_par = rec.put_dyn_par(nan, local::ind_dyn ); + CPPAD_ASSERT_UNKNOWN( isnan( parameter[i_par] ) ); + node_type.push_back(dynamic_enum); + node2fun.push_back(i_par); + } + else + { i_var = rec.PutOp( local::InvOp ); + node_type.push_back(variable_enum);; + node2fun.push_back(i_var); + } + } + CPPAD_ASSERT_UNKNOWN( size_t( i_par ) == n_dynamic_ind_fun ); + CPPAD_ASSERT_UNKNOWN( size_t( i_var ) == n_variable_ind_fun ); + + // Next come the constant parameters + for(size_t i = 0; i < n_constant; ++i) + { Base par = Base( graph_obj.constant_vec_get(i) ); + i_par = rec.put_con_par(par); + CPPAD_ASSERT_UNKNOWN( parameter[i_par] == par ); + // + node_type.push_back(constant_enum);; + node2fun.push_back(i_par); + } + + // + // local arrays used to avoid reallocating memory + local::pod_vector temporary; + vector type_x; + vector arg; + vector arg_node; + // + // arrays only used by atom_graph_op + vector parameter_x, taylor_y; + vector type_y; + vector< AD > ax, ay; + // + // define here because not using as loop index + cpp_graph::const_iterator graph_itr; + // + // loop over operators in the recording + size_t start_result = start_operator; + for(size_t op_index = 0; op_index < n_usage; ++op_index) + { // op_enum, str_index, n_result, arg_node + if( op_index == 0 ) + graph_itr = graph_obj.begin(); + else + ++graph_itr; + cpp_graph::const_iterator::value_type itr_value = *graph_itr; + const vector& str_index(*itr_value.str_index_ptr ); + graph_op_enum op_enum = itr_value.op_enum; + size_t n_result = itr_value.n_result; + size_t n_arg = itr_value.arg_node_ptr->size(); + arg.resize(n_arg); + // + // make sure type_x is large enough + type_x.resize(n_arg); +# ifndef NDEBUG + addr_t n_con_arg = 0; +# endif + addr_t n_dyn_arg = 0; + addr_t n_var_arg = 0; + for(size_t j = 0; j < n_arg; ++j) + { size_t node_index = (*itr_value.arg_node_ptr)[j]; + // + // argument to graph operator + CPPAD_ASSERT_KNOWN( node_index < start_result, + "from_graph op argument index is greater or equal\n" + "the starting index for the next result" + ); + // + // type of argument + type_x[j] = node_type[ node_index ]; + // + // argument to function operator + arg[j] = node2fun[ node_index ]; + CPPAD_ASSERT_UNKNOWN( arg[j] != 0 ); + // + // count number of arguments of different types +# ifndef NDEBUG + n_con_arg += addr_t( type_x[j] == constant_enum ); +# endif + n_dyn_arg += addr_t( type_x[j] == dynamic_enum ); + n_var_arg += addr_t( type_x[j] == variable_enum ); + } + CPPAD_ASSERT_UNKNOWN( + n_arg == size_t(n_con_arg + n_dyn_arg + n_var_arg) + ); + // + addr_t i_result = 0; // invalid value + // ------------------------------------------------------------------- + // conditional expressions + // ------------------------------------------------------------------- + if( op_enum == cexp_eq_graph_op || + op_enum == cexp_le_graph_op || + op_enum == cexp_lt_graph_op ) + { CPPAD_ASSERT_UNKNOWN( n_result == 1 && n_arg == 4 ); + // cop + CompareOp cop; + if( op_enum == cexp_eq_graph_op ) + cop = CompareEq; + else if ( op_enum == cexp_le_graph_op ) + cop = CompareLe; + else + cop = CompareLt; + // + if( n_var_arg == 0 ) + { if( n_dyn_arg == 0 ) + { // result is a constant parameter + Base result = CondExpOp(cop, + parameter[arg[0]], // left + parameter[arg[1]], // right + parameter[arg[2]], // if_true + parameter[arg[3]] // if_false + ); + i_result = rec.put_con_par(result); + } + else + { i_result = rec.put_dyn_cond_exp( + nan, cop, arg[0], arg[1], arg[2], arg[3] + ); + } + } + else + { // flag marking which arguments are variables + addr_t flag = 0; + addr_t bit = 1; + for(size_t j = 0; j < 4; ++j) + { if( type_x[j] == variable_enum ) + flag |= bit; + bit = 2 * bit; + } + CPPAD_ASSERT_UNKNOWN( flag != 0 ); + rec.PutArg(addr_t(cop), flag, arg[0], arg[1], arg[2], arg[3]); + i_result = rec.PutOp(local::CExpOp); + } + } + // ------------------------------------------------------------------- + // compare operators + // ------------------------------------------------------------------- + else if( + op_enum == comp_eq_graph_op || + op_enum == comp_le_graph_op || + op_enum == comp_lt_graph_op || + op_enum == comp_ne_graph_op ) + { CPPAD_ASSERT_UNKNOWN( n_result == 0 && n_arg == 2 ); + // + bool var_left = type_x[0] == variable_enum; + bool var_right = type_x[1] == variable_enum; + bool dyn_left = type_x[0] == dynamic_enum; + bool dyn_right = type_x[1] == dynamic_enum; + // + ax.resize(n_arg); + // ax[0] + if( var_left | dyn_left ) + ax[0].taddr_ = arg[0]; + else + ax[0].value_ = parameter_x[0]; + // ax[1] + if( var_right | dyn_right ) + ax[1].taddr_ = arg[1]; + else + ax[1].value_ = parameter_x[1]; + // + bool result; + switch( op_enum ) + { + case comp_eq_graph_op: + result = true; + rec.comp_eq( + var_left, var_right, dyn_left, dyn_right, ax[0], ax[1], result + ); + break; + + case comp_le_graph_op: + result = true; + rec.comp_le( + var_left, var_right, dyn_left, dyn_right, ax[0], ax[1], result + ); + break; + + case comp_lt_graph_op: + result = true; + rec.comp_lt( + var_left, var_right, dyn_left, dyn_right, ax[0], ax[1], result + ); + break; + + case comp_ne_graph_op: + result = false; + rec.comp_eq( + var_left, var_right, dyn_left, dyn_right, ax[0], ax[1], result + ); + break; + + + default: + CPPAD_ASSERT_UNKNOWN(false); + } + } + // ------------------------------------------------------------------- + // sum operator + // ------------------------------------------------------------------- + else if( op_enum == sum_graph_op ) + { + CPPAD_ASSERT_KNOWN( n_result == 1 , + "AD graph sum operator: n_result is not 1" + ); + if( n_var_arg == 0 ) + { // result of the sum is a parameter + Base sum_constant = 0.0; + temporary.resize(0); + for(size_t j = 0; j < n_arg; j++) + { if( type_x[j] == constant_enum ) + sum_constant += parameter[ arg[j] ]; + else + { CPPAD_ASSERT_UNKNOWN( type_x[j] == dynamic_enum ); + temporary.push_back( arg[j] ); + } + } + CPPAD_ASSERT_UNKNOWN( temporary.size() == size_t(n_dyn_arg) ); + // + // start with constant parameter + i_result = rec.put_con_par(sum_constant); + CPPAD_ASSERT_UNKNOWN( parameter[i_result] == sum_constant ); + // + // sum the dynamic parameters + for(addr_t j = 0; j < n_dyn_arg; ++j) + { i_result = rec.put_dyn_par( + nan, local::add_dyn, i_result, temporary[j] + ); + CPPAD_ASSERT_UNKNOWN( isnan( parameter[i_result] ) ); + } + } + else + { // result of the sum is a variable + size_t n_temporary = 6 + size_t(n_var_arg + n_dyn_arg); + if( temporary.size() < n_temporary ) + temporary.resize( n_temporary ); + Base sum_constant = 0.0; + addr_t j_variable = 5 ; + addr_t j_dynamic = 5 + n_var_arg; + for(size_t j = 0; j < n_arg; j++) + { if( type_x[j] == constant_enum ) + sum_constant += parameter[ arg[j] ]; + if( type_x[j] == variable_enum ) + temporary[ j_variable++ ] = arg[j]; + if( type_x[j] == dynamic_enum ) + temporary[ j_dynamic++ ] = arg[j]; + } + temporary[j_dynamic] = j_dynamic; + // + temporary[0] = rec.put_con_par(sum_constant); + CPPAD_ASSERT_UNKNOWN(parameter[temporary[0]] == sum_constant); + // + temporary[1] = 5 + n_var_arg; + temporary[2] = 5 + n_var_arg; + temporary[3] = temporary[2] + n_dyn_arg; + temporary[4] = temporary[2] + n_dyn_arg; + // + i_result = rec.PutOp(local::CSumOp); + for(size_t j = 0; j < n_temporary; ++j) + rec.PutArg( temporary[j] ); + CPPAD_ASSERT_UNKNOWN( local::NumRes(local::CSumOp) == 1 ); + } + } + // ------------------------------------------------------------------- + // print operator + // ------------------------------------------------------------------- + else if( op_enum == print_graph_op ) + { CPPAD_ASSERT_UNKNOWN( n_arg == 2 && n_result == 0 ); + // + // before + size_t before_graph = str_index[0]; + addr_t before_rec = rec_text_index[before_graph]; + // + // after + size_t after_graph = str_index[1]; + addr_t after_rec = rec_text_index[after_graph]; + // + // base 2 representation of [ Var(notpos), Var(value) ] + addr_t is_var = 0; + if( type_x[0] == variable_enum ) + is_var += 1; + if( type_x[1] == variable_enum ) + is_var += 2; + // + // record this print operator + addr_t notpos = arg[0]; + addr_t value = arg[1]; + rec.PutOp(local::PriOp); + rec.PutArg(is_var, notpos, before_rec, value, after_rec); + } + // ------------------------------------------------------------------- + // discrete operator + // ------------------------------------------------------------------- + else if( op_enum == discrete_graph_op ) + { CPPAD_ASSERT_UNKNOWN( n_arg == 1 && n_result == 1 ); + size_t name_index = str_index[0]; + size_t function_index = discrete_index[name_index]; + if( function_index == n_list_discrete ) + { std::string msg = "from_graph: error in call to "; + msg += graph_obj.discrete_name_vec_get(name_index); + msg += ".\nNo previously defined discrete function "; + msg += "has this name"; + // + // use this source code as point of detection + bool known = true; + int line = __LINE__; + const char* file = __FILE__; + const char* exp = + "discrete_index[name_index] != n_list_discrete"; + // + // CppAD error handler + ErrorHandler::Call(known, line, file, exp, msg.c_str()); + } + if( type_x[0] == variable_enum ) + { CPPAD_ASSERT_NARG_NRES(local::DisOp, 2, 1); + i_result = rec.PutOp(local::DisOp); + rec.PutArg( addr_t(function_index) ); + rec.PutArg( arg[0] ); + } + else if( type_x[0] == dynamic_enum ) + { i_result = rec.put_dyn_par( + nan, local::dis_dyn, addr_t(function_index), arg[0] + ); + } + else + { Base result = discrete::eval( + function_index, parameter[ arg[0] ] + ); + i_result = rec.put_con_par(result); + CPPAD_ASSERT_UNKNOWN( parameter[i_result] == result ); + } + } + // ------------------------------------------------------------------- + // atomic operator + // ------------------------------------------------------------------- + else if( op_enum == atom_graph_op ) + { size_t name_index = str_index[0]; + // + // atomic_index + CPPAD_ASSERT_UNKNOWN( name_index < atomic_three_index.size() ); + size_t atomic_index = atomic_three_index[name_index]; + if( atomic_index == 0 ) + { std::string msg = "from_graph: error in call to "; + msg += graph_obj.atomic_name_vec_get(name_index); + msg += ".\n"; + msg += "No previously defined atomic_three function "; + msg += "has this name"; + // + // use this source code as point of detection + bool known = true; + int line = __LINE__; + const char* file = __FILE__; + const char* exp = "atomic_index != 0"; + // + // CppAD error handler + ErrorHandler::Call(known, line, file, exp, msg.c_str()); + } + // + // afun + bool set_null = false; + size_t type; + std::string* name = nullptr; + void* v_ptr; + CppAD::local::atomic_index( + set_null, atomic_index, type, name, v_ptr + ); + CPPAD_ASSERT_UNKNOWN( type == 3 ); + atomic_three* afun = + reinterpret_cast< atomic_three* >( v_ptr ); + // + // parameter_x + parameter_x.resize(n_arg); + for(size_t j = 0; j < n_arg; ++j) + { if( type_x[j] == constant_enum ) + parameter_x[j] = parameter[ arg[j] ]; + else + parameter_x[j] = nan; + } + // + // type_y + type_y.resize(n_result); + afun->for_type(parameter_x, type_x, type_y); + // + // taylor_y + size_t need_y = size_t(constant_enum); + size_t order_low = 0; + size_t order_up = 0; + taylor_y.resize(n_result); + afun->forward( + parameter_x , + type_x , + need_y , + order_low , + order_up , + parameter_x , + taylor_y + ); + // + // record_dynamic, record_variable + bool record_dynamic = false; + bool record_variable = false; + for(size_t i = 0; i < n_result; ++i) + { CPPAD_ASSERT_UNKNOWN( type_y[i] <= variable_enum ); + record_dynamic |= type_y[i] == dynamic_enum; + record_variable |= type_y[i] == variable_enum; + } + // tape_id is zero because not a true recording + tape_id_t tape_id = 0; + // + // ax, ay + if( record_dynamic || record_variable ) + { // tape_id (not a recording AD operations) + // ax + ax.resize(n_arg); + for(size_t j = 0; j < n_arg; ++j) + { ax[j].value_ = parameter_x[j]; + ax[j].taddr_ = arg[j]; + } + // ay + ay.resize(n_result); + for(size_t i = 0; i < n_result; ++i) + { ay[i].value_ = taylor_y[i]; + ay[i].taddr_ = 0; + } + } + if( record_dynamic ) rec.put_dyn_atomic( + tape_id, atomic_index, type_x, type_y, ax, ay + ); + if( record_variable ) rec.put_var_atomic( + tape_id, atomic_index, type_x, type_y, ax, ay + ); + // + // node_type, node2fun + for(size_t i = 0; i < n_result; ++i) + { node_type.push_back(type_y[i]); + switch( type_y[i] ) + { case constant_enum: + node2fun.push_back(rec.put_con_par(taylor_y[i])); + break; + + case dynamic_enum: + case variable_enum: + node2fun.push_back(ay[i].taddr_); + break; + + default: + CPPAD_ASSERT_UNKNOWN(false); + break; + } + } + } + // ------------------------------------------------------------------- + // unary operators + // ------------------------------------------------------------------- + else if( n_arg == 1 ) + { CPPAD_ASSERT_UNKNOWN( n_arg == 1 && n_result == 1 ); + Base result; // used in cases argument is a constant + if( type_x[0] == variable_enum ) switch( op_enum ) + { + case abs_graph_op: + i_result = rec.PutOp(local::AbsOp); + rec.PutArg( arg[0] ); + CPPAD_ASSERT_UNKNOWN( NumArg(local::AbsOp) == 1 ); + break; + + case acosh_graph_op: + i_result = rec.PutOp(local::AcoshOp); + rec.PutArg( arg[0] ); + CPPAD_ASSERT_UNKNOWN( NumArg(local::AcoshOp) == 1 ); + break; + + case asinh_graph_op: + i_result = rec.PutOp(local::AsinhOp); + rec.PutArg( arg[0] ); + CPPAD_ASSERT_UNKNOWN( NumArg(local::AsinhOp) == 1 ); + break; + + case atanh_graph_op: + i_result = rec.PutOp(local::AtanhOp); + rec.PutArg( arg[0] ); + CPPAD_ASSERT_UNKNOWN( NumArg(local::AtanhOp) == 1 ); + break; + + case erf_graph_op: + i_result = rec.PutOp(local::ErfOp); + CPPAD_ASSERT_UNKNOWN( NumArg(local::ErfOp) == 3 ); + // + // arg[0] = variable index for function argument + rec.PutArg( arg[0] ); + // + // parameter[ arg[1] ] = 0.0 + i_par = rec.put_con_par( Base(0.0) ); + rec.PutArg( i_par ); + // + // parameter[ arg[2] ] = 2 / sqrt(pi) + i_par = rec.put_con_par(Base( + 1.0 / std::sqrt( std::atan(1.0) ) + )); + rec.PutArg( i_par ); + // + break; + + case erfc_graph_op: + i_result = rec.PutOp(local::ErfcOp); + CPPAD_ASSERT_UNKNOWN( NumArg(local::ErfcOp) == 3 ); + // + // arg[0] = variable index for function argument + rec.PutArg( arg[0] ); + // + // parameter[ arg[1] ] = 0.0 + i_par = rec.put_con_par( Base(0.0) ); + rec.PutArg( i_par ); + // + // parameter[ arg[2] ] = 2 / sqrt(pi) + i_par = rec.put_con_par(Base( + 1.0 / std::sqrt( std::atan(1.0) ) + )); + rec.PutArg( i_par ); + // + break; + + case expm1_graph_op: + i_result = rec.PutOp(local::Expm1Op); + rec.PutArg( arg[0] ); + CPPAD_ASSERT_UNKNOWN( NumArg(local::Expm1Op) == 1 ); + break; + + case log1p_graph_op: + i_result = rec.PutOp(local::Log1pOp); + rec.PutArg( arg[0] ); + CPPAD_ASSERT_UNKNOWN( NumArg(local::Log1pOp) == 1 ); + break; + + case acos_graph_op: + i_result = rec.PutOp(local::AcosOp); + rec.PutArg( arg[0] ); + CPPAD_ASSERT_UNKNOWN( NumArg(local::AcosOp) == 1 ); + break; + + case asin_graph_op: + i_result = rec.PutOp(local::AsinOp); + rec.PutArg( arg[0] ); + CPPAD_ASSERT_UNKNOWN( NumArg(local::AsinOp) == 1 ); + break; + + case atan_graph_op: + i_result = rec.PutOp(local::AtanOp); + rec.PutArg( arg[0] ); + CPPAD_ASSERT_UNKNOWN( NumArg(local::AtanOp) == 1 ); + break; + + case cosh_graph_op: + i_result = rec.PutOp(local::CoshOp); + rec.PutArg( arg[0] ); + CPPAD_ASSERT_UNKNOWN( NumArg(local::CoshOp) == 1 ); + break; + + case cos_graph_op: + i_result = rec.PutOp(local::CosOp); + rec.PutArg( arg[0] ); + CPPAD_ASSERT_UNKNOWN( NumArg(local::CosOp) == 1 ); + break; + + case exp_graph_op: + i_result = rec.PutOp(local::ExpOp); + rec.PutArg( arg[0] ); + CPPAD_ASSERT_UNKNOWN( NumArg(local::ExpOp) == 1 ); + break; + + case log_graph_op: + i_result = rec.PutOp(local::LogOp); + rec.PutArg( arg[0] ); + CPPAD_ASSERT_UNKNOWN( NumArg(local::LogOp) == 1 ); + break; + + case sign_graph_op: + i_result = rec.PutOp(local::SignOp); + rec.PutArg( arg[0] ); + CPPAD_ASSERT_UNKNOWN( NumArg(local::SignOp) == 1 ); + break; + + case sinh_graph_op: + i_result = rec.PutOp(local::SinhOp); + rec.PutArg( arg[0] ); + CPPAD_ASSERT_UNKNOWN( NumArg(local::SinhOp) == 1 ); + break; + + case sin_graph_op: + i_result = rec.PutOp(local::SinOp); + rec.PutArg( arg[0] ); + CPPAD_ASSERT_UNKNOWN( NumArg(local::SinOp) == 1 ); + break; + + case sqrt_graph_op: + i_result = rec.PutOp(local::SqrtOp); + rec.PutArg( arg[0] ); + CPPAD_ASSERT_UNKNOWN( NumArg(local::SqrtOp) == 1 ); + break; + + case tanh_graph_op: + i_result = rec.PutOp(local::TanhOp); + rec.PutArg( arg[0] ); + CPPAD_ASSERT_UNKNOWN( NumArg(local::TanhOp) == 1 ); + break; + + case tan_graph_op: + i_result = rec.PutOp(local::TanOp); + rec.PutArg( arg[0] ); + CPPAD_ASSERT_UNKNOWN( NumArg(local::TanOp) == 1 ); + break; + + default: + CPPAD_ASSERT_UNKNOWN( false ); + break; + } + else if( type_x[0] == dynamic_enum ) switch( op_enum ) + { + case abs_graph_op: + i_result = rec.put_dyn_par(nan, local::abs_dyn, arg[0] ); + CPPAD_ASSERT_UNKNOWN( isnan( parameter[i_result] ) ); + break; + + case acosh_graph_op: + i_result = rec.put_dyn_par(nan, local::acosh_dyn, arg[0] ); + CPPAD_ASSERT_UNKNOWN( isnan( parameter[i_result] ) ); + break; + + case asinh_graph_op: + i_result = rec.put_dyn_par(nan, local::asinh_dyn, arg[0] ); + CPPAD_ASSERT_UNKNOWN( isnan( parameter[i_result] ) ); + break; + + case atanh_graph_op: + i_result = rec.put_dyn_par(nan, local::atanh_dyn, arg[0] ); + CPPAD_ASSERT_UNKNOWN( isnan( parameter[i_result] ) ); + break; + + case erf_graph_op: + i_result = rec.put_dyn_par(nan, local::erf_dyn, arg[0] ); + CPPAD_ASSERT_UNKNOWN( isnan( parameter[i_result] ) ); + break; + + case erfc_graph_op: + i_result = rec.put_dyn_par(nan, local::erfc_dyn, arg[0] ); + CPPAD_ASSERT_UNKNOWN( isnan( parameter[i_result] ) ); + break; + + case expm1_graph_op: + i_result = rec.put_dyn_par(nan, local::expm1_dyn, arg[0] ); + CPPAD_ASSERT_UNKNOWN( isnan( parameter[i_result] ) ); + break; + + case log1p_graph_op: + i_result = rec.put_dyn_par(nan, local::log1p_dyn, arg[0] ); + CPPAD_ASSERT_UNKNOWN( isnan( parameter[i_result] ) ); + break; + + case acos_graph_op: + i_result = rec.put_dyn_par(nan, local::acos_dyn, arg[0] ); + CPPAD_ASSERT_UNKNOWN( isnan( parameter[i_result] ) ); + break; + + case asin_graph_op: + i_result = rec.put_dyn_par(nan, local::asin_dyn, arg[0] ); + CPPAD_ASSERT_UNKNOWN( isnan( parameter[i_result] ) ); + break; + + case atan_graph_op: + i_result = rec.put_dyn_par(nan, local::atan_dyn, arg[0] ); + CPPAD_ASSERT_UNKNOWN( isnan( parameter[i_result] ) ); + break; + + case cosh_graph_op: + i_result = rec.put_dyn_par(nan, local::cosh_dyn, arg[0] ); + CPPAD_ASSERT_UNKNOWN( isnan( parameter[i_result] ) ); + break; + + case cos_graph_op: + i_result = rec.put_dyn_par(nan, local::cos_dyn, arg[0] ); + CPPAD_ASSERT_UNKNOWN( isnan( parameter[i_result] ) ); + break; + + case exp_graph_op: + i_result = rec.put_dyn_par(nan, local::exp_dyn, arg[0] ); + CPPAD_ASSERT_UNKNOWN( isnan( parameter[i_result] ) ); + break; + + case log_graph_op: + i_result = rec.put_dyn_par(nan, local::log_dyn, arg[0] ); + CPPAD_ASSERT_UNKNOWN( isnan( parameter[i_result] ) ); + break; + + case sign_graph_op: + i_result = rec.put_dyn_par(nan, local::sign_dyn, arg[0] ); + CPPAD_ASSERT_UNKNOWN( isnan( parameter[i_result] ) ); + break; + + case sinh_graph_op: + i_result = rec.put_dyn_par(nan, local::sinh_dyn, arg[0] ); + CPPAD_ASSERT_UNKNOWN( isnan( parameter[i_result] ) ); + break; + + case sin_graph_op: + i_result = rec.put_dyn_par(nan, local::sin_dyn, arg[0] ); + CPPAD_ASSERT_UNKNOWN( isnan( parameter[i_result] ) ); + break; + + case sqrt_graph_op: + i_result = rec.put_dyn_par(nan, local::sqrt_dyn, arg[0] ); + CPPAD_ASSERT_UNKNOWN( isnan( parameter[i_result] ) ); + break; + + case tanh_graph_op: + i_result = rec.put_dyn_par(nan, local::tanh_dyn, arg[0] ); + CPPAD_ASSERT_UNKNOWN( isnan( parameter[i_result] ) ); + break; + + case tan_graph_op: + i_result = rec.put_dyn_par(nan, local::tan_dyn, arg[0] ); + CPPAD_ASSERT_UNKNOWN( isnan( parameter[i_result] ) ); + break; + + default: + CPPAD_ASSERT_UNKNOWN( false ); + break; + } + else switch( op_enum ) + { + case abs_graph_op: + result = CppAD::abs( parameter[ arg[0] ] ); + i_result = rec.put_con_par(result); + CPPAD_ASSERT_UNKNOWN( parameter[i_result] == result ); + break; + + case acosh_graph_op: + result = CppAD::acosh( parameter[ arg[0] ] ); + i_result = rec.put_con_par(result); + CPPAD_ASSERT_UNKNOWN( parameter[i_result] == result ); + break; + + case asinh_graph_op: + result = CppAD::asinh( parameter[ arg[0] ] ); + i_result = rec.put_con_par(result); + CPPAD_ASSERT_UNKNOWN( parameter[i_result] == result ); + break; + + case atanh_graph_op: + result = CppAD::atanh( parameter[ arg[0] ] ); + i_result = rec.put_con_par(result); + CPPAD_ASSERT_UNKNOWN( parameter[i_result] == result ); + break; + + case erf_graph_op: + result = CppAD::erf( parameter[ arg[0] ] ); + i_result = rec.put_con_par(result); + CPPAD_ASSERT_UNKNOWN( parameter[i_result] == result ); + break; + + case erfc_graph_op: + result = CppAD::erfc( parameter[ arg[0] ] ); + i_result = rec.put_con_par(result); + CPPAD_ASSERT_UNKNOWN( parameter[i_result] == result ); + break; + + case expm1_graph_op: + result = CppAD::expm1( parameter[ arg[0] ] ); + i_result = rec.put_con_par(result); + CPPAD_ASSERT_UNKNOWN( parameter[i_result] == result ); + break; + + case log1p_graph_op: + result = CppAD::log1p( parameter[ arg[0] ] ); + i_result = rec.put_con_par(result); + CPPAD_ASSERT_UNKNOWN( parameter[i_result] == result ); + break; + + case acos_graph_op: + result = CppAD::acos( parameter[ arg[0] ] ); + i_result = rec.put_con_par(result); + CPPAD_ASSERT_UNKNOWN( parameter[i_result] == result ); + break; + + case asin_graph_op: + result = CppAD::asin( parameter[ arg[0] ] ); + i_result = rec.put_con_par(result); + CPPAD_ASSERT_UNKNOWN( parameter[i_result] == result ); + break; + + case atan_graph_op: + result = CppAD::atan( parameter[ arg[0] ] ); + i_result = rec.put_con_par(result); + CPPAD_ASSERT_UNKNOWN( parameter[i_result] == result ); + break; + + case cosh_graph_op: + result = CppAD::cosh( parameter[ arg[0] ] ); + i_result = rec.put_con_par(result); + CPPAD_ASSERT_UNKNOWN( parameter[i_result] == result ); + break; + + case cos_graph_op: + result = CppAD::cos( parameter[ arg[0] ] ); + i_result = rec.put_con_par(result); + CPPAD_ASSERT_UNKNOWN( parameter[i_result] == result ); + break; + + case exp_graph_op: + result = CppAD::exp( parameter[ arg[0] ] ); + i_result = rec.put_con_par(result); + CPPAD_ASSERT_UNKNOWN( parameter[i_result] == result ); + break; + + case log_graph_op: + result = CppAD::log( parameter[ arg[0] ] ); + i_result = rec.put_con_par(result); + CPPAD_ASSERT_UNKNOWN( parameter[i_result] == result ); + break; + + case sign_graph_op: + result = CppAD::sign( parameter[ arg[0] ] ); + i_result = rec.put_con_par(result); + CPPAD_ASSERT_UNKNOWN( parameter[i_result] == result ); + break; + + case sinh_graph_op: + result = CppAD::sinh( parameter[ arg[0] ] ); + i_result = rec.put_con_par(result); + CPPAD_ASSERT_UNKNOWN( parameter[i_result] == result ); + break; + + case sin_graph_op: + result = CppAD::sin( parameter[ arg[0] ] ); + i_result = rec.put_con_par(result); + CPPAD_ASSERT_UNKNOWN( parameter[i_result] == result ); + break; + + case sqrt_graph_op: + result = CppAD::sqrt( parameter[ arg[0] ] ); + i_result = rec.put_con_par(result); + CPPAD_ASSERT_UNKNOWN( parameter[i_result] == result ); + break; + + case tanh_graph_op: + result = CppAD::tanh( parameter[ arg[0] ] ); + i_result = rec.put_con_par(result); + CPPAD_ASSERT_UNKNOWN( parameter[i_result] == result ); + break; + + case tan_graph_op: + result = CppAD::tan( parameter[ arg[0] ] ); + i_result = rec.put_con_par(result); + CPPAD_ASSERT_UNKNOWN( parameter[i_result] == result ); + break; + + default: + CPPAD_ASSERT_UNKNOWN( false ); + break; + } + } + // ------------------------------------------------------------------- + // binary operators + // ------------------------------------------------------------------- + else + { CPPAD_ASSERT_UNKNOWN( n_arg == 2 && n_result == 1 ); + Base result; // used in cases where both arguments are constants + if( type_x[0] == variable_enum && type_x[1] == variable_enum ) + switch( op_enum ) + { + case add_graph_op: + i_result = rec.PutOp(local::AddvvOp); + rec.PutArg( arg[0], arg[1] ); + CPPAD_ASSERT_UNKNOWN( NumArg(local::AddvvOp) == 2 ); + break; + + case azmul_graph_op: + i_result = rec.PutOp(local::ZmulvvOp); + rec.PutArg( arg[0], arg[1] ); + CPPAD_ASSERT_UNKNOWN( NumArg(local::ZmulvvOp) == 2 ); + break; + + case div_graph_op: + i_result = rec.PutOp(local::DivvvOp); + rec.PutArg( arg[0], arg[1] ); + CPPAD_ASSERT_UNKNOWN( NumArg(local::DivvvOp) == 2 ); + break; + + case mul_graph_op: + i_result = rec.PutOp(local::MulvvOp); + rec.PutArg( arg[0], arg[1] ); + CPPAD_ASSERT_UNKNOWN( NumArg(local::MulvvOp) == 2 ); + break; + + case pow_graph_op: + i_result = rec.PutOp(local::PowvvOp); + rec.PutArg( arg[0], arg[1] ); + CPPAD_ASSERT_UNKNOWN( NumArg(local::PowvvOp) == 2 ); + break; + + case sub_graph_op: + i_result = rec.PutOp(local::SubvvOp); + rec.PutArg( arg[0], arg[1] ); + CPPAD_ASSERT_UNKNOWN( NumArg(local::SubvvOp) == 2 ); + break; + + default: + CPPAD_ASSERT_UNKNOWN( false ); + break; + } + else if( type_x[0] == variable_enum ) switch( op_enum ) + { + // addition is communitative, so use Addpv + case add_graph_op: + i_result = rec.PutOp(local::AddpvOp); + rec.PutArg( arg[1], arg[0] ); + CPPAD_ASSERT_UNKNOWN( NumArg(local::AddpvOp) == 2 ); + break; + + case azmul_graph_op: + i_result = rec.PutOp(local::ZmulvpOp); + rec.PutArg( arg[0], arg[1] ); + CPPAD_ASSERT_UNKNOWN( NumArg(local::ZmulvpOp) == 2 ); + break; + + case div_graph_op: + i_result = rec.PutOp(local::DivvpOp); + rec.PutArg( arg[0], arg[1] ); + CPPAD_ASSERT_UNKNOWN( NumArg(local::DivvpOp) == 2 ); + break; + + // multiplication is communitative, so use Mulpv + case mul_graph_op: + i_result = rec.PutOp(local::MulpvOp); + rec.PutArg( arg[1], arg[0] ); + CPPAD_ASSERT_UNKNOWN( NumArg(local::MulpvOp) == 2 ); + break; + + case pow_graph_op: + i_result = rec.PutOp(local::PowvpOp); + rec.PutArg( arg[0], arg[1] ); + CPPAD_ASSERT_UNKNOWN( NumArg(local::PowvpOp) == 2 ); + break; + + case sub_graph_op: + i_result = rec.PutOp(local::SubvpOp); + rec.PutArg( arg[0], arg[1] ); + CPPAD_ASSERT_UNKNOWN( NumArg(local::SubvpOp) == 2 ); + break; + + default: + CPPAD_ASSERT_UNKNOWN( false ); + break; + } + else if( type_x[1] == variable_enum ) switch( op_enum ) + { + case add_graph_op: + i_result = rec.PutOp(local::AddpvOp); + rec.PutArg( arg[0], arg[1] ); + CPPAD_ASSERT_UNKNOWN( NumArg(local::AddpvOp) == 2 ); + break; + + case azmul_graph_op: + i_result = rec.PutOp(local::ZmulpvOp); + rec.PutArg( arg[0], arg[1] ); + CPPAD_ASSERT_UNKNOWN( NumArg(local::ZmulpvOp) == 2 ); + break; + + case div_graph_op: + i_result = rec.PutOp(local::DivpvOp); + rec.PutArg( arg[0], arg[1] ); + CPPAD_ASSERT_UNKNOWN( NumArg(local::DivpvOp) == 2 ); + break; + + case mul_graph_op: + i_result = rec.PutOp(local::MulpvOp); + rec.PutArg( arg[0], arg[1] ); + CPPAD_ASSERT_UNKNOWN( NumArg(local::MulpvOp) == 2 ); + break; + + case pow_graph_op: + i_result = rec.PutOp(local::PowpvOp); + rec.PutArg( arg[0], arg[1] ); + CPPAD_ASSERT_UNKNOWN( NumArg(local::PowpvOp) == 2 ); + break; + + case sub_graph_op: + i_result = rec.PutOp(local::SubpvOp); + rec.PutArg( arg[0], arg[1] ); + CPPAD_ASSERT_UNKNOWN( NumArg(local::SubpvOp) == 2 ); + break; + + default: + CPPAD_ASSERT_UNKNOWN( false ); + break; + } + else if( type_x[0] == dynamic_enum || type_x[1] == dynamic_enum ) + switch( op_enum ) + { + case add_graph_op: + i_result = + rec.put_dyn_par(nan, local::add_dyn, arg[0], arg[1]); + CPPAD_ASSERT_UNKNOWN( isnan( parameter[i_result] ) ); + break; + + case azmul_graph_op: + i_result = + rec.put_dyn_par(nan, local::zmul_dyn, arg[0], arg[1]); + CPPAD_ASSERT_UNKNOWN( isnan( parameter[i_result] ) ); + break; + + case div_graph_op: + i_result = + rec.put_dyn_par(nan, local::div_dyn, arg[0], arg[1]); + CPPAD_ASSERT_UNKNOWN( isnan( parameter[i_result] ) ); + break; + + case mul_graph_op: + i_result = + rec.put_dyn_par(nan, local::mul_dyn, arg[0], arg[1]); + break; + + case pow_graph_op: + i_result = + rec.put_dyn_par(nan, local::pow_dyn, arg[0], arg[1]); + CPPAD_ASSERT_UNKNOWN( isnan( parameter[i_result] ) ); + break; + + case sub_graph_op: + i_result = + rec.put_dyn_par(nan, local::sub_dyn, arg[0], arg[1]); + CPPAD_ASSERT_UNKNOWN( isnan( parameter[i_result] ) ); + break; + + default: + CPPAD_ASSERT_UNKNOWN( false ); + break; + } + else switch( op_enum ) + { + case add_graph_op: + result = parameter[ arg[0] ] + parameter[ arg[1] ]; + i_result = rec.put_con_par(result); + CPPAD_ASSERT_UNKNOWN( parameter[i_result] == result ); + break; + + case azmul_graph_op: + result = azmul( parameter[ arg[0] ] , parameter[ arg[1] ] ); + i_result = rec.put_con_par(result); + CPPAD_ASSERT_UNKNOWN( parameter[i_result] == result ); + break; + + case div_graph_op: + result = parameter[ arg[0] ] / parameter[ arg[1] ]; + i_result = rec.put_con_par(result); + CPPAD_ASSERT_UNKNOWN( parameter[i_result] == result ); + break; + + case mul_graph_op: + result = parameter[ arg[0] ] * parameter[ arg[1] ]; + i_result = rec.put_con_par(result); + CPPAD_ASSERT_UNKNOWN( parameter[i_result] == result ); + break; + + case pow_graph_op: + result = pow( parameter[ arg[0] ], parameter[ arg[1] ] ); + i_result = rec.put_con_par(result); + CPPAD_ASSERT_UNKNOWN( parameter[i_result] == result ); + break; + + case sub_graph_op: + result = parameter[ arg[0] ] - parameter[ arg[1] ]; + i_result = rec.put_con_par(result); + CPPAD_ASSERT_UNKNOWN( parameter[i_result] == result ); + break; + + default: + CPPAD_ASSERT_UNKNOWN( false ); + break; + + } + } + // case where node_type and node2fun for the results are set above + if( op_enum != atom_graph_op && n_result != 0 ) + { // set node_type and node2fun for result + // + CPPAD_ASSERT_UNKNOWN( i_result != 0 ); + CPPAD_ASSERT_UNKNOWN( n_result == 1 ); + if( n_var_arg > 0 ) + node_type.push_back(variable_enum); + else if( n_dyn_arg > 0 ) + node_type.push_back(dynamic_enum); + else + node_type.push_back(constant_enum); + node2fun.push_back(i_result); + } + // + start_result += n_result; + CPPAD_ASSERT_UNKNOWN( node2fun.size() == start_result ); + CPPAD_ASSERT_UNKNOWN( node_type.size() == start_result ); + } + // set this->dep_parameter_, set this->dep_taddr_ + // + CPPAD_ASSERT_NARG_NRES(local::ParOp, 1, 1); + dep_parameter_.resize( n_dependent ); + dep_taddr_.resize( n_dependent ); + for(size_t i = 0; i < n_dependent; ++i) + { + CPPAD_ASSERT_UNKNOWN( + node_type[ graph_obj.dependent_vec_get(i) ] != number_ad_type_enum + ); + if( node_type[ graph_obj.dependent_vec_get(i) ] == variable_enum ) + { dep_parameter_[i] = false; + dep_taddr_[i] = size_t( node2fun[ graph_obj.dependent_vec_get(i) ] ); + } + else + { dep_parameter_[i] = true; + dep_taddr_[i] = size_t( rec.PutOp(local::ParOp) ); + rec.PutArg( node2fun[ graph_obj.dependent_vec_get(i) ] ); + } + } + rec.PutOp(local::EndOp); + // ---------------------------------------------------------------------- + // End recording, set private member data except for + // dep__parameter_ and dep_taddr_ + // ---------------------------------------------------------------------- + // + // bool values in this object except check_for_nan_ + has_been_optimized_ = false; + // + // size_t values in this object + compare_change_count_ = 1; + compare_change_number_ = 0; + compare_change_op_index_ = 0; + num_order_taylor_ = 0; + cap_order_taylor_ = 0; + num_direction_taylor_ = 0; + num_var_tape_ = rec.num_var_rec(); + // + // taylor_ + taylor_.resize(0); + // + // cskip_op_ + cskip_op_.resize( rec.num_op_rec() ); + // + // load_op2var_ + load_op2var_.resize( rec.num_var_load_rec() ); + // + // play_ + // Now that each dependent variable has a place in the recording, + // and there is a EndOp at the end of the record, we can transfer the + // recording to the player and and erase the recording. + play_.get_recording(rec, n_variable_ind_fun); + // + // ind_taddr_ + // Note that play_ has been set, we can use it to check operators + ind_taddr_.resize(n_variable_ind_fun); + CPPAD_ASSERT_UNKNOWN( n_variable_ind_fun < num_var_tape_); + for(size_t j = 0; j < n_variable_ind_fun; j++) + { CPPAD_ASSERT_UNKNOWN( play_.GetOp(j+1) == local::InvOp ); + ind_taddr_[j] = j+1; + } + // + // for_jac_sparse_pack_, for_jac_sparse_set_ + for_jac_sparse_pack_.resize(0, 0); + for_jac_sparse_set_.resize(0,0); + // + // resize subgraph_info_ + subgraph_info_.resize( + ind_taddr_.size(), // n_dep + dep_taddr_.size(), // n_ind + play_.num_op_rec(), // n_op + play_.num_var_rec() // n_var + ); + // + // set the function name + function_name_ = function_name; + // + return; +} +// BEGIN_ONE_ARGUMENT +template +void CppAD::ADFun::from_graph( + const CppAD::cpp_graph& graph_obj ) +// END_ONE_ARGUMENT +{ size_t n_variable_ind = graph_obj.n_variable_ind_get(); + size_t n_dynamic_ind = graph_obj.n_dynamic_ind_get(); + CppAD::vector dyn2var(n_dynamic_ind), var2dyn(n_variable_ind); + for(size_t j = 0; j < n_dynamic_ind; ++j) + dyn2var[j] = false; + for(size_t j = 0; j < n_variable_ind; ++j) + var2dyn[j] = false; + // + from_graph(graph_obj, dyn2var, var2dyn); +} + +} // END_CPPAD_NAMESPACE + +# endif diff --git a/build-config/cppad/include/cppad/core/graph/from_json.hpp b/build-config/cppad/include/cppad/core/graph/from_json.hpp new file mode 100644 index 00000000..eca0676f --- /dev/null +++ b/build-config/cppad/include/cppad/core/graph/from_json.hpp @@ -0,0 +1,76 @@ +# ifndef CPPAD_CORE_GRAPH_FROM_JSON_HPP +# define CPPAD_CORE_GRAPH_FROM_JSON_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +# include +# include +# include + +/* +$begin from_json$$ +$spell + Json +$$ + +$section ADFun Object Corresponding to a Json AD Graph$$ + +$head Syntax$$ +$codei% + ADFun<%Base%> %fun% + %fun%.from_json(%json%) +%$$ + +$head Prototype$$ +$srcthisfile% + 0%// BEGIN_PROTOTYPE%// END_PROTOTYPE%1 +%$$ + +$head json$$ +is a $cref json_ad_graph$$. + +$head Base$$ +is the type corresponding to this $cref/ADFun/adfun/$$ object; +i.e., its calculations are done using the type $icode Base$$. + +$head RecBase$$ +in the prototype above, $icode RecBase$$ is the same type as $icode Base$$. + +$children% + example/json/from_json.cpp +%$$ +$head Example$$ +The file $cref from_json.cpp$$ is an example and test of this operation. + +$end +*/ +// BEGIN_PROTOTYPE +template +void CppAD::ADFun::from_json(const std::string& json) +// END_PROTOTYPE +{ + using CppAD::isnan; + // + // + // C++ graph object + cpp_graph graph_obj; + // + // convert json to graph representation + local::graph::json_parser(json, graph_obj); + // + // convert the graph representation to a function + from_graph(graph_obj); + // + return; +} + +# endif diff --git a/build-config/cppad/include/cppad/core/graph/graph_op_enum.hpp b/build-config/cppad/include/cppad/core/graph/graph_op_enum.hpp new file mode 100644 index 00000000..84eb8661 --- /dev/null +++ b/build-config/cppad/include/cppad/core/graph/graph_op_enum.hpp @@ -0,0 +1,238 @@ +# ifndef CPPAD_CORE_GRAPH_GRAPH_OP_ENUM_HPP +# define CPPAD_CORE_GRAPH_GRAPH_OP_ENUM_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell + + CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + + This Source Code may also be made available under the following + Secondary License when the conditions for such availability set forth + in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +-------------------------------------------------------------------------- */ + +# include +# include +# include + +# include +# include + +/* +$begin graph_op_enum$$ +$spell + Cond + asinh + acosh + atanh + erf + erfc + expm + vec + enum + Exp + Gt + Le + notpos +$$ + +$section C++ AD Graph Operator Enum Type$$ + +$head Unary$$ +The unary operators have one argument and one result node. +The argument is a node index and the result is the next node. + +$subhead Require C++11$$ +The following unary operators require a compiler that supports c++11: +$code asinh$$, $code acosh$$, $code atanh$$, +$code erf$$, $code erfc$$, +$code expm1$$, $code log1p$$. + +$head Binary$$ +The binary operators have two arguments and one result node. +The arguments are node indices and the result is the next node. +The first (second) argument is the left (right) operand node index. + +$head Conditional Expression$$ +The conditional expression operators have four arguments and one result node. +The arguments are node indices and the result is the next node. +The first argument is $cref/left/CondExp/left/$$, +the second is $cref/right/CondExp/right/$$, +the third is $cref/if_true/CondExp/if_true/$$, +the fourth is $cref/if_false/CondExp/if_false/$$, +the result is given by +$codei% + if( %left% %cop% %right%) + %result% = %if_true%; + else + %result% = %if_false%; +%$$ +where $icode cop$$ is given in the comment after the enum type values below. + +$subhead Other Comparisons$$ +Note that +$codei% + CondExpGt(%left%, %right%, %if_true%, %if_false%) +%$$ +is equivalent to +$codei% + CondExpLe(%left%, %right%, %if_false%, %if_true%) +%$$ +Similar conversions can be used for all the possible +$cref/conditional expressions/CondExp/$$. + +$head Comparison$$ +The comparison operators have two arguments and no result node. +The first (second) argument is the left (right) operand node index. +The comparison result was true for the value of the independent +dynamic parameters and independent variables at which this graph was created. + +$subhead Other Comparisons$$ +The comparison result true for $icode%left% > %right%$$ +is equivalent to the comparison result true for $icode%right% < %left%$$. +The comparison result false for $icode%left% > %right%$$ +is equivalent to the comparison result true for $icode%left% <= %right%$$. +In a similar fashion, all the possible comparisons results +can be converted to a true result for one of the comparisons above. + +$head Summation$$ +The summation operator has one node result and a variable +number of arguments. +The first argument is the number of nodes in the summation, +and the other arguments are the indices of the nodes to be summed. +The total number of arguments for this operator +is one plus the number of nodes in the summation. + +$head Discrete Function$$ +The discrete function operator has two arguments and one node result. +The first argument is the index in +$cref/discrete_name_vec/cpp_ad_graph/discrete_name_vec/$$ for the +$cref/name/discrete/name/$$ of the discrete function that is called. +The second argument is the index of the node that is the argument +to the discrete function. + +$head Atomic Function$$ +The atomic function operator has a variable number of arguments +and a variable number of node results. +The total number of arguments for this operator is three plus the number +of arguments for the function being called. +$list number$$ +The first argument is the index in +$cref/atomic_name_vec/cpp_ad_graph/atomic_name_vec/$$ for the +$cref/name/atomic_three_ctor/atomic_three/name/$$ +of the $code atomic_three$$ function that is called. +$lnext +The second argument is the number of result for this function call. +The order of the results is determined by function being called. +$lnext +The third argument is the number of arguments +for this function call. +$lnext +The other arguments are the indices of nodes for each argument to the +function call. The order of the arguments is determined by function +being called. +$lend + +$head Print$$ +The print operator has four arguments. +$list number$$ +The first argument is the index in +$cref/print_text_vec/cpp_ad_graph/print_text_vec/$$ for the +$cref/before/PrintFor/before/$$ text for this print operator. +$lnext +The second argument is the index in +$cref/print_text_vec/cpp_ad_graph/print_text_vec/$$ for the +$cref/after/PrintFor/after/$$ text for this print operator. +$lnext +The third argument is the node corresponding to +$cref/notpos/PrintFor/notpos/$$ for this print operator. +$lnext +The fourth argument is the node corresponding to +$cref/value/PrintFor/value/$$ for this print operator. +$lend + + +$head Missing Operators$$ +As of yet the following $cref ADFun$$ operators do not have a corresponding +graph operator: +$list number$$ +Operators to load and store $cref VecAD$$ elements. +$lnext +An operator for the $cref atomic_two$$ interface. +$lend + + +$head Enum Values$$ +$srcthisfile% + 0%// BEGIN_SORT_THIS_LINE_PLUS_2%// END_SORT_THIS_LINE_MINUS_3%1 +%$$ + +$head Examples$$ + +$childtable% + example/graph/azmul_op.cpp% + example/graph/add_op.cpp% + example/graph/div_op.cpp% + example/graph/mul_op.cpp% + example/graph/pow_op.cpp% + example/graph/sub_op.cpp% + example/graph/unary_op.cpp% + example/graph/sum_op.cpp% + example/graph/comp_op.cpp% + example/graph/cexp_op.cpp% + example/graph/discrete_op.cpp% + example/graph/atom_op.cpp% + example/graph/print_op.cpp +%$$ + +$end +*/ +// BEGIN_SORT_THIS_LINE_PLUS_2 +namespace CppAD { namespace graph { + enum graph_op_enum { + abs_graph_op, // unary: absolute value + acos_graph_op, // unary: inverse cosine + acosh_graph_op, // unary: inverse hyperbolic cosine + add_graph_op, // binary: addition + asin_graph_op, // unary: inverse sine + asinh_graph_op, // unary: inverse hyperbolic sine + atan_graph_op, // unary: inverse tangent + atanh_graph_op, // unary: inverse hyperbolic tangent + atom_graph_op, // atomic function + azmul_graph_op, // binary: absolute zero multiplication + cexp_eq_graph_op, // conditional expression: == + cexp_le_graph_op, // conditional expression: <= + cexp_lt_graph_op, // conditional expression: < + comp_eq_graph_op, // comparison: == + comp_le_graph_op, // comparison: <= + comp_lt_graph_op, // comparison: < + comp_ne_graph_op, // comparison: != + cos_graph_op, // unary: cosine + cosh_graph_op, // unary: hyperbolic cosine + discrete_graph_op, // discrete function + div_graph_op, // binary: division + erf_graph_op, // unary: error function + erfc_graph_op, // unary: complementary error function + exp_graph_op, // unary: exponential + expm1_graph_op, // unary: exponential minus one + log1p_graph_op, // unary: logarithm of one plus argument + log_graph_op, // unary: logarithm + mul_graph_op, // binary: multiplication + pow_graph_op, // binary: first argument raised to second argument + print_graph_op, // print during zero order forward + sign_graph_op, // unary: sign of argument + sin_graph_op, // unary: sine + sinh_graph_op, // unary: hyperbolic sine + sqrt_graph_op, // unary: square root + sub_graph_op, // binary: subtraction + sum_graph_op, // summation + tan_graph_op, // unary: tangent + tanh_graph_op, // unary: hyperbolic tangent + n_graph_op // number of graph_op_enum operators + }; +} } +// END_SORT_THIS_LINE_MINUS_3 + + +# endif diff --git a/build-config/cppad/include/cppad/core/graph/json_ad_graph.omh b/build-config/cppad/include/cppad/core/graph/json_ad_graph.omh new file mode 100644 index 00000000..a727f82b --- /dev/null +++ b/build-config/cppad/include/cppad/core/graph/json_ad_graph.omh @@ -0,0 +1,330 @@ +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell + + CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + + This Source Code may also be made available under the following + Secondary License when the conditions for such availability set forth + in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +-------------------------------------------------------------------------- */ +$begin json_ad_graph$$ +$spell + Json + vec + enum_op + arg + ind + acyclic + str + np nx nc +$$ + +$section Json Representation of an AD Graph$$ + +$head See Also$$ +$tref cpp_ad_graph$$. + +$head Node Indices$$ +The nodes in an AD graph have the following order: +$pre + p_0 , ... , p_{np-1} , + x_0 , ... , x_{nx-1} , + c_0 , ... , c_{nc-1} , + r_0 , ... , r_{no-1} +$$ + +$subhead p$$ +The sub-vector +$pre p_0, ... , p_{np-1}$$ is the independent dynamic parameter vector; +see $cref/n_dynamic_ind/json_ad_graph/dynamic_ind_vec/n_dynamic_ind/$$. +The node index corresponding to $icode p_0$$ is $code 1$$. + +$subhead x$$ +The sub-vector +$pre x_0, ... , x_{nx-1}$$ is the independent variable vector; +see $cref/n_variable_ind/json_ad_graph/variable_ind_vec/n_variable_ind/$$. +The node index corresponding to $icode x_0$$ is +the index corresponding to $icode p_0$$ plus $icode np$$. + +$subhead c$$ +The sub-vector +$pre c_0, ... , c_{nc-1}$$ is the constant parameter vector; +see $cref/constant_vec/json_ad_graph/constant_vec/$$. +The node index corresponding to $icode c_0$$ is +the index corresponding to $icode x_0$$ plus $icode nx$$. + +$subhead r_i$$ +For $icode%i%=0,%...%,%no%-1%$$ +the sub-vector $pre r_i$$ +is the result vector for the $th i$$ operator usage; +see $cref/op_usage_vec/json_ad_graph/op_usage_vec/$$. +The value $icode no$$ is the number of operator usages; see +$cref/n_usage/json_ad_graph/op_usage_vec/n_usage/$$ below. +All of the arguments for an the $th i$$ operator are nodes +that come before the first element of $icode r_i$$. +The node index corresponding to the first element of $icode r_0$$ is +the index corresponding to $icode c_0$$ plus $icode nc$$. +For $icode%i% > 0%$$, +The node index corresponding to the first element of $icode r_i$$ is +the index corresponding to the first element of $icode r_{i-1}$$ plus +the number of results for the $th i-1$$ operator. + +$head Format$$ +A complete description of the format for an AD graph is given below. +For a general description of Json format see +$href% + https://en.wikipedia.org/wiki/JSON#Data_types_and_syntax% + Json data types and syntax +%$$. + +$head Token$$ + +$subhead White Space$$ +Any sequence of white space, except within a string, +terminates the current token and is otherwise ignored. + +$subhead Non-Negative Integer$$ +A non-negative integer is a non-empty sequence of the following +characters: $code 0123456789$$. + +$subhead Floating Point Number$$ +A floating point number is a non-empty sequence of the following +characters: $code 0123456789+-eE.$$. +Note that there can't be any white space between a leading plus +or minus sign and the rest of the number. + +$subhead String$$ +A string starts with the double quote character $code "$$ +and includes all the characters until the next double quote. +The value of a string is the sequence of characters between the +double quotes. +Currently there is no support using the double quote +as part of the value of a string. + +$subhead Single Character$$ +The following is a list of the single character tokens: +$table +Token $cnext Usage $rnext +$code ,$$ $cnext separates entries in a list $rnext +$code :$$ $cnext separates name from corresponding value $rnext +$code {$$ $cnext starts a list of name $code :$$ value pairs $rnext +$code }$$ $cnext ends a list of name $code:$$ value pairs $rnext +$code [$$ $cnext starts a list of values $rnext +$code ]$$ $cnext ends a list of values +$tend + +$head op_define_vec$$ +This vector has the following Json format: +$codei% + [ %n_define%, [ %first_op_define%, %...%, %last_op_define% ] ] +%$$ +where the non-negative integer $icode n_define$$ +is the number of operator definitions in this vector. + +$subhead op_define$$ +The possible operator definitions $icode op_define$$ are listed in +section $cref json_graph_op$$. +If an operator has a fixed number of arguments, one result, and +only node indices for arguments, its definition has the form +$codei% +{ + "op_code": %op_code%, + "name": %name%, + "n_arg": %n_arg% +} +%$$ +Otherwise the operator definition has the form +$codei% +{ + "op_code": %op_code%, + "name": %name% +} +%$$ +For example, the following is the $icode op_define$$ corresponding to the +$cref/add/json_graph_op/Binary Operators/add/$$ operator: +$codei% +{ + "op_code": %op_code%, + "name": "add", + "n_arg": 2 +} +%$$ + +$subhead op_code$$ +Note that every operator definition has a $icode op_code$$ value. +These values must start at one and increment by one for each operator +definition; i.e., the $icode op_code$$ for in $icode first_op_define$$ is +$code 1$$, the value in the next definition is $code 2$$, and so on. +The order of the definitions determines the $icode op_code$$ values +used to specify operators for this computational graph. + +$subhead n_arg$$ +This is the number of argument values for the operator; i.e., +the dimension of its domain space. +If it is present in an operator definition, +it is the same value for every usage of the operator. +Otherwise it is specified by the operator usage. + +$subhead n_result$$ +This is the number of results for the operator; i.e., +the dimension of its range space. +If $icode n_arg$$ is present in an operator definition, +$icode n_result$$ is one for every usage of the operator. +Otherwise it is specified by the operator usage. + +$head op_usage$$ +Each operation usage +has the following information: + +$subhead n_arg In Definition$$ +If $icode n_arg$$ is present in an operator definition, +it is not in a corresponding $icode op_usage$$ which as the form +$codei% + [ %op_code%, %first_arg%, %...%, %last_arg% ] +%$$ + +$subhead n_arg Not In Definition$$ +If $icode n_arg$$ is not in an operator definition, +it is in a corresponding $icode op_usage$$. +If there are no strings in a corresponding usage, it has the form +$codei% + [ %op_code%, %n_result%, %n_arg%, [ %first_arg%, %...%, %last_arg% ] ] +%$$ + +$subhead Strings In Usage$$ +If $icode n_arg$$ is not in an operator definition, +and there are strings in a corresponding usage, +a corresponding usage has the form +$codei% + [ %op_code%, %first_str%, %...%, %last_str%, %n_result%, %n_arg%, + [ %first_arg%, %...%, %last_arg% ] + ] +%$$ +where $icode first_str$$ ..., $icode last_str$$, +are a fixed number of strings that are part of the corresponding operator. + +$subhead first_arg, ..., last_arg$$ +The values $icode first_arg$$, ..., $icode last_arg$$, +are the node indices corresponding to each of the arguments for this operator. +They must be less than the node index corresponding to the first +result for this operator; see +$cref/r_i/json_ad_graph/Node Indices/r_i/$$ above. +They specify which previous results (results before this operator in the graph) +correspond to each of the arguments to this operator. +As a consequence, there cannot be any cycles in the graph where +the operators are represented by arcs from the argument to the result nodes; +i.e., the graph is acyclic. + +$head dynamic_ind_vec$$ +This is the independent dynamic parameter vector +(called $icode p$$ above); see +$cref/dynamic/Independent/dynamic/$$. +The function can depend on these parameters, +but no derivatives are computed with respect to these parameters. + +$subhead n_dynamic_ind$$ +We use the non-negative integer $icode n_dynamic_ind$$ +for the number of elements in this vector +(called $icode np$$ above). + +$head variable_ind_vec$$ +This is the independent variable vector +(called $icode x$$ above); see +$cref/x/Independent/x/$$. +The function can depend on these variable and +derivatives can be computed with respect to these variables. + +$subhead n_variable_ind$$ +We use the non-negative integer $icode n_variable_ind$$ +for the number of element in this vector +(called $icode nx$$ above). + +$head constant_vec$$ +This is the constant parameter vector (called $icode c$$ above). +These parameters can be used to define the function and cannot change. +The Json format for $icode constant_vec$$ is +$codei% + %n_constant%, [ %first_constant%, %...%, %last_constant% ] +%$$ +Each of the elements of this vector, +e.g., $icode first_constant$$, +is a $cref/floating point number/json_ad_graph/Token/Floating Point Number/$$ +specifying the value for the corresponding node. + +$subhead n_constant$$ +The non-negative integer $icode n_constant$$ +is the number of elements in this vector +(called $icode nc$$ above). + +$head op_usage_vec$$ +The Jason format for an $icode op_usage_vec$$ is +$codei% + [ %n_usage%, [ %first_op_usage%, %...%, %last_op_usage% ] ] +%$$ +Each of the elements of this vector, +e.g. $icode first_op_usage$$, +is an $cref/op_usage/json_ad_graph/op_usage/$$. + +$subhead n_usage$$ +The non-negative integer $icode n_usage$$ +is the number of operator usages (called $icode no$$ above). + +$head dependent_vec$$ +This is the vector of dependent variable node indices. +This identifies which nodes in the graph correspond to dependent variables. +The Json format for $icode dependent_vec$$ is +$codei% + [ %n_dependent%, [ %first_dependent%, %...%, %last_dependent% ] ] +%$$ +Each of the elements of this vector, +e.g. $icode first_dependent$$, +is a $cref/non-negative integer/json_ad_graph/Token/Non-Negative Integer/$$ +corresponding to a node index in the graph. + +$subhead n_dependent$$ +The non-negative integer $icode n_dependent$$ +is the number of elements in this vector. + +$head AD Graph$$ +Each operator corresponds to a set of arcs from its argument nodes +to its result nodes. +The graph is acyclic; see +$cref/ + first_arg, ..., last_arg/ + json_ad_graph/op_usage/ + first_arg, ..., last_arg +/$$. + +$subhead function_name$$ +A $icode function_name$$ is a +$cref/string/json_ad_graph/Token/String/$$ that is used to identify +the function. + +$subhead function$$ +The Json AD graph representation of a function is +$codei% +{ + "function_name": %function_name%, + "op_define_vec": %op_define_vec%, + "n_dynamic_ind": %n_dynamic_ind%, + "n_variable_ind": %n_variable_ind%, + "constant_vec": %constant_vec%, + "op_usage_vec": %op_usage_vec%, + "dependent_vec": %dependent_vec% +} +%$$ +This represents a the $latex y = f(x, p)$$ where +$latex p$$ is the dynamic parameter vector, +$latex x$$ is the independent variable vector, and +$latex y$$ is the dependent variable vector. + +$childtable%include/cppad/core/graph/json_graph_op.omh + %include/cppad/core/graph/from_json.hpp + %include/cppad/core/graph/to_json.hpp + %example/json/get_started.cpp + %example/json/sparse.cpp +%$$ + +$end diff --git a/build-config/cppad/include/cppad/core/graph/json_graph_op.omh b/build-config/cppad/include/cppad/core/graph/json_graph_op.omh new file mode 100644 index 00000000..0a80b46b --- /dev/null +++ b/build-config/cppad/include/cppad/core/graph/json_graph_op.omh @@ -0,0 +1,430 @@ +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 Bradley M. Bell + + CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + + This Source Code may also be made available under the following + Secondary License when the conditions for such availability set forth + in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +-------------------------------------------------------------------------- */ +$begin json_graph_op$$ +$spell + notpos + azmul + cexp_rel + eq + lt + le + Cond + Gt + log1p + expm1 + erfc + erf + atanh + asinh + acosh + acos + asin + atan + cos + exp + sqrt + tanh + Json + arg + op + mul + div + chkpoint + CppAD +$$ + +$section Json AD Graph Operator Definitions$$ + +$head Notation$$ + +$subhead op_code$$ +Each operator definition has a $icode op_code$$ value that +is used to identify it for a particular $icode json_ad_graph$$. + +$subhead Arguments$$ +The values $icode first_arg$$, ... , +$cref/last_arg/json_ad_graph/op_usage/first_arg, ..., last_arg/$$ +are the node indices for arguments to an operator. + +$head Unary Operators$$ +All these operations create one result node and +have the following Json definition: +$codei% +{ + "op_code": %op_code%, + "name": %name%, + "n_arg": 1 +} +%$$ +where $icode name$$ is a $cref/string/json_ad_graph/Token/String/$$. +A corresponding $icode op_usage$$ has the form +$codei% + [ %op_code%, %arg% ] +%$$ +The possible values for the string $icode name$$ are listed +in the table below. +The result is the node value as a function of the +argument value. +If c++11 is yes (no), +then c++11 or higher is required to use the operator with CppAD. + +$table +$icode name$$ $cnext result $cnext c++11 $rnext +$code abs$$ $cnext absolute value $cnext no $rnext +$code acos$$ $cnext inverse cosine $cnext no $rnext +$code asin$$ $cnext inverse sine $cnext no $rnext +$code atan$$ $cnext inverse tangent $cnext no $rnext +$code cosh$$ $cnext hyperbolic cosine $cnext no $rnext +$code cos$$ $cnext cosine $cnext no $rnext +$code exp$$ $cnext exponential $cnext no $rnext +$code log$$ $cnext logarithm $cnext no $rnext +$code sign$$ $cnext sign function $cnext no $rnext +$code sinh$$ $cnext hyperbolic sine $cnext no $rnext +$code sin$$ $cnext sine $cnext no $rnext +$code sqrt$$ $cnext square root $cnext no $rnext +$code tanh$$ $cnext hyperbolic tangent $cnext no $rnext +$code tan$$ $cnext tangent $cnext no $rnext +$code asinh$$ $cnext inverse hyperbolic sine $cnext yes $rnext +$code atanh$$ $cnext inverse hyperbolic sine $cnext yes $rnext +$code erf$$ $cnext error functions $cnext yes $rnext +$code erfc$$ $cnext complementary error function $cnext yes $rnext +$code expm1$$ $cnext minus one plus the exponential $cnext yes $rnext +$code log1p$$ $cnext log plus one $cnext yes $rnext +$code acosh$$ $cnext inverse hyperbolic cosine $cnext yes +$tend + +$subhead Example$$ +The file $cref json_unary_op.cpp$$ is an example and test +for one of these operators. + +$head Binary Operators$$ +All these operations create one result node and +have the following Json definition: +$codei% +{ + "op_code": %op_code%, + "name": %name%, + "n_arg": 2 +} +%$$ +where $icode name$$ is a $cref/string/json_ad_graph/Token/String/$$. +A corresponding $icode op_usage$$ has the form +$codei% + [ %op_code%, %first_arg%, %second_arg% ] +%$$ +The possible values for the string $icode name$$ are listed below: + +$subhead add$$ +The result is +the first argument value plus the second argument value; see +the example and test $cref json_add_op.cpp$$. + +$subhead azmul$$ +If the first argument value is zero, the result is zero +(even if the second argument value is nan). +Otherwise the result is +the first argument value times the second argument value; see +the example and test $cref json_azmul_op.cpp$$. + +$subhead div$$ +The result is +the first argument value divided by the second argument value; see +the example and test $cref json_div_op.cpp$$. + +$subhead mul$$ +The result is +the first argument value times the second argument value; see +the example and test $cref json_mul_op.cpp$$. + +$subhead pow$$ +The result is +the first argument value raised to the second argument value; see +the example and test $cref json_pow_op.cpp$$. + +$subhead sub$$ +The result is +the first argument value minus the second argument value; see +the example and test $cref json_sub_op.cpp$$. + +$head sum$$ +This operator has the following Json definition: +$codei% +{ + "op_code": %op_code%, + "name": "sum" +} +%$$ +A corresponding $icode op_usage$$ has the form +$codei% + [ %op_code%, %n_result%, %n_arg%, [ %first_arg%, %...%, %last_arg% ] ] +%$$ +where $icode n_result$$ is always $code 1$$. +This operation creates one node with value equal to +the sum of values corresponding to all of its argument nodes. + +$subhead Example$$ +The file $cref json_sum_op.cpp$$ is an example and test +of this operation. + +$head Conditional Expressions$$ +These operators are $cref/conditional expressions/CondExp/$$ +and have the following Json definition: +$codei% +{ + "op_code": %op_code%, + "name": "cexp_%rel%, + "n_arg": 4 +} +%$$ +where $icode rel$$ is $code eq$$ (equal), +$code le$$ (less than or equal), or +$code lt$$ (less than). +The first argument is $cref/left/CondExp/left/$$, +the second is $cref/right/CondExp/right/$$, +the third is $cref/if_true/CondExp/if_true/$$, +the fourth is $cref/if_false/CondExp/if_false/$$, +the result is given by +$codei% + if( %left% %cop% %right%) + %result% = %if_true%; + else + %result% = %if_false%; +%$$ +where the comparison $icode cop$$ is define by the cases below: + +$subhead cexp_eq$$ +For this operator $icode cop$$ is $code ==$$ + +$subhead cexp_le$$ +For this operator $icode cop$$ is $code <=$$ + +$subhead cexp_lt$$ +For this operator $icode cop$$ is $code <$$ + +$subhead Other Comparisons$$ +Note that +$codei% + CondExpGt(%left%, %right%, %if_true%, %if_false%) +%$$ +is equivalent to +$codei% + CondExpLe(%left%, %right%, %if_false%, %if_true%) +%$$ +Similar conversions can be used for all the possible +$cref/conditional expressions/CondExp/$$. + +$subhead Example$$ +The file $cref json_cexp_op.cpp$$ is an example and test +for one of these operators. + +$head Compare Operators$$ +These are $cref/comparison/Compare/$$ operators +and have the following Json definition: +$codei% +{ + "op_code": %op_code%, + "name": "comp_%rel%" +} +%$$ +where $icode rel$$ is $code eq$$ (equal), +$code ne$$ (not equal), +$code le$$ (less than or equal), or +$code lt$$ (less than). +A corresponding $icode op_usage$$ has the form +$codei% + [ %op_code%, %n_result%, %n_arg%, [ %left%, %right% ] ] +%$$ + +$subhead n_result$$ +This is always zero because a comparison operator does not create +any new nodes. + +$subhead n_arg$$ +This is always two because a comparison operator has two argument nodes +corresponding to the left and right operands. + +$subhead left, right$$ +The logical comparison is defined as the logical expression +$codei% + %left% %cop% %right% +%$$ +The comparison $icode cop$$ is define by the cases below. +The Json graph corresponds to the comparison being true. +If, for a value of the independent parameters and variables, +the comparison is false, +the Json graph may no longer be valid. +For example, the Json graph may only contain the code for the true case below: +$codei% + if( %left% %cop% %right% ) + { %source code when result is true% } + else + { %source code when result is false% } +%$$ +Including this operator enables CppAD to detect when the graph +may no longer be a valid representation of the intended function. + +$subhead comp_eq$$ +For this operator $icode cop$$ is $code ==$$ + +$subhead comp_le$$ +For this operator $icode cop$$ is $code <=$$ + +$subhead comp_lt$$ +For this operator $icode cop$$ is $code <$$ + +$subhead comp_ne$$ +For this operator $icode cop$$ is $code !=$$ + +$subhead Other Comparisons$$ +The comparison result true for $icode%left% > %right%$$ +is equivalent to the comparison result true for $icode%right% < %left%$$. +The comparison result false for $icode%left% > %right%$$ +is equivalent to the comparison result true for $icode%left% <= %right%$$. +In a similar fashion, all the possible comparisons results +can be converted to a true result for one of the comparisons above. + +$subhead Example$$ +The file $cref json_comp_op.cpp$$ is an example and test +for one of these operators. + +$head Discrete Functions$$ +This operator has the following Json definition: +$codei% +{ + "op_code": %op_code%, + "name": "discrete" +} +%$$ +A corresponding op_usage has the form +$codei% + [ %op_code%, %name%, %n_result%, %n_arg%, [ %arg% ] ] +%$$ + +$subhead name$$ +The value $icode name$$ is a +$cref/string/json_ad_graph/Token/String/$$ specifying the +$cref/name/discrete/name/$$ of the discrete function that is called. + +$subhead n_result$$ +This is always $code 1$$ because a discrete function +creates one new node. +The result node value is the specified discrete function of the argument value. + +$subhead n_arg$$ +This is always $code 1$$ because a discrete function has +one argument node. + +$subhead arg$$ +is the node index for the argument to the discrete function. + +$subhead Example$$ +the example and test $cref json_discrete_op.cpp$$. + + +$head Atomic Functions$$ +This operator has the following Json definition: +$codei% +{ + "op_code": %op_code%, + "name": "atom" +} +%$$ +A corresponding $icode op_usage$$ has the form +$codei% + [ %op_code%, %name%, %n_result%, %n_arg%, + [ %first_arg%, %...%, %last_arg% ] + ] +%$$ +This operator creates $icode n_result$$ nodes with values equal to +an evaluation of the $code atomic_three$$ function. + +$subhead name$$ +The value $icode name$$ is a +$cref/string/json_ad_graph/Token/String/$$ specifying the +$cref/name/atomic_three_ctor/atomic_three/name/$$ +of the $code atomic_three$$ function that is called. + +$subhead n_result$$ +is the number of results for this function; i.e., +its range space dimension. + +$subhead n_arg$$ +is the number of arguments to this function; i.e., +its domain space dimension. + +$subhead first_arg, ..., last_arg$$ +The values corresponding to the node indices +$icode first_arg$$, ..., $icode last_arg$$ are the +arguments (independent variables) for the atomic function evaluation. +In the case where the atomic function is a $code chkpoint_two$$ function, +the independent dynamic parameters are specified by calling its +$cref/new_dynamic/chkpoint_two/Syntax/new_dynamic/$$ routine. + +$subhead Example$$ +the example and test $cref json_atom_op.cpp$$. + +$head Print$$ +This operator has the following Json definition: +$codei% +{ + "op_code": %op_code%, + "name": "print" +} +%$$ +A corresponding $icode op_usage$$ has the form +$codei% + [ %op_code%, %before%, %after%, %n_result%, %n_arg%, [ %notpos%, %value% ] ] +%$$ + +$subhead before$$ +is a $cref/string/json_ad_graph/Token/String/$$ that is printed +$cref/before/PrintFor/before/$$ the value for this operator. + +$subhead after$$ +is a $cref/string/json_ad_graph/Token/String/$$ that is printed +$cref/after/PrintFor/after/$$ the value for this operator. + +$subhead n_result$$ +This is always zero because a print operator does not create +any new nodes. + +$subhead n_arg$$ +This is always two because a print operator has two argument nodes. + +$subhead notpos$$ +This is $cref/notpos/PrintFor/notpos/$$ +which determines if the value is printed. + +$subhead value$$ +This is the $cref/value/PrintFor/value/$$ that is printed. + +$subhead Example$$ +The file $cref json_print_op.cpp$$ is an example and test +of this operator. + +$childtable% + example/json/unary_op.cpp% + example/json/add_op.cpp% + example/json/azmul_op.cpp% + example/json/discrete_op.cpp% + example/json/div_op.cpp% + example/json/mul_op.cpp% + example/json/pow_op.cpp% + example/json/print_op.cpp% + example/json/sub_op.cpp% + example/json/sum_op.cpp% + example/json/comp_op.cpp% + example/json/cexp_op.cpp% + example/json/atom_op.cpp +%$$ + +$end diff --git a/build-config/cppad/include/cppad/core/graph/to_graph.hpp b/build-config/cppad/include/cppad/core/graph/to_graph.hpp new file mode 100644 index 00000000..02654e51 --- /dev/null +++ b/build-config/cppad/include/cppad/core/graph/to_graph.hpp @@ -0,0 +1,1199 @@ +# ifndef CPPAD_CORE_GRAPH_TO_GRAPH_HPP +# define CPPAD_CORE_GRAPH_TO_GRAPH_HPP + +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-21 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +# include +# include +# include + +/* +------------------------------------------------------------------------------ +$begin to_graph$$ +$spell + Json + cpp + ind + vec + arg + obj + op_enum +$$ + +$section Create a C++ AD Graph Corresponding to an ADFun Object$$ + +$head Syntax$$ +$codei% + ADFun<%Base%> %fun% + %fun%.to_graph(%graph_obj%) +%$$ + +$head Prototype$$ +$srcthisfile% + 0%// BEGIN_PROTOTYPE%// END_PROTOTYPE%1 +%$$ + +$head Base$$ +is the type corresponding to this $cref/ADFun/adfun/$$ object; +i.e., its calculations are done using the type $icode Base$$. + +$head RecBase$$ +in the prototype above, $icode RecBase$$ is the same type as $icode Base$$. + +$head graph_obj$$ +This is a $code cpp_graph$$ object. +The input value of the object does not matter. +Upon return it is a $cref cpp_ad_graph$$ representation of this function. + +$head Restrictions$$ +The $code to_graph$$ routine is not yet implement for some +possible $cref ADFun$$ operators; see +$cref/missing operators/graph_op_enum/Missing Operators/$$. + +$head Examples$$ +See $cref/graph_op_enum examples/graph_op_enum/Examples/$$. + +$end +*/ +// BEGIN_PROTOTYPE +template +void CppAD::ADFun::to_graph( + CppAD::cpp_graph& graph_obj ) +// END_PROTOTYPE +{ using local::pod_vector; + using local::opcode_t; + using namespace CppAD::graph; + // -------------------------------------------------------------------- + if( local::graph::op_name2enum.size() == 0 ) + { CPPAD_ASSERT_KNOWN( ! thread_alloc::in_parallel() , + "call to set_operator_info in parallel mode" + ); + local::graph::set_operator_info(); + } + // +# ifndef NDEBUG +# endif + graph_obj.initialize(); + // + // -------------------------------------------------------------------- + // some constants + // -------------------------------------------------------------------- + // + // output: function_name + graph_obj.function_name_set(function_name_); + // + // dynamic parameter information + const pod_vector& dyn_par_op ( play_.dyn_par_op() ); + const pod_vector& dyn_par_arg( play_.dyn_par_arg() ); + const pod_vector& dyn_ind2par_ind ( play_.dyn_ind2par_ind() ); + const pod_vector& dyn_par_is( play_.dyn_par_is() ); + // + // number of dynamic parameters + const size_t n_dynamic = dyn_ind2par_ind.size(); + // + // output: n_dynamic_ind + size_t n_dynamic_ind = play_.num_dynamic_ind(); + graph_obj.n_dynamic_ind_set(n_dynamic_ind); + // + // number of parameters + const size_t n_parameter = play_.num_par_rec(); + // + // number of constant parameters +# ifndef NDEBUG + const size_t n_constant = n_parameter - n_dynamic - 1; +# endif + // + // output: n_variable_ind + size_t n_variable_ind = ind_taddr_.size(); + graph_obj.n_variable_ind_set(n_variable_ind); + // + // value of parameters + const Base* parameter = play_.GetPar(); + // + // number of variables + const size_t n_variable = play_.num_var_rec(); + // + // some checks + CPPAD_ASSERT_UNKNOWN( n_dynamic_ind <= n_dynamic ); + CPPAD_ASSERT_UNKNOWN( dyn_par_is.size() == n_parameter ); + CPPAD_ASSERT_UNKNOWN( n_parameter > 0 ); + CPPAD_ASSERT_UNKNOWN( isnan( parameter[0] ) ); + CPPAD_ASSERT_UNKNOWN( ! dyn_par_is[0] ); + // -------------------------------------------------------------------- + // par2node + pod_vector par2node(n_parameter); + par2node[0] = 0; // invalid value + for(size_t i = 1; i <= n_dynamic_ind; ++i) + par2node[i] = i; // independent dynamic parameters + for(size_t i = n_dynamic_ind + 1; i < n_parameter; ++i) + par2node[i] = 0; // will be set later + // ---------------------------------------------------------------------- + // + // initialize index of previous node in the graph + size_t previous_node = 0; + // + // n_dynamic_ind + previous_node += n_dynamic_ind; + // + // n_variable_ind + previous_node += n_variable_ind; + // -------------------------------------------------------------------- + // + // output: constant_vec + // constant_vec and par2node for constants + for(size_t i = 1; i < n_parameter; ++i) + { if( ! dyn_par_is[i] ) + { // this is a constant node + graph_obj.constant_vec_push_back( parameter[i] ); + par2node[i] = ++previous_node; + } + } + CPPAD_ASSERT_UNKNOWN( n_constant == graph_obj.constant_vec_size() ); + // ---------------------------------------------------------------------- + // output: initialize atomic_name_vec, operator_vec, operator_arg + // temporary used for elements of operator_vec + // + // Json operators are dynamic operators plus variables operators. + // Skip BeginOp, EndOp, and independent variables. + // + // dynamic parameter operations and par2node + // for dynamic parameters that are not constants or independent + CPPAD_ASSERT_UNKNOWN( num_arg_dyn(local::ind_dyn) == 0 ); + CPPAD_ASSERT_UNKNOWN( num_arg_dyn(local::atom_dyn) == 0 ); + size_t i_arg = 0; + pod_vector node_arg; + + for(size_t i_dyn = n_dynamic_ind; i_dyn < n_dynamic; ++i_dyn) + { // operator for this dynamic parameter + local::op_code_dyn dyn_op = local::op_code_dyn( dyn_par_op[i_dyn] ); + // + // parameter index for this dynamic parameter + size_t i_par = size_t( dyn_ind2par_ind[i_dyn] ); + CPPAD_ASSERT_UNKNOWN( par2node[i_par] == 0 ); + par2node[i_par] = ++previous_node; + // + // number of arguments for operators with exception of atom_dyn + size_t n_arg = num_arg_dyn(dyn_op); + if( n_arg > node_arg.size() ) + node_arg.resize(n_arg); + // + // parameter arguments in graph node space (except for atom_dyn) + if( dyn_op != local::atom_dyn ) + { size_t offset_par = num_non_par_arg_dyn(dyn_op); + for(size_t i = offset_par; i < n_arg; ++i) + { node_arg[i] = par2node[ dyn_par_arg[i_arg + i] ]; + CPPAD_ASSERT_UNKNOWN( node_arg[i] > 0 ); + } + } + // + // invalid value + graph_op_enum graph_op = n_graph_op; + switch(dyn_op) + { + // --------------------------------------------------------------- + // unary operators + + case local::abs_dyn: + case local::fabs_dyn: + graph_op = abs_graph_op; + break; + + case local::acosh_dyn: + graph_op = acosh_graph_op; + break; + + case local::asinh_dyn: + graph_op = asinh_graph_op; + break; + + case local::atanh_dyn: + graph_op = atanh_graph_op; + break; + + case local::erf_dyn: + graph_op = erf_graph_op; + break; + + case local::erfc_dyn: + graph_op = erfc_graph_op; + break; + + case local::expm1_dyn: + graph_op = expm1_graph_op; + break; + + case local::log1p_dyn: + graph_op = log1p_graph_op; + break; + + case local::acos_dyn: + graph_op = acos_graph_op; + break; + + case local::asin_dyn: + graph_op = asin_graph_op; + break; + + case local::atan_dyn: + graph_op = atan_graph_op; + break; + + case local::cosh_dyn: + graph_op = cosh_graph_op; + break; + + case local::cos_dyn: + graph_op = cos_graph_op; + break; + + case local::exp_dyn: + graph_op = exp_graph_op; + break; + + case local::log_dyn: + graph_op = log_graph_op; + break; + + case local::sign_dyn: + graph_op = sign_graph_op; + break; + + case local::sinh_dyn: + graph_op = sinh_graph_op; + break; + + case local::sin_dyn: + graph_op = sin_graph_op; + break; + + case local::sqrt_dyn: + graph_op = sqrt_graph_op; + break; + + case local::tanh_dyn: + graph_op = tanh_graph_op; + break; + + case local::tan_dyn: + graph_op = tan_graph_op; + break; + + // --------------------------------------------------------------- + // binary operators + + case local::add_dyn: + graph_op = add_graph_op; + break; + + case local::div_dyn: + graph_op = div_graph_op; + break; + + case local::mul_dyn: + graph_op = mul_graph_op; + break; + + case local::pow_dyn: + graph_op = pow_graph_op; + break; + + case local::sub_dyn: + graph_op = sub_graph_op; + break; + + case local::zmul_dyn: + graph_op = azmul_graph_op; + break; + + // --------------------------------------------------------------- + // graph_op determined later for these cases + case local::atom_dyn: + case local::cond_exp_dyn: + case local::dis_dyn: + case local::result_dyn: + break; + + // --------------------------------------------------------------- + default: + // This error should have been reported above + CPPAD_ASSERT_UNKNOWN( false ); + break; + } + switch( dyn_op ) + { // -------------------------------------------------------------- + case local::result_dyn: + // setting par2node[i_dyn] above is all that is necessary + CPPAD_ASSERT_UNKNOWN( n_arg == 0 ); + break; + + // -------------------------------------------------------------- + case local::dis_dyn: + { + // arg[0]: discrete function index + size_t discrete_index = size_t( dyn_par_arg[i_arg + 0] ); + // get the name for this dicrete function + std::string name = discrete::name( discrete_index ); + // + // set graph index for this discrete function call + size_t name_index = graph_obj.discrete_name_vec_find(name); + if( name_index == graph_obj.discrete_name_vec_size() ) + graph_obj.discrete_name_vec_push_back(name); + // + graph_op = discrete_graph_op; + graph_obj.operator_vec_push_back( graph_op ); + graph_obj.operator_arg_push_back( name_index ); + graph_obj.operator_arg_push_back( node_arg[1] ); + } + break; + + // -------------------------------------------------------------- + case local::atom_dyn: + { + // arg[0]: atomic function index + size_t atom_index = size_t( dyn_par_arg[i_arg + 0] ); + // arg[1]: number of arguments to function + n_arg = size_t( dyn_par_arg[i_arg + 1] ); + // arg[2]: number of results from function + size_t n_result = size_t( dyn_par_arg[i_arg + 2] ); + // + // get the name for this atomic function + std::string name; + { bool set_null = false; + size_t type; + void* ptr; + CppAD::local::atomic_index( + set_null, atom_index, type, &name, ptr + ); + } + // set graph index for this atomic function call + size_t name_index = graph_obj.atomic_name_vec_find(name); + if( name_index == graph_obj.atomic_name_vec_size() ) + graph_obj.atomic_name_vec_push_back(name); + // + // for atom_graph_op: + // name_index, n_result, n_arg come before first_node + graph_obj.operator_arg_push_back(name_index); + graph_obj.operator_arg_push_back(n_result); + graph_obj.operator_arg_push_back(n_arg); + // + graph_op = atom_graph_op; + graph_obj.operator_vec_push_back( graph_op ); + // + for(size_t j = 0; j < n_arg; ++j) + { // arg[4 + j] is j-th argument to the function + size_t node_j = par2node[ dyn_par_arg[i_arg + 4 + j] ]; + CPPAD_ASSERT_UNKNOWN( node_j < i_par ); + graph_obj.operator_arg_push_back( node_j ); + } + } + break; + + // -------------------------------------------------------------- + case local::cond_exp_dyn: + { + CompareOp cop = CompareOp( dyn_par_arg[i_arg + 0] ); + size_t left = node_arg[1]; + size_t right = node_arg[2]; + size_t if_true = node_arg[3]; + size_t if_false = node_arg[4]; + switch( cop ) + { case CompareLt: + graph_op = cexp_lt_graph_op; + break; + + case CompareLe: + graph_op = cexp_le_graph_op; + break; + + case CompareEq: + graph_op = cexp_eq_graph_op; + break; + + case CompareGe: + graph_op = cexp_lt_graph_op; + std::swap(if_true, if_false); + break; + + case CompareGt: + graph_op = cexp_le_graph_op; + std::swap(if_true, if_false); + break; + + case CompareNe: + graph_op = cexp_eq_graph_op; + std::swap(if_true, if_false); + break; + + default: + CPPAD_ASSERT_UNKNOWN(false); + break; + } + graph_obj.operator_vec_push_back( graph_op ); + graph_obj.operator_arg_push_back( left ); + graph_obj.operator_arg_push_back( right ); + graph_obj.operator_arg_push_back( if_true ); + graph_obj.operator_arg_push_back( if_false ); + } + break; + + // -------------------------------------------------------------- + // unary or binary + default: + CPPAD_ASSERT_UNKNOWN((n_arg == 1) | (n_arg == 2)); + // + graph_obj.operator_vec_push_back( graph_op ); + for(size_t i = 0; i < n_arg; ++i) + graph_obj.operator_arg_push_back( node_arg[i] ); + break; + } + i_arg += n_arg; + } + // ---------------------------------------------------------------------- + // variable operators + pod_vector var2node(n_variable); + var2node[0] = 0; // invalide node value + for(size_t i = 1; i <= n_variable_ind; ++i) + var2node[i] = n_dynamic_ind + i; + for(size_t i = n_variable_ind + 1; i < n_variable; ++i) + var2node[i] = 0; // invalid node value + // + local::play::const_sequential_iterator itr = play_.begin(); + local::OpCode var_op; + const addr_t* arg; + size_t i_var; + pod_vector is_var(2); + vector atom_node_arg; + bool in_atomic_call = false; + bool more_operators = true; + while(more_operators) + { // if non-zero, this is a fixed size operator with this many arguments + // and implemented after the switch. In additionk, is_var is set for + // each of the at most 2 arguments. + size_t fixed_n_arg = 0; + + // invalid value + graph_op_enum graph_op = n_graph_op; + + // next op + (++itr).op_info(var_op, arg, i_var); + + + // ------------------------------------------------------------------- + // Cases with fixed number of arguments, one or two arguments, and + // operator is not ignored. + // ------------------------------------------------------------------- + switch( var_op ) + { + // ------------------------------------------------------------- + // unary operators + case local::AbsOp: + fixed_n_arg = 1; + is_var[0] = true; + break; + + case local::AcoshOp: + fixed_n_arg = 1; + is_var[0] = true; + break; + + case local::AsinhOp: + fixed_n_arg = 1; + is_var[0] = true; + break; + + case local::AtanhOp: + fixed_n_arg = 1; + is_var[0] = true; + break; + + case local::ErfOp: + fixed_n_arg = 1; + is_var[0] = true; + break; + + case local::ErfcOp: + fixed_n_arg = 1; + is_var[0] = true; + break; + + case local::Expm1Op: + fixed_n_arg = 1; + is_var[0] = true; + break; + + case local::Log1pOp: + fixed_n_arg = 1; + is_var[0] = true; + break; + + case local::AcosOp: + fixed_n_arg = 1; + is_var[0] = true; + break; + + case local::AsinOp: + fixed_n_arg = 1; + is_var[0] = true; + break; + + case local::AtanOp: + fixed_n_arg = 1; + is_var[0] = true; + break; + + case local::CoshOp: + fixed_n_arg = 1; + is_var[0] = true; + break; + + case local::CosOp: + fixed_n_arg = 1; + is_var[0] = true; + break; + + case local::ExpOp: + fixed_n_arg = 1; + is_var[0] = true; + break; + + case local::LogOp: + fixed_n_arg = 1; + is_var[0] = true; + break; + + case local::SignOp: + fixed_n_arg = 1; + is_var[0] = true; + break; + + case local::SinhOp: + fixed_n_arg = 1; + is_var[0] = true; + break; + + case local::SinOp: + fixed_n_arg = 1; + is_var[0] = true; + break; + + case local::SqrtOp: + fixed_n_arg = 1; + is_var[0] = true; + break; + + case local::TanhOp: + fixed_n_arg = 1; + is_var[0] = true; + break; + + case local::TanOp: + fixed_n_arg = 1; + is_var[0] = true; + break; + + // --------------------------------------------------------------- + // binary operators + // --------------------------------------------------------------- + + // first argument a parameter, second argument a variable + case local::AddpvOp: + case local::DivpvOp: + case local::MulpvOp: + case local::PowpvOp: + case local::SubpvOp: + case local::ZmulpvOp: + fixed_n_arg = 2; + is_var[0] = false; + is_var[1] = true; + break; + + // first argument a variable, second argument a parameter + case local::DivvpOp: + case local::PowvpOp: + case local::SubvpOp: + case local::ZmulvpOp: + fixed_n_arg = 2; + is_var[0] = true; + is_var[1] = false; + break; + + // first argument a variable, second argument a variable + case local::AddvvOp: + case local::DivvvOp: + case local::MulvvOp: + case local::PowvvOp: + case local::SubvvOp: + case local::ZmulvvOp: + fixed_n_arg = 2; + is_var[0] = true; + is_var[1] = true; + break; + + // -------------------------------------------------------------- + default: + break; + } + if( fixed_n_arg > 0 ) + { // Set graph_op + switch( var_op ) + { + // ---------------------------------------------------------- + // unary operators + + case local::AbsOp: + graph_op = abs_graph_op; + break; + + case local::AcoshOp: + graph_op = acosh_graph_op; + break; + + case local::AsinhOp: + graph_op = asinh_graph_op; + break; + + case local::AtanhOp: + graph_op = atanh_graph_op; + break; + + case local::ErfOp: + graph_op = erf_graph_op; + break; + + case local::ErfcOp: + graph_op = erfc_graph_op; + break; + + case local::Expm1Op: + graph_op = expm1_graph_op; + break; + + case local::Log1pOp: + graph_op = log1p_graph_op; + break; + + case local::AcosOp: + graph_op = acos_graph_op; + break; + + case local::AsinOp: + graph_op = asin_graph_op; + break; + + case local::AtanOp: + graph_op = atan_graph_op; + break; + + case local::CoshOp: + graph_op = cosh_graph_op; + break; + + case local::CosOp: + graph_op = cos_graph_op; + break; + + case local::ExpOp: + graph_op = exp_graph_op; + break; + + case local::LogOp: + graph_op = log_graph_op; + break; + + case local::SignOp: + graph_op = sign_graph_op; + break; + + case local::SinhOp: + graph_op = sinh_graph_op; + break; + + case local::SinOp: + graph_op = sin_graph_op; + break; + + case local::SqrtOp: + graph_op = sqrt_graph_op; + break; + + case local::TanhOp: + graph_op = tanh_graph_op; + break; + + case local::TanOp: + graph_op = tan_graph_op; + break; + + // ----------------------------------------------------------- + // binary operators + + case local::AddpvOp: + case local::AddvvOp: + graph_op = add_graph_op; + break; + + case local::DivpvOp: + case local::DivvpOp: + case local::DivvvOp: + graph_op = div_graph_op; + break; + + case local::MulpvOp: + case local::MulvvOp: + graph_op = mul_graph_op; + break; + + case local::PowpvOp: + case local::PowvpOp: + case local::PowvvOp: + graph_op = pow_graph_op; + break; + + case local::SubpvOp: + case local::SubvpOp: + case local::SubvvOp: + graph_op = sub_graph_op; + break; + + case local::ZmulpvOp: + case local::ZmulvpOp: + case local::ZmulvvOp: + graph_op = azmul_graph_op; + break; + + // ----------------------------------------------------------- + default: + // This should be one of the cases above + CPPAD_ASSERT_UNKNOWN(false); + break; + } + // + // var2node and previous_node for this operator + var2node[i_var] = ++previous_node; + // + // + graph_obj.operator_vec_push_back( graph_op ); + for(size_t i = 0; i < fixed_n_arg; ++i) + { if( is_var[i] ) + graph_obj.operator_arg_push_back( var2node[ arg[i] ] ); + else + graph_obj.operator_arg_push_back( par2node[ arg[i] ] ); + } + } + // ------------------------------------------------------------------- + // Other cases + // ------------------------------------------------------------------- + else switch( var_op ) + { + // ------------------------------------------------------------- + // comparison operators + case local::EqppOp: + case local::EqpvOp: + case local::EqvvOp: + case local::NeppOp: + case local::NepvOp: + case local::NevvOp: + case local::LtppOp: + case local::LtpvOp: + case local::LtvpOp: + case local::LtvvOp: + case local::LeppOp: + case local::LepvOp: + case local::LevpOp: + case local::LevvOp: + { // node_0, node_1 + size_t node_0, node_1; + switch( var_op ) + { // both nodes parameters + case local::EqppOp: + case local::NeppOp: + case local::LtppOp: + case local::LeppOp: + node_0 = par2node[arg[0]]; + node_1 = par2node[arg[1]]; + break; + + // first node parameter, second variable + case local::EqpvOp: + case local::NepvOp: + case local::LtpvOp: + case local::LepvOp: + node_0 = par2node[arg[0]]; + node_1 = var2node[arg[1]]; + break; + + // first node variable, second parameter + case local::LtvpOp: + case local::LevpOp: + node_0 = var2node[arg[0]]; + node_1 = par2node[arg[1]]; + break; + + // both nodes variables + case local::EqvvOp: + case local::NevvOp: + case local::LtvvOp: + case local::LevvOp: + node_0 = var2node[arg[0]]; + node_1 = var2node[arg[1]]; + break; + + // should never get here + default: + CPPAD_ASSERT_UNKNOWN(false); + node_0 = 0; // to avoid compiler warning + node_1 = 0; + break; + } + // Set graph_op + switch( var_op ) + { + case local::EqppOp: + case local::EqpvOp: + case local::EqvvOp: + graph_op = comp_eq_graph_op; + break; + + case local::NeppOp: + case local::NepvOp: + case local::NevvOp: + graph_op = comp_ne_graph_op; + break; + + case local::LtppOp: + case local::LtpvOp: + case local::LtvpOp: + case local::LtvvOp: + graph_op = comp_lt_graph_op; + break; + + case local::LeppOp: + case local::LepvOp: + case local::LevpOp: + case local::LevvOp: + graph_op = comp_le_graph_op; + break; + + // should never get here + default: + CPPAD_ASSERT_UNKNOWN(false); + graph_op = n_graph_op; // invalid values + break; + } + graph_obj.operator_vec_push_back( graph_op ); + graph_obj.operator_arg_push_back( node_0 ); + graph_obj.operator_arg_push_back( node_1 ); + } + break; + + // -------------------------------------------------------------- + // CSumOp + case local::CSumOp: + { // does this case have subtraction terms + bool has_subtract = (arg[1] != arg[2]) | (arg[3] != arg[4]); + // + // var2node for this operator + if( has_subtract ) + { // two cumulative sum and one subtract operators + var2node[i_var] = previous_node + 3; + } + else + { // one cumulative sum operator + var2node[i_var] = previous_node + 1; + } + // + // previous_node + 1 = sum corresponding to addition terms + // + graph_op = sum_graph_op; + CPPAD_ASSERT_UNKNOWN( 5 <= arg[1] ); + CPPAD_ASSERT_UNKNOWN( arg[2] <= arg[3] ); + size_t n_arg = size_t(1 + arg[1] - 5 + arg[3] - arg[2]); + // + // n_arg comes befrore first_node + graph_obj.operator_arg_push_back(n_arg); + // + // graph_op for addition terms + graph_obj.operator_vec_push_back( graph_op ); + // + // argument nodes + size_t arg_node = par2node[ arg[0] ]; + graph_obj.operator_arg_push_back( arg_node ); + size_t j_arg = 1; + for(addr_t i = 5; i < arg[1]; ++i) + { arg_node = var2node[ arg[i] ]; + CPPAD_ASSERT_UNKNOWN( arg_node > 0 ); + graph_obj.operator_arg_push_back( arg_node ); + ++j_arg; + } + for(addr_t i = arg[2]; i < arg[3]; ++i) + { arg_node = par2node[ arg[i] ]; + CPPAD_ASSERT_UNKNOWN( arg_node > 0 ); + graph_obj.operator_arg_push_back( arg_node ); + ++j_arg; + } + CPPAD_ASSERT_UNKNOWN( j_arg == n_arg ); + if( has_subtract ) + { // previous_node + 2 = sum corresponding to subtract terms + CPPAD_ASSERT_UNKNOWN( arg[1] <= arg[2] ); + CPPAD_ASSERT_UNKNOWN( arg[3] <= arg[4] ); + n_arg = size_t(arg[2] - arg[1] + arg[4] - arg[3]); + // + // n_arg comes before first_node + graph_obj.operator_arg_push_back(n_arg); + // + // graph_op for subtraction terms + graph_op = sum_graph_op; + graph_obj.operator_vec_push_back( graph_op ); + // + // argument nodes + j_arg = 0; + for(addr_t i = arg[1]; i < arg[2]; ++i) + { arg_node = var2node[ arg[i] ]; + CPPAD_ASSERT_UNKNOWN( arg_node > 0 ); + graph_obj.operator_arg_push_back( arg_node ); + ++j_arg; + } + for(addr_t i = arg[3]; i < arg[4]; ++i) + { arg_node = par2node[ arg[i] ]; + CPPAD_ASSERT_UNKNOWN( arg_node > 0 ); + graph_obj.operator_arg_push_back( arg_node ); + ++j_arg; + } + CPPAD_ASSERT_UNKNOWN( j_arg == n_arg ); + // + // previous_node + 3 = first sum minus second sum + graph_op = sub_graph_op; + graph_obj.operator_vec_push_back( graph_op ); + graph_obj.operator_arg_push_back( previous_node + 1 ); + graph_obj.operator_arg_push_back( previous_node + 2 ); + } + // previous node + if( has_subtract ) + previous_node += 3; + else + previous_node += 1; + } + itr.correct_before_increment(); + break; + + // -------------------------------------------------------------- + case local::DisOp: + { // discrete function index + size_t discrete_index = size_t( arg[0] ); + // name of this discrete function + std::string name = discrete::name( discrete_index ); + // + // set graph index for this discrete function call + size_t name_index = graph_obj.discrete_name_vec_find(name); + if( name_index == graph_obj.discrete_name_vec_size() ) + graph_obj.discrete_name_vec_push_back(name); + // + graph_op = discrete_graph_op; + graph_obj.operator_vec_push_back( graph_op ); + graph_obj.operator_arg_push_back( name_index ); + graph_obj.operator_arg_push_back( var2node[arg[1]] ); + // + var2node[i_var] = ++previous_node; + } + break; + // -------------------------------------------------------------- + case local::PriOp: + { + // before + std::string before( play_.GetTxt( size_t(arg[2]) ) ); + size_t before_index = graph_obj.print_text_vec_find(before); + if( before_index == graph_obj.print_text_vec_size() ) + graph_obj.print_text_vec_push_back(before); + // after + std::string after( play_.GetTxt( size_t(arg[4]) ) ); + size_t after_index = graph_obj.print_text_vec_find(after); + if( after_index == graph_obj.print_text_vec_size() ) + graph_obj.print_text_vec_push_back(after); + // notpos + size_t notpos_node; + if( arg[0] & 1 ) + notpos_node = var2node[ arg[1] ]; + else + notpos_node = par2node[ arg[1] ]; + // value + size_t value_node; + if( arg[0] & 1 ) + value_node = var2node[ arg[3] ]; + else + value_node = par2node[ arg[3] ]; + // + graph_op = print_graph_op; + graph_obj.operator_vec_push_back( graph_op ); + graph_obj.operator_arg_push_back( before_index ); + graph_obj.operator_arg_push_back( after_index ); + graph_obj.operator_arg_push_back( notpos_node ); + graph_obj.operator_arg_push_back( value_node ); + } + break; + + // -------------------------------------------------------------- + case local::FunapOp: + atom_node_arg.push_back( par2node[arg[0]] ); + break; + + case local::FunavOp: + CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) <= i_var ); + atom_node_arg.push_back( var2node[arg[0]] ); + break; + + case local::FunrpOp: + par2node[arg[0]] = ++previous_node; + break; + + case local::FunrvOp: + var2node[i_var] = ++previous_node; + break; + + case local::AFunOp: + in_atomic_call = ! in_atomic_call; + if( in_atomic_call ) + { atom_node_arg.resize(0); + } + else + { // This is the AFunOp at the end of the call + size_t atom_index = size_t( arg[0] ); + size_t n_arg = size_t( arg[2] ); + size_t n_result = size_t( arg[3] ); + CPPAD_ASSERT_UNKNOWN( atom_node_arg.size() == n_arg ); + // + // get the name for this atomic function + std::string name; + { bool set_null = false; + size_t type; + void* ptr; + CppAD::local::atomic_index( + set_null, atom_index, type, &name, ptr + ); + } + // set graph index for this atomic function + size_t name_index = graph_obj.atomic_name_vec_find(name); + if( name_index == graph_obj.atomic_name_vec_size() ) + graph_obj.atomic_name_vec_push_back(name); + // + // for atom_graph_op: + // name_index, n_result, n_arg come before first_node + graph_obj.operator_arg_push_back(name_index); + graph_obj.operator_arg_push_back(n_result); + graph_obj.operator_arg_push_back(n_arg); + // + graph_op = atom_graph_op; + graph_obj.operator_vec_push_back( graph_op ); + for(size_t i = 0; i < n_arg; ++i) + graph_obj.operator_arg_push_back( atom_node_arg[i] ); + } + break; + // -------------------------------------------------------------- + // CExpOp: + case local::CExpOp: + { CompareOp cop = CompareOp( arg[0] ); + size_t left, right, if_true, if_false; + if( arg[1] & 1 ) + left = var2node[ arg[2] ]; + else + left = par2node[ arg[2] ]; + if( arg[1] & 2 ) + right = var2node[ arg[3] ]; + else + right = par2node[ arg[3] ]; + if( arg[1] & 4 ) + if_true = var2node[ arg[4] ]; + else + if_true = par2node[ arg[4] ]; + if( arg[1] & 8 ) + if_false = var2node[ arg[5] ]; + else + if_false = par2node[ arg[5] ]; + switch( cop ) + { case CompareLt: + graph_op = cexp_lt_graph_op; + break; + + case CompareLe: + graph_op = cexp_le_graph_op; + break; + + case CompareEq: + graph_op = cexp_eq_graph_op; + break; + + case CompareGe: + graph_op = cexp_lt_graph_op; + std::swap(if_true, if_false); + break; + + case CompareGt: + graph_op = cexp_le_graph_op; + std::swap(if_true, if_false); + break; + + case CompareNe: + graph_op = cexp_eq_graph_op; + std::swap(if_true, if_false); + break; + + default: + CPPAD_ASSERT_UNKNOWN(false); + break; + } + // var2node and previous_node for this operator + var2node[i_var] = ++previous_node; + // + graph_obj.operator_vec_push_back( graph_op ); + graph_obj.operator_arg_push_back( left ); + graph_obj.operator_arg_push_back( right ); + graph_obj.operator_arg_push_back( if_true ); + graph_obj.operator_arg_push_back( if_false ); + } + break; + + // -------------------------------------------------------------- + // EndOp: + case local::EndOp: + more_operators = false; + break; + + // -------------------------------------------------------------- + // InvOp: independent variables + case local::InvOp: + // no graph operators for independent variables + break; + + // -------------------------------------------------------------- + // ParOp: + case local::ParOp: + // no need for a graph operator, just map variable to parameter + var2node[i_var] = par2node[arg[0]]; + break; + + // -------------------------------------------------------------- + default: + // This error should have been reported above + CPPAD_ASSERT_UNKNOWN(false); + break; + } + } + // ---------------------------------------------------------------------- + // output: dependent_vec + size_t n_dependent = dep_taddr_.size(); + for(size_t i = 0; i < n_dependent; ++i) + graph_obj.dependent_vec_push_back( var2node[ dep_taddr_[i] ] ); + // + return; +} + +# endif diff --git a/build-config/cppad/include/cppad/core/graph/to_json.hpp b/build-config/cppad/include/cppad/core/graph/to_json.hpp new file mode 100644 index 00000000..7ae92e8e --- /dev/null +++ b/build-config/cppad/include/cppad/core/graph/to_json.hpp @@ -0,0 +1,96 @@ +# ifndef CPPAD_CORE_GRAPH_TO_JSON_HPP +# define CPPAD_CORE_GRAPH_TO_JSON_HPP + +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +# include +# include +# include +# include +# include + +/* +------------------------------------------------------------------------------ +$begin to_json$$ +$spell + Json + cpp +$$ + +$section Json AD Graph Corresponding to an ADFun Object$$ + +$head Syntax$$ +$codei% + %json% = %fun%.to_json() +%$$ + +$head Prototype$$ +$srcthisfile% + 0%// BEGIN_PROTOTYPE%// END_PROTOTYPE%1 +%$$ + +$head fun$$ +is the $cref/ADFun/adfun/$$ object. + +$head json$$ +The return value of $icode json$$ is a +$cref json_ad_graph$$ representation of the corresponding function. + +$head Base$$ +is the type corresponding to this $cref/ADFun/adfun/$$ object; +i.e., its calculations are done using the type $icode Base$$. + +$head RecBase$$ +in the prototype above, $icode RecBase$$ is the same type as $icode Base$$. + +$head Restrictions$$ +The $code to_json$$ routine is not yet implement for some +possible $cref ADFun$$ operators; see +$cref/missing operators/graph_op_enum/Missing Operators/$$. + +$children% + example/json/to_json.cpp +%$$ +$head Example$$ +The file $cref to_json.cpp$$ is an example and test of this operation. + +$end +*/ +// BEGIN_PROTOTYPE +template +std::string CppAD::ADFun::to_json(void) +// END_PROTOTYPE +{ using local::pod_vector; + using local::opcode_t; + // -------------------------------------------------------------------- + if( local::graph::op_name2enum.size() == 0 ) + { CPPAD_ASSERT_KNOWN( ! thread_alloc::in_parallel() , + "call to set_operator_info in parallel mode" + ); + local::graph::set_operator_info(); + } + // + // to_graph return values + cpp_graph graph_obj; + // + // graph corresponding to this function + to_graph(graph_obj); + // + // convert to json + std::string json; + local::graph::json_writer(json, graph_obj); + // + return json; +} + +# endif diff --git a/build-config/cppad/include/cppad/core/hash_code.hpp b/build-config/cppad/include/cppad/core/hash_code.hpp new file mode 100644 index 00000000..5b023650 --- /dev/null +++ b/build-config/cppad/include/cppad/core/hash_code.hpp @@ -0,0 +1,70 @@ +# ifndef CPPAD_CORE_HASH_CODE_HPP +# define CPPAD_CORE_HASH_CODE_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-18 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ +/*! +\file core/hash_code.hpp +CppAD hashing utility. +*/ +# include + +namespace CppAD { // BEGIN_CPPAD_NAMESPACE +/*! +General purpose hash code for an arbitrary value. + +\tparam Value +is the type of the argument being hash coded. +It should be a plain old data class; i.e., +the values included in the equality operator in the object and +not pointed to by the object. + +\param value +the value that we are generating a hash code for. +All of the fields in value should have been set before the hash code +is computed (otherwise undefined values are used). + +\return +is a hash code that is between zero and CPPAD_HASH_TABLE_SIZE - 1. + +\par Checked Assertions +\li std::numeric_limits::max() >= CPPAD_HASH_TABLE_SIZE +\li sizeof(value) is even +\li sizeof(unsigned short) == 2 +*/ +template +unsigned short hash_code(const Value& value) +{ return local::local_hash_code(value); } + +/*! +hash code for an AD object. + +\tparam Base +is the base type for this AD value. + +\param u +the AD value that we are generating a hash code for. + +\return +is a hash code that is between zero and CPPAD_HASH_TABLE_SIZE - 1. +*/ +template +unsigned short hash_code(const AD& u) +{ size_t code = hash_code(u.value_); + code += size_t(u.taddr_); + code += size_t(u.ad_type_ == dynamic_enum); + return (unsigned short)(code % CPPAD_HASH_TABLE_SIZE); +} + +} // END_CPPAD_NAMESPACE + + +# endif diff --git a/build-config/cppad/include/cppad/core/hessian.hpp b/build-config/cppad/include/cppad/core/hessian.hpp new file mode 100644 index 00000000..bee11342 --- /dev/null +++ b/build-config/cppad/include/cppad/core/hessian.hpp @@ -0,0 +1,213 @@ +# ifndef CPPAD_CORE_HESSIAN_HPP +# define CPPAD_CORE_HESSIAN_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-18 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +/* +$begin Hessian$$ +$spell + hes + typename + Taylor + HesLuDet + const +$$ + + +$section Hessian: Easy Driver$$ + +$head Syntax$$ +$icode%hes% = %f%.Hessian(%x%, %w%) +%$$ +$icode%hes% = %f%.Hessian(%x%, %l%) +%$$ + + +$head Purpose$$ +We use $latex F : \B{R}^n \rightarrow \B{R}^m$$ to denote the +$cref/AD function/glossary/AD Function/$$ corresponding to $icode f$$. +The syntax above sets $icode hes$$ to the Hessian +The syntax above sets $icode h$$ to the Hessian +$latex \[ + hes = \dpow{2}{x} \sum_{i=1}^m w_i F_i (x) +\] $$ +The routine $cref sparse_hessian$$ may be faster in the case +where the Hessian is sparse. + +$head f$$ +The object $icode f$$ has prototype +$codei% + ADFun<%Base%> %f% +%$$ +Note that the $cref ADFun$$ object $icode f$$ is not $code const$$ +(see $cref/Hessian Uses Forward/Hessian/Hessian Uses Forward/$$ below). + +$head x$$ +The argument $icode x$$ has prototype +$codei% + const %Vector% &%x% +%$$ +(see $cref/Vector/Hessian/Vector/$$ below) +and its size +must be equal to $icode n$$, the dimension of the +$cref/domain/seq_property/Domain/$$ space for $icode f$$. +It specifies +that point at which to evaluate the Hessian. + +$head l$$ +If the argument $icode l$$ is present, it has prototype +$codei% + size_t %l% +%$$ +and is less than $icode m$$, the dimension of the +$cref/range/seq_property/Range/$$ space for $icode f$$. +It specifies the component of $icode F$$ +for which we are evaluating the Hessian. +To be specific, in the case where the argument $icode l$$ is present, +$latex \[ + w_i = \left\{ \begin{array}{ll} + 1 & i = l \\ + 0 & {\rm otherwise} + \end{array} \right. +\] $$ + +$head w$$ +If the argument $icode w$$ is present, it has prototype +$codei% + const %Vector% &%w% +%$$ +and size $latex m$$. +It specifies the value of $latex w_i$$ in the expression +for $icode h$$. + +$head hes$$ +The result $icode hes$$ has prototype +$codei% + %Vector% %hes% +%$$ +(see $cref/Vector/Hessian/Vector/$$ below) +and its size is $latex n * n$$. +For $latex j = 0 , \ldots , n - 1 $$ +and $latex \ell = 0 , \ldots , n - 1$$ +$latex \[ + hes [ j * n + \ell ] = \DD{ w^{\rm T} F }{ x_j }{ x_\ell } ( x ) +\] $$ + +$head Vector$$ +The type $icode Vector$$ must be a $cref SimpleVector$$ class with +$cref/elements of type/SimpleVector/Elements of Specified Type/$$ +$icode Base$$. +The routine $cref CheckSimpleVector$$ will generate an error message +if this is not the case. + +$head Hessian Uses Forward$$ +After each call to $cref Forward$$, +the object $icode f$$ contains the corresponding +$cref/Taylor coefficients/glossary/Taylor Coefficient/$$. +After a call to $code Hessian$$, +the zero order Taylor coefficients correspond to +$icode%f%.Forward(0, %x%)%$$ +and the other coefficients are unspecified. + +$head Example$$ +$children% + example/general/hessian.cpp% + example/general/hes_lagrangian.cpp +%$$ +The routines +$cref hessian.cpp$$ and +$cref hes_lagrangian.cpp$$ +are examples and tests of $code Hessian$$. +They return $code true$$, if they succeed and $code false$$ otherwise. + + +$end +----------------------------------------------------------------------------- +*/ + +// BEGIN CppAD namespace +namespace CppAD { + +template +template +Vector ADFun::Hessian(const Vector &x, size_t l) +{ size_t i, m = Range(); + CPPAD_ASSERT_KNOWN( + l < m, + "Hessian: index i is not less than range dimension for f" + ); + + Vector w(m); + for(i = 0; i < m; i++) + w[i] = Base(0.0); + w[l] = Base(1.0); + + return Hessian(x, w); +} + + +template +template +Vector ADFun::Hessian(const Vector &x, const Vector &w) +{ size_t j; + size_t k; + + size_t n = Domain(); + + // check Vector is Simple Vector class with Base type elements + CheckSimpleVector(); + + CPPAD_ASSERT_KNOWN( + size_t(x.size()) == n, + "Hessian: length of x not equal domain dimension for f" + ); + CPPAD_ASSERT_KNOWN( + size_t(w.size()) == Range(), + "Hessian: length of w not equal range dimension for f" + ); + + // point at which we are evaluating the Hessian + Forward(0, x); + + // define the return value + Vector hes(n * n); + + // direction vector for calls to forward + Vector u(n); + for(j = 0; j < n; j++) + u[j] = Base(0.0); + + + // location for return values from Reverse + Vector ddw(n * 2); + + // loop over forward directions + for(j = 0; j < n; j++) + { // evaluate partials of entire function w.r.t. j-th coordinate + u[j] = Base(1.0); + Forward(1, u); + u[j] = Base(0.0); + + // evaluate derivative of partial corresponding to F_i + ddw = Reverse(2, w); + + // return desired components + for(k = 0; k < n; k++) + hes[k * n + j] = ddw[k * 2 + 1]; + } + + return hes; +} + +} // END CppAD namespace + +# endif diff --git a/build-config/cppad/include/cppad/core/identical.hpp b/build-config/cppad/include/cppad/core/identical.hpp new file mode 100644 index 00000000..70a96fb9 --- /dev/null +++ b/build-config/cppad/include/cppad/core/identical.hpp @@ -0,0 +1,100 @@ +# ifndef CPPAD_CORE_IDENTICAL_HPP +# define CPPAD_CORE_IDENTICAL_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-18 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +# include + +namespace CppAD { // BEGIN_CPPAD_NAMESPACE +/*! +\file identical.hpp +Check if certain properties is true for any possible AD tape play back. +*/ + +// --------------------------------------------------------------------------- +/*! +Determine if an AD object is a parameter, and could never have +a different value during any tape playback. + +An AD object x is identically a parameter if and only if +all of the objects in the following chain are parameters: +\code + x , x.value , x.value.value , ... +\endcode +In such a case, the value of the object will always be the same +no matter what the independent variable values are at any level. + +\param x +values that we are checking for identically a pamameter. + +\return +returns true iff x is identically a parameter. +*/ +template +bool IdenticalCon(const AD &x) +{ return Constant(x) & IdenticalCon(x.value_); } +// Zero ============================================================== +/*! +Determine if an AD is equal to zero, +and must be equal zero during any tape playback. + +\param x +object that we are checking. + +\return +returns true if and only if + x is equals zero and is identically a parameter \ref CppAD::IdenticalCon. +*/ +template +bool IdenticalZero(const AD &x) +{ return Constant(x) & IdenticalZero(x.value_); } +// One ============================================================== +/*! +Determine if an AD is equal to one, +and must be equal one during any tape playback. + +\param x +object that we are checking. + +\return +returns true if and only if + x is equals one and is identically a parameter \ref CppAD::IdenticalCon. +*/ +template +bool IdenticalOne(const AD &x) +{ return Constant(x) & IdenticalOne(x.value_); } +// Equal =================================================================== +/*! +Determine if two AD objects are equal, +and must be equal during any tape playback. + +\param x +first of two objects we are checking for equal. + +\param y +second of two objects we are checking for equal. + +\return +returns true if and only if +the arguments are equal and both identically parameters \ref CppAD::IdenticalCon. +*/ +template +bool IdenticalEqualCon +(const AD &x, const AD &y) +{ bool constant; + constant = Constant(x) & Constant(y); + return constant & IdenticalEqualCon(x.value_, y.value_); +} +// ========================================================================== + +} // END_CPPAD_NAMESPACE +# endif diff --git a/build-config/cppad/include/cppad/core/independent/devel.omh b/build-config/cppad/include/cppad/core/independent/devel.omh new file mode 100644 index 00000000..b6f29ded --- /dev/null +++ b/build-config/cppad/include/cppad/core/independent/devel.omh @@ -0,0 +1,30 @@ +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ +$begin devel_independent$$ +$spell + op + alloc + num + Cpp + bool + const + var + typename +$$ + +$section Developer Documentation for Independent$$ + +$childtable% + include/cppad/core/independent/independent.hpp +%$$ + +$end diff --git a/build-config/cppad/include/cppad/core/independent/independent.hpp b/build-config/cppad/include/cppad/core/independent/independent.hpp new file mode 100644 index 00000000..ee151c5d --- /dev/null +++ b/build-config/cppad/include/cppad/core/independent/independent.hpp @@ -0,0 +1,257 @@ +# ifndef CPPAD_CORE_INDEPENDENT_INDEPENDENT_HPP +# define CPPAD_CORE_INDEPENDENT_INDEPENDENT_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ +# include + +namespace CppAD { // BEGIN_CPPAD_NAMESPACE + +/* +$begin independent_all$$ +$spell + op +$$ + +$section Independent: All Arguments Present$$ + +$head Purpose$$ +This implements $cref Independent$$ with all the possible arguments present. + +$head Syntax$$ +$codei%Independent(%x%, %abort_op_index%, %record_compare%, %dynamic%)%$$ + +$head Prototype$$ +$srcthisfile% + 0%// BEGIN_ALL_ARGUMENT%// END_ALL_ARGUMENT%1 +%$$ + +$head Base$$ +The base type the recording started by this operation. + +$head ADVector$$ +is simple vector type with elements of type $codei%AD<%Base%>%$$. + +$head x$$ +is the vector of the independent variables. + +$head abort_op_index$$ +operator index at which execution will be aborted (during the recording +of operations). The value zero corresponds to not aborting (will not match). + +$head record_compare$$ +should comparison operators be recorded. + +$head dynamic$$ +is the independent dynamic parameter vector. + +$end +*/ +// BEGIN_ALL_ARGUMENT +template +void Independent( + ADVector& x , + size_t abort_op_index , + bool record_compare , + ADVector& dynamic ) +// END_ALL_ARGUMENT +{ CPPAD_ASSERT_KNOWN( + abort_op_index == 0 || record_compare, + "Independent: abort_op_index is non-zero and record_compare is false." + ); + typedef typename ADVector::value_type ADBase; + typedef typename ADBase::value_type Base; + CPPAD_ASSERT_KNOWN( + ADBase::tape_ptr() == nullptr, + "Independent: cannot create a new tape because\n" + "a previous tape is still active (for this thread).\n" + "AD::abort_recording() would abort this previous recording." + ); + local::ADTape* tape = ADBase::tape_manage(new_tape_manage); + tape->Independent(x, abort_op_index, record_compare, dynamic); +} +/* +---------------------------------------------------------------------------- +$begin independent_x_abort_record$$ +$spell + op +$$ + +$section Independent: Default For dynamic$$ + +$head Purpose$$ +This implements $cref Independent$$ using +the default for the dynamic argument. + +$head Syntax$$ +$codei%Independent(%x%, %abort_op_index%, %record_compare%)%$$ + +$head Prototype$$ +$srcthisfile% + 0%// BEGIN_THREE_ARGUMENT%// END_THREE_ARGUMENT%1 +%$$ + +$head Base$$ +The base type the recording started by this operation. + +$head ADVector$$ +is simple vector type with elements of type $codei%AD<%Base%>%$$. + +$head x$$ +is the vector of the independent variables. + +$head abort_op_index$$ +operator index at which execution will be aborted (during the recording +of operations). The value zero corresponds to not aborting (will not match). + +$head record_compare$$ +should comparison operators be recorded. + +$end +*/ +// BEGIN_THREE_ARGUMENT +template +void Independent(ADVector &x, size_t abort_op_index, bool record_compare) +// END_THREE_ARGUMENT +{ ADVector dynamic(0); // empty vector + Independent(x, abort_op_index, record_compare, dynamic); +} +/* +------------------------------------------------------------------------------ +$begin independent_x_abort_op_index$$ +$spell + op +$$ + +$section Independent: Default For record_compare, dynamic$$ + +$head Purpose$$ +This implements $cref Independent$$ using +the default for the record_compare and dynamic arguments. + +$head Syntax$$ +$codei%Independent(%x%, %abort_op_index%)%$$ + +$head Prototype$$ +$srcthisfile% + 0%// BEGIN_X_ABORT_OP_INDEX%// END_X_ABORT_OP_INDEX%1 +%$$ + +$head Base$$ +The base type the recording started by this operation. + +$head ADVector$$ +is simple vector type with elements of type $codei%AD<%Base%>%$$. + +$head x$$ +is the vector of the independent variables. + +$head abort_op_index$$ +operator index at which execution will be aborted (during the recording +of operations). The value zero corresponds to not aborting (will not match). + +$end +*/ +// BEGIN_X_ABORT_OP_INDEX +template +void Independent(ADVector &x, size_t abort_op_index) +// END_X_ABORT_OP_INDEX +{ bool record_compare = true; + ADVector dynamic(0); // empty vector + Independent(x, abort_op_index, record_compare, dynamic); +} +/* +------------------------------------------------------------------------------ +$begin independent_x_dynamic$$ +$spell + op +$$ + +$section Independent: Default For abort_op_index, record_compare$$ + +$head Purpose$$ +This implements $cref Independent$$ using +the default for the abort_op_index and record_compare. + +$head Syntax$$ +$codei%Independent(%x%, %dynamic%)%$$ + +$head Prototype$$ +$srcthisfile% + 0%// BEGIN_X_DYNAMIC%// END_X_DYNAMIC%1 +%$$ + +$head Base$$ +The base type the recording started by this operation. + +$head ADVector$$ +is simple vector type with elements of type $codei%AD<%Base%>%$$. + +$head x$$ +is the vector of the independent variables. + +$head dynamic$$ +is the independent dynamic parameter vector. + +$end +*/ +// BEGIN_X_DYNAMIC +template +void Independent(ADVector& x, ADVector& dynamic) +// END_X_DYNAMIC +{ size_t abort_op_index = 0; + bool record_compare = true; + Independent(x, abort_op_index, record_compare, dynamic); +} +/* +------------------------------------------------------------------------------ +$begin independent_x$$ +$spell + op +$$ + +$section Independent: Default For abort_op_index, record_compare, dynamic$$ + +$head Purpose$$ +This implements $cref Independent$$ using +the default for the abort_op_index, record_compare and dynamic arguments. + +$head Syntax$$ +$codei%Independent(%x%)%$$ + +$head Prototype$$ +$srcthisfile% + 0%// BEGIN_ONE_ARGUMENT%// END_ONE_ARGUMENT%1 +%$$ + +$head Base$$ +The base type the recording started by this operation. + +$head ADVector$$ +is simple vector type with elements of type $codei%AD<%Base%>%$$. + +$head x$$ +is the vector of the independent variables. + +$end +*/ +// BEGIN_ONE_ARGUMENT +template +void Independent(ADVector &x) +// END_ONE_ARGUMENT +{ size_t abort_op_index = 0; + bool record_compare = true; + ADVector dynamic(0); // empty vector + Independent(x, abort_op_index, record_compare, dynamic); +} + +} // END_CPPAD_NAMESPACE +# endif diff --git a/build-config/cppad/include/cppad/core/independent/user.omh b/build-config/cppad/include/cppad/core/independent/user.omh new file mode 100644 index 00000000..e63eed83 --- /dev/null +++ b/build-config/cppad/include/cppad/core/independent/user.omh @@ -0,0 +1,157 @@ +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ +$begin Independent$$ +$spell + op + alloc + num + Cpp + bool + const + var + typename +$$ + +$section Declare Independent Variables and Start Recording$$ + +$head Syntax$$ +$codei%Independent(%x%) +%$$ +$codei%Independent(%x%, %dynamic%) +%$$ +$codei%Independent(%x%, %abort_op_index%) +%$$ +$codei%Independent(%x%, %abort_op_index%, %record_compare%) +%$$ +$codei%Independent(%x%, %abort_op_index%, %record_compare%, %dynamic%) +%$$ + +$head Start Recording$$ +The syntax above starts recording +$cref/AD of Base/glossary/AD of Base/$$ operations +with $icode x$$ as the independent variable vector. +Once the +$cref/operation sequence/glossary/Operation/Sequence/$$ is completed, +it must be transferred to a function object or aborted; see below. + +$head Stop Recording$$ +The recording is stopped, +and the operation sequence is transferred to the AD function object $icode f$$, +using either the $cref/function constructor/FunConstruct/$$ +$codei% + ADFun<%Base%> %f%(%x%, %y%) +%$$ +or the $cref/dependent variable specifier/Dependent/$$ +$codei% + %f%.Dependent(%x%, %y%) +%$$ +The only other way to stop a recording is using +$cref abort_recording$$. +Between when the recording is started and when it stopped, +we refer to the elements of $icode x$$, +and the values that depend on the elements of $icode x$$, +as $codei%AD<%Base%>%$$ variables. + +$head x$$ +The vector $icode x$$ has prototype +$codei% + %ADVector% &%x% +%$$ +(see $icode ADVector$$ below). +The size of the vector $icode x$$, must be greater than zero, +and is the number of independent variables for this +AD operation sequence. + +$head abort_op_index$$ +If this argument has prototype +$codei% + size_t %abort_op_index% +%$$ +If it is present, +it specifies the operator index at which the execution will aborted +by calling the CppAD $cref/error handler/ErrorHandler/$$. +When this error handler leads to an assert, the user +can inspect the call stack to see the source code corresponding to +this operator index; see +$cref/purpose/compare_change/op_index/Purpose/$$ for $icode op_index$$ +and $cref/NDEBUG/Faq/Speed/NDEBUG/$$. +No abort will occur if $icode abort_op_index$$ is zero. +If this argument is not present, the default value zero is used +for $icode abort_index$$. + +$head record_compare$$ +This argument has prototype +$codei% + bool %record_compare% +%$$ +If it is present, +it specifies if AD $cref compare$$ operations are recorded. +It takes extra time and memory to record these operations. +On the other hand, they can be useful for detecting when and why +a functions recording would change; see $icode abort_op_index$$ above and +$cref compare_change$$. +If this argument is not present, the default value $code true$$ is used +for $icode record_compare$$. +If this argument is false, $icode abort_op_index$$ must be zero. + +$head dynamic$$ +If this argument is present, it has prototype +$codei% + const %ADVector%& %dynamic% +%$$ +(see $icode Vector$$ below). +It specifies the independent +$cref/dynamic/glossary/Parameter/Dynamic/$$ parameters. +The value of these parameters, +in the $cref ADFun$$ object $icode f$$, +that can be changed using $cref new_dynamic$$. + +$subhead Efficiency$$ +Any operations that use dynamic parameters will be recorded. +We use other dynamic parameters to denote parameters that depend on +the independent dynamic parameters $icode dynamic$$, +and do not depend on $icode x$$. +It is more efficient to compute other dynamic parameters before calling +$code Independent$$ and include them in the +independent dynamic parameter vector $icode dynamic$$. + +$head ADVector$$ +The type $icode ADVector$$ must be a $cref SimpleVector$$ class with +$cref/elements of type/SimpleVector/Elements of Specified Type/$$ +$codei%AD<%Base%>%$$. +The routine $cref CheckSimpleVector$$ will generate an error message +if this is not the case. + +$head Parallel Mode$$ +Each thread can have one, and only one, active recording. +A call to $code Independent$$ starts the recording for the current thread. +The recording must be stopped by a corresponding call to +$codei% + ADFun<%Base%> %f%( %x%, %y%) +%$$ +or +$codei% + %f%.Dependent( %x%, %y%) +%$$ +or $cref abort_recording$$ +preformed by the same thread; i.e., +$cref/thread_alloc::thread_num/ta_thread_num/$$ must be the same. + +$head Example$$ +$children% + example/general/independent.cpp +%$$ +The file +$cref independent.cpp$$ +contains an example and test of this operation. + +$end diff --git a/build-config/cppad/include/cppad/core/integer.hpp b/build-config/cppad/include/cppad/core/integer.hpp new file mode 100644 index 00000000..8a3e976d --- /dev/null +++ b/build-config/cppad/include/cppad/core/integer.hpp @@ -0,0 +1,111 @@ +# ifndef CPPAD_CORE_INTEGER_HPP +# define CPPAD_CORE_INTEGER_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-18 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +/* +------------------------------------------------------------------------------ +$begin Integer$$ +$spell + std + VecAD + CppAD + namespace + const + bool +$$ + + + +$section Convert From AD to Integer$$ + +$head Syntax$$ +$icode%i% = Integer(%x%)%$$ + + +$head Purpose$$ +Converts from an AD type to the corresponding integer value. + +$head i$$ +The result $icode i$$ has prototype +$codei% + int %i% +%$$ + +$head x$$ + +$subhead Real Types$$ +If the argument $icode x$$ has either of the following prototypes: +$codei% + const float %% &%x% + const double %% &%x% +%$$ +the fractional part is dropped to form the integer value. +For example, if $icode x$$ is 1.5, $icode i$$ is 1. +In general, if $latex x \geq 0$$, $icode i$$ is the +greatest integer less than or equal $icode x$$. +If $latex x \leq 0$$, $icode i$$ is the +smallest integer greater than or equal $icode x$$. + +$subhead Complex Types$$ +If the argument $icode x$$ has either of the following prototypes: +$codei% + const std::complex %% &%x% + const std::complex %% &%x% +%$$ +The result $icode i$$ is given by +$codei% + %i% = Integer(%x%.real()) +%$$ + +$subhead AD Types$$ +If the argument $icode x$$ has either of the following prototypes: +$codei% + const AD<%Base%> &%x% + const VecAD<%Base%>::reference &%x% +%$$ +$icode Base$$ must support the $code Integer$$ function and +the conversion has the same meaning as for $icode Base$$. + +$head Operation Sequence$$ +The result of this operation is not an +$cref/AD of Base/glossary/AD of Base/$$ object. +Thus it will not be recorded as part of an +AD of $icode Base$$ +$cref/operation sequence/glossary/Operation/Sequence/$$. + +$head Example$$ +$children% + example/general/integer.cpp +%$$ +The file +$cref integer.cpp$$ +contains an example and test of this operation. + +$end +------------------------------------------------------------------------------ +*/ + + +namespace CppAD { + + template + CPPAD_INLINE_FRIEND_TEMPLATE_FUNCTION + int Integer(const AD &x) + { return Integer(x.value_); } + + template + CPPAD_INLINE_FRIEND_TEMPLATE_FUNCTION + int Integer(const VecAD_reference &x) + { return Integer( x.ADBase() ); } +} +# endif diff --git a/build-config/cppad/include/cppad/core/jacobian.hpp b/build-config/cppad/include/cppad/core/jacobian.hpp new file mode 100644 index 00000000..3490bb1f --- /dev/null +++ b/build-config/cppad/include/cppad/core/jacobian.hpp @@ -0,0 +1,237 @@ +# ifndef CPPAD_CORE_JACOBIAN_HPP +# define CPPAD_CORE_JACOBIAN_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-18 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +/* +$begin Jacobian$$ +$spell + jac + typename + Taylor + Jacobian + DetLu + const +$$ + + +$section Jacobian: Driver Routine$$ + +$head Syntax$$ +$icode%jac% = %f%.Jacobian(%x%)%$$ + + +$head Purpose$$ +We use $latex F : \B{R}^n \rightarrow \B{R}^m$$ to denote the +$cref/AD function/glossary/AD Function/$$ corresponding to $icode f$$. +The syntax above sets $icode jac$$ to the +Jacobian of $icode F$$ evaluated at $icode x$$; i.e., +$latex \[ + jac = F^{(1)} (x) +\] $$ + +$head f$$ +The object $icode f$$ has prototype +$codei% + ADFun<%Base%> %f% +%$$ +Note that the $cref ADFun$$ object $icode f$$ is not $code const$$ +(see $cref/Forward or Reverse/Jacobian/Forward or Reverse/$$ below). + +$head x$$ +The argument $icode x$$ has prototype +$codei% + const %Vector% &%x% +%$$ +(see $cref/Vector/Jacobian/Vector/$$ below) +and its size +must be equal to $icode n$$, the dimension of the +$cref/domain/seq_property/Domain/$$ space for $icode f$$. +It specifies +that point at which to evaluate the Jacobian. + +$head jac$$ +The result $icode jac$$ has prototype +$codei% + %Vector% %jac% +%$$ +(see $cref/Vector/Jacobian/Vector/$$ below) +and its size is $latex m * n$$; i.e., the product of the +$cref/domain/seq_property/Domain/$$ +and +$cref/range/seq_property/Range/$$ +dimensions for $icode f$$. +For $latex i = 0 , \ldots , m - 1 $$ +and $latex j = 0 , \ldots , n - 1$$ +$latex \[. + jac[ i * n + j ] = \D{ F_i }{ x_j } ( x ) +\] $$ + + +$head Vector$$ +The type $icode Vector$$ must be a $cref SimpleVector$$ class with +$cref/elements of type/SimpleVector/Elements of Specified Type/$$ +$icode Base$$. +The routine $cref CheckSimpleVector$$ will generate an error message +if this is not the case. + +$head Forward or Reverse$$ +This will use order zero Forward mode and either +order one Forward or order one Reverse to compute the Jacobian +(depending on which it estimates will require less work). +After each call to $cref Forward$$, +the object $icode f$$ contains the corresponding +$cref/Taylor coefficients/glossary/Taylor Coefficient/$$. +After a call to $code Jacobian$$, +the zero order Taylor coefficients correspond to +$icode%f%.Forward(0, %x%)%$$ +and the other coefficients are unspecified. + +$head Example$$ +$children% + example/general/jacobian.cpp +%$$ +The routine +$cref/Jacobian/jacobian.cpp/$$ is both an example and test. +It returns $code true$$, if it succeeds and $code false$$ otherwise. + +$end +----------------------------------------------------------------------------- +*/ + +// BEGIN CppAD namespace +namespace CppAD { + +template +void JacobianFor(ADFun &f, const Vector &x, Vector &jac) +{ size_t i; + size_t j; + + size_t n = f.Domain(); + size_t m = f.Range(); + + // check Vector is Simple Vector class with Base type elements + CheckSimpleVector(); + + CPPAD_ASSERT_UNKNOWN( size_t(x.size()) == f.Domain() ); + CPPAD_ASSERT_UNKNOWN( size_t(jac.size()) == f.Range() * f.Domain() ); + + // argument and result for forward mode calculations + Vector u(n); + Vector v(m); + + // initialize all the components + for(j = 0; j < n; j++) + u[j] = Base(0.0); + + // loop through the different coordinate directions + for(j = 0; j < n; j++) + { // set u to the j-th coordinate direction + u[j] = Base(1.0); + + // compute the partial of f w.r.t. this coordinate direction + v = f.Forward(1, u); + + // reset u to vector of all zeros + u[j] = Base(0.0); + + // return the result + for(i = 0; i < m; i++) + jac[ i * n + j ] = v[i]; + } +} +template +void JacobianRev(ADFun &f, const Vector &x, Vector &jac) +{ size_t i; + size_t j; + + size_t n = f.Domain(); + size_t m = f.Range(); + + CPPAD_ASSERT_UNKNOWN( size_t(x.size()) == f.Domain() ); + CPPAD_ASSERT_UNKNOWN( size_t(jac.size()) == f.Range() * f.Domain() ); + + // argument and result for reverse mode calculations + Vector u(n); + Vector v(m); + + // initialize all the components + for(i = 0; i < m; i++) + v[i] = Base(0.0); + + // loop through the different coordinate directions + for(i = 0; i < m; i++) + { if( f.Parameter(i) ) + { // return zero for this component of f + for(j = 0; j < n; j++) + jac[ i * n + j ] = Base(0.0); + } + else + { + // set v to the i-th coordinate direction + v[i] = Base(1.0); + + // compute the derivative of this component of f + u = f.Reverse(1, v); + + // reset v to vector of all zeros + v[i] = Base(0.0); + + // return the result + for(j = 0; j < n; j++) + jac[ i * n + j ] = u[j]; + } + } +} + +template +template +Vector ADFun::Jacobian(const Vector &x) +{ size_t i; + size_t n = Domain(); + size_t m = Range(); + + CPPAD_ASSERT_KNOWN( + size_t(x.size()) == n, + "Jacobian: length of x not equal domain dimension for F" + ); + + // point at which we are evaluating the Jacobian + Forward(0, x); + + // work factor for forward mode + size_t workForward = n; + + // work factor for reverse mode + size_t workReverse = 0; + for(i = 0; i < m; i++) + { if( ! Parameter(i) ) + ++workReverse; + } + + // choose the method with the least work + Vector jac( n * m ); +# ifdef CPPAD_FOR_TMB + if( workForward < workReverse ) +# else + if( workForward <= workReverse ) +# endif + JacobianFor(*this, x, jac); + else + JacobianRev(*this, x, jac); + + return jac; +} + +} // END CppAD namespace + +# endif diff --git a/build-config/cppad/include/cppad/core/lu_ratio.hpp b/build-config/cppad/include/cppad/core/lu_ratio.hpp new file mode 100644 index 00000000..f46207b3 --- /dev/null +++ b/build-config/cppad/include/cppad/core/lu_ratio.hpp @@ -0,0 +1,335 @@ +# ifndef CPPAD_CORE_LU_RATIO_HPP +# define CPPAD_CORE_LU_RATIO_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-18 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +/* +$begin LuRatio$$ +$spell + cppad.hpp + xk + Cpp + Lu + bool + const + ip + jp + std + ADvector +$$ + + +$section LU Factorization of A Square Matrix and Stability Calculation$$ + +$head Syntax$$ +$code# include $$ +$pre +$$ +$icode%sign% = LuRatio(%ip%, %jp%, %LU%, %ratio%)%$$ + + +$head Description$$ +Computes an LU factorization of the matrix $icode A$$ +where $icode A$$ is a square matrix. +A measure of the numerical stability called $icode ratio$$ is calculated. +This ratio is useful when the results of $code LuRatio$$ are +used as part of an $cref ADFun$$ object. + +$head Include$$ +This routine is designed to be used with AD objects and +requires the $code cppad/cppad.hpp$$ file to be included. + +$head Matrix Storage$$ +All matrices are stored in row major order. +To be specific, if $latex Y$$ is a vector +that contains a $latex p$$ by $latex q$$ matrix, +the size of $latex Y$$ must be equal to $latex p * q $$ and for +$latex i = 0 , \ldots , p-1$$, +$latex j = 0 , \ldots , q-1$$, +$latex \[ + Y_{i,j} = Y[ i * q + j ] +\] $$ + +$head sign$$ +The return value $icode sign$$ has prototype +$codei% + int %sign% +%$$ +If $icode A$$ is invertible, $icode sign$$ is plus or minus one +and is the sign of the permutation corresponding to the row ordering +$icode ip$$ and column ordering $icode jp$$. +If $icode A$$ is not invertible, $icode sign$$ is zero. + +$head ip$$ +The argument $icode ip$$ has prototype +$codei% + %SizeVector% &%ip% +%$$ +(see description of $cref/SizeVector/LuFactor/SizeVector/$$ below). +The size of $icode ip$$ is referred to as $icode n$$ in the +specifications below. +The input value of the elements of $icode ip$$ does not matter. +The output value of the elements of $icode ip$$ determine +the order of the rows in the permuted matrix. + +$head jp$$ +The argument $icode jp$$ has prototype +$codei% + %SizeVector% &%jp% +%$$ +(see description of $cref/SizeVector/LuFactor/SizeVector/$$ below). +The size of $icode jp$$ must be equal to $icode n$$. +The input value of the elements of $icode jp$$ does not matter. +The output value of the elements of $icode jp$$ determine +the order of the columns in the permuted matrix. + +$head LU$$ +The argument $icode LU$$ has the prototype +$codei% + %ADvector% &%LU% +%$$ +and the size of $icode LU$$ must equal $latex n * n$$ +(see description of $cref/ADvector/LuRatio/ADvector/$$ below). + +$subhead A$$ +We define $icode A$$ as the matrix corresponding to the input +value of $icode LU$$. + +$subhead P$$ +We define the permuted matrix $icode P$$ in terms of $icode A$$ by +$codei% + %P%(%i%, %j%) = %A%[ %ip%[%i%] * %n% + %jp%[%j%] ] +%$$ + +$subhead L$$ +We define the lower triangular matrix $icode L$$ in terms of the +output value of $icode LU$$. +The matrix $icode L$$ is zero above the diagonal +and the rest of the elements are defined by +$codei% + %L%(%i%, %j%) = %LU%[ %ip%[%i%] * %n% + %jp%[%j%] ] +%$$ +for $latex i = 0 , \ldots , n-1$$ and $latex j = 0 , \ldots , i$$. + +$subhead U$$ +We define the upper triangular matrix $icode U$$ in terms of the +output value of $icode LU$$. +The matrix $icode U$$ is zero below the diagonal, +one on the diagonal, +and the rest of the elements are defined by +$codei% + %U%(%i%, %j%) = %LU%[ %ip%[%i%] * %n% + %jp%[%j%] ] +%$$ +for $latex i = 0 , \ldots , n-2$$ and $latex j = i+1 , \ldots , n-1$$. + +$subhead Factor$$ +If the return value $icode sign$$ is non-zero, +$codei% + %L% * %U% = %P% +%$$ +If the return value of $icode sign$$ is zero, +the contents of $icode L$$ and $icode U$$ are not defined. + +$subhead Determinant$$ +If the return value $icode sign$$ is zero, +the determinant of $icode A$$ is zero. +If $icode sign$$ is non-zero, +using the output value of $icode LU$$ +the determinant of the matrix $icode A$$ is equal to +$codei% +%sign% * %LU%[%ip%[0], %jp%[0]] * %...% * %LU%[%ip%[%n%-1], %jp%[%n%-1]] +%$$ + +$head ratio$$ +The argument $icode ratio$$ has prototype +$codei% + AD<%Base%> &%ratio% +%$$ +On input, the value of $icode ratio$$ does not matter. +On output it is a measure of how good the choice of pivots is. +For $latex p = 0 , \ldots , n-1$$, +the $th p$$ pivot element is the element of maximum absolute value of a +$latex (n-p) \times (n-p)$$ sub-matrix. +The ratio of each element of sub-matrix divided by the pivot element +is computed. +The return value of $icode ratio$$ is the maximum absolute value of +such ratios over with respect to all elements and all the pivots. + +$subhead Purpose$$ +Suppose that the execution of a call to $code LuRatio$$ +is recorded in the $codei%ADFun<%Base%>%$$ object $icode F$$. +Then a call to $cref Forward$$ of the form +$codei% + %F%.Forward(%k%, %xk%) +%$$ +with $icode k$$ equal to zero will revaluate this Lu factorization +with the same pivots and a new value for $icode A$$. +In this case, the resulting $icode ratio$$ may not be one. +If $icode ratio$$ is too large (the meaning of too large is up to you), +the current pivots do not yield a stable LU factorization of $icode A$$. +A better choice for the pivots (for this value of $icode A$$) +will be made if you recreate the $code ADFun$$ object +starting with the $cref Independent$$ variable values +that correspond to the vector $icode xk$$. + +$head SizeVector$$ +The type $icode SizeVector$$ must be a $cref SimpleVector$$ class with +$cref/elements of type size_t/SimpleVector/Elements of Specified Type/$$. +The routine $cref CheckSimpleVector$$ will generate an error message +if this is not the case. + +$head ADvector$$ +The type $icode ADvector$$ must be a +$cref/simple vector class/SimpleVector/$$ with elements of type +$codei%AD<%Base%>%$$. +The routine $cref CheckSimpleVector$$ will generate an error message +if this is not the case. + + +$head Example$$ +$children% + example/general/lu_ratio.cpp +%$$ +The file $cref lu_ratio.cpp$$ +contains an example and test of using $code LuRatio$$. + +$end +-------------------------------------------------------------------------- +*/ +namespace CppAD { // BEGIN CppAD namespace + +// Lines different from the code in cppad/lu_factor.hpp end with // +template // +int LuRatio(SizeVector &ip, SizeVector &jp, ADvector &LU, AD &ratio) // +{ + typedef ADvector FloatVector; // + typedef AD Float; // + + // check numeric type specifications + CheckNumericType(); + + // check simple vector class specifications + CheckSimpleVector(); + CheckSimpleVector(); + + size_t i, j; // some temporary indices + const Float zero( 0 ); // the value zero as a Float object + size_t imax; // row index of maximum element + size_t jmax; // column indx of maximum element + Float emax; // maximum absolute value + size_t p; // count pivots + int sign; // sign of the permutation + Float etmp; // temporary element + Float pivot; // pivot element + + // ------------------------------------------------------- + size_t n = size_t(ip.size()); + CPPAD_ASSERT_KNOWN( + size_t(jp.size()) == n, + "Error in LuFactor: jp must have size equal to n" + ); + CPPAD_ASSERT_KNOWN( + size_t(LU.size()) == n * n, + "Error in LuFactor: LU must have size equal to n * m" + ); + // ------------------------------------------------------- + + // initialize row and column order in matrix not yet pivoted + for(i = 0; i < n; i++) + { ip[i] = i; + jp[i] = i; + } + // initialize the sign of the permutation + sign = 1; + // initialize the ratio // + ratio = Float(1); // + // --------------------------------------------------------- + + // Reduce the matrix P to L * U using n pivots + for(p = 0; p < n; p++) + { // determine row and column corresponding to element of + // maximum absolute value in remaining part of P + imax = jmax = n; + emax = zero; + for(i = p; i < n; i++) + { for(j = p; j < n; j++) + { CPPAD_ASSERT_UNKNOWN( + (ip[i] < n) & (jp[j] < n) + ); + etmp = LU[ ip[i] * n + jp[j] ]; + + // check if maximum absolute value so far + if( AbsGeq (etmp, emax) ) + { imax = i; + jmax = j; + emax = etmp; + } + } + } + for(i = p; i < n; i++) // + { for(j = p; j < n; j++) // + { etmp = fabs(LU[ ip[i] * n + jp[j] ] / emax); // + ratio = // + CondExpGt(etmp, ratio, etmp, ratio); // + } // + } // + CPPAD_ASSERT_KNOWN( + (imax < n) & (jmax < n) , + "AbsGeq must return true when second argument is zero" + ); + if( imax != p ) + { // switch rows so max absolute element is in row p + i = ip[p]; + ip[p] = ip[imax]; + ip[imax] = i; + sign = -sign; + } + if( jmax != p ) + { // switch columns so max absolute element is in column p + j = jp[p]; + jp[p] = jp[jmax]; + jp[jmax] = j; + sign = -sign; + } + // pivot using the max absolute element + pivot = LU[ ip[p] * n + jp[p] ]; + + // check for determinant equal to zero + if( pivot == zero ) + { // abort the mission + return 0; + } + + // Reduce U by the elementary transformations that maps + // LU( ip[p], jp[p] ) to one. Only need transform elements + // above the diagonal in U and LU( ip[p] , jp[p] ) is + // corresponding value below diagonal in L. + for(j = p+1; j < n; j++) + LU[ ip[p] * n + jp[j] ] /= pivot; + + // Reduce U by the elementary transformations that maps + // LU( ip[i], jp[p] ) to zero. Only need transform elements + // above the diagonal in U and LU( ip[i], jp[p] ) is + // corresponding value below diagonal in L. + for(i = p+1; i < n; i++ ) + { etmp = LU[ ip[i] * n + jp[p] ]; + for(j = p+1; j < n; j++) + { LU[ ip[i] * n + jp[j] ] -= + etmp * LU[ ip[p] * n + jp[j] ]; + } + } + } + return sign; +} +} // END CppAD namespace + +# endif diff --git a/build-config/cppad/include/cppad/core/mul.hpp b/build-config/cppad/include/cppad/core/mul.hpp new file mode 100644 index 00000000..a85eb71d --- /dev/null +++ b/build-config/cppad/include/cppad/core/mul.hpp @@ -0,0 +1,136 @@ +# ifndef CPPAD_CORE_MUL_HPP +# define CPPAD_CORE_MUL_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +// BEGIN CppAD namespace +namespace CppAD { + +template +AD operator * (const AD &left , const AD &right) +{ + // compute the Base part + AD result; + result.value_ = left.value_ * right.value_; + CPPAD_ASSERT_UNKNOWN( Parameter(result) ); + + // check if there is a recording in progress + local::ADTape* tape = AD::tape_ptr(); + if( tape == nullptr ) + return result; + tape_id_t tape_id = tape->id_; + // tape_id cannot match the default value for tape_id_; i.e., 0 + CPPAD_ASSERT_UNKNOWN( tape_id > 0 ); + + // check if left and right tapes match + bool match_left = left.tape_id_ == tape_id; + bool match_right = right.tape_id_ == tape_id; + + // check if left and right are dynamic parameters + bool dyn_left = match_left & (left.ad_type_ == dynamic_enum); + bool dyn_right = match_right & (right.ad_type_ == dynamic_enum); + + // check if left and right are variables + bool var_left = match_left & (left.ad_type_ != dynamic_enum); + bool var_right = match_right & (right.ad_type_ != dynamic_enum); + + CPPAD_ASSERT_KNOWN( + left.tape_id_ == right.tape_id_ || ! match_left || ! match_right , + "Multiply: AD variables or dynamic parameters on different threads." + ); + if( var_left ) + { if( var_right ) + { // result = variable * variable + CPPAD_ASSERT_UNKNOWN( local::NumRes(local::MulvvOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( local::NumArg(local::MulvvOp) == 2 ); + + // put operand addresses in tape + tape->Rec_.PutArg(left.taddr_, right.taddr_); + // put operator in the tape + result.taddr_ = tape->Rec_.PutOp(local::MulvvOp); + // make result a variable + result.tape_id_ = tape_id; + result.ad_type_ = variable_enum; + } + else if( (! dyn_right) & IdenticalZero(right.value_) ) + { // result = variable * 0 + } + else if( (! dyn_right) & IdenticalOne(right.value_) ) + { // result = variable * 1 + result.make_variable(left.tape_id_, left.taddr_); + } + else + { // result = variable * parameter + CPPAD_ASSERT_UNKNOWN( local::NumRes(local::MulpvOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( local::NumArg(local::MulpvOp) == 2 ); + + // put operand addresses in tape + addr_t p = right.taddr_; + if( ! dyn_right ) + p = tape->Rec_.put_con_par(right.value_); + tape->Rec_.PutArg(p, left.taddr_); + // put operator in the tape + result.taddr_ = tape->Rec_.PutOp(local::MulpvOp); + // make result a variable + result.tape_id_ = tape_id; + result.ad_type_ = variable_enum; + } + } + else if( var_right ) + { if( (! dyn_left) & IdenticalZero(left.value_) ) + { // result = 0 * variable + } + else if( (! dyn_left) & IdenticalOne(left.value_) ) + { // result = 1 * variable + result.make_variable(right.tape_id_, right.taddr_); + } + else + { // result = parameter * variable + CPPAD_ASSERT_UNKNOWN( local::NumRes(local::MulpvOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( local::NumArg(local::MulpvOp) == 2 ); + + // put operand addresses in tape + addr_t p = left.taddr_; + if( ! dyn_left ) + p = tape->Rec_.put_con_par(left.value_); + tape->Rec_.PutArg(p, right.taddr_); + // put operator in the tape + result.taddr_ = tape->Rec_.PutOp(local::MulpvOp); + // make result a variable + result.tape_id_ = tape_id; + result.ad_type_ = variable_enum; + } + } + else if( dyn_left | dyn_right ) + { addr_t arg0 = left.taddr_; + addr_t arg1 = right.taddr_; + if( ! dyn_left ) + arg0 = tape->Rec_.put_con_par(left.value_); + if( ! dyn_right ) + arg1 = tape->Rec_.put_con_par(right.value_); + // + // parameters with a dynamic parameter result + result.taddr_ = tape->Rec_.put_dyn_par( + result.value_, local::mul_dyn, arg0, arg1 + ); + result.tape_id_ = tape_id; + result.ad_type_ = dynamic_enum; + } + return result; +} + +// convert other cases into the case above +CPPAD_FOLD_AD_VALUED_BINARY_OPERATOR(*) + +} // END CppAD namespace + +# endif diff --git a/build-config/cppad/include/cppad/core/mul_eq.hpp b/build-config/cppad/include/cppad/core/mul_eq.hpp new file mode 100644 index 00000000..acc4e774 --- /dev/null +++ b/build-config/cppad/include/cppad/core/mul_eq.hpp @@ -0,0 +1,138 @@ +# ifndef CPPAD_CORE_MUL_EQ_HPP +# define CPPAD_CORE_MUL_EQ_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +// BEGIN CppAD namespace +namespace CppAD { + +template +AD& AD::operator *= (const AD &right) +{ + // compute the Base part + Base left; + left = value_; + value_ *= right.value_; + + // check if there is a recording in progress + local::ADTape* tape = AD::tape_ptr(); + if( tape == nullptr ) + return *this; + tape_id_t tape_id = tape->id_; + // tape_id cannot match the default value for tape_id_; i.e., 0 + CPPAD_ASSERT_UNKNOWN( tape_id > 0 ); + + // check if left and right tapes match + bool match_left = tape_id_ == tape_id; + bool match_right = right.tape_id_ == tape_id; + + // check if left and right are dynamic parameters + bool dyn_left = match_left & (ad_type_ == dynamic_enum); + bool dyn_right = match_right & (right.ad_type_ == dynamic_enum); + + // check if left and right are variables + bool var_left = match_left & (ad_type_ != dynamic_enum); + bool var_right = match_right & (right.ad_type_ != dynamic_enum); + + CPPAD_ASSERT_KNOWN( + tape_id_ == right.tape_id_ || ! match_left || ! match_right , + "*= : AD variables or dynamic parameters on different threads." + ); + if( var_left ) + { if( var_right ) + { // this = variable * variable + CPPAD_ASSERT_UNKNOWN( local::NumRes(local::MulvvOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( local::NumArg(local::MulvvOp) == 2 ); + + // put operand addresses in tape + tape->Rec_.PutArg(taddr_, right.taddr_); + // put operator in the tape + taddr_ = tape->Rec_.PutOp(local::MulvvOp); + // check that this is a variable + CPPAD_ASSERT_UNKNOWN( tape_id_ == tape_id ); + CPPAD_ASSERT_UNKNOWN( ad_type_ == variable_enum); + } + else if( (! dyn_right) & IdenticalOne(right.value_) ) + { // this = variable * 1 + } + else if( (! dyn_right) & IdenticalZero(right.value_) ) + { // this = variable * 0 + tape_id_ = 0; // not in current tape + } + else + { // this = variable * parameter + // = parameter * variable + CPPAD_ASSERT_UNKNOWN( local::NumRes(local::MulpvOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( local::NumArg(local::MulpvOp) == 2 ); + + // put operand addresses in tape + addr_t p = right.taddr_; + if( ! dyn_right ) + p = tape->Rec_.put_con_par(right.value_); + tape->Rec_.PutArg(p, taddr_); + // put operator in the tape + taddr_ = tape->Rec_.PutOp(local::MulpvOp); + // check that this is a variable + CPPAD_ASSERT_UNKNOWN( tape_id_ == tape_id ); + CPPAD_ASSERT_UNKNOWN( ad_type_ == variable_enum); + } + } + else if( var_right ) + { if( (! dyn_left) & IdenticalZero(left) ) + { // this = 0 * right + } + else if( (! dyn_left) & IdenticalOne(left) ) + { // this = 1 * right + make_variable(right.tape_id_, right.taddr_); + } + else + { // this = parameter * variable + CPPAD_ASSERT_UNKNOWN( local::NumRes(local::MulpvOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( local::NumArg(local::MulpvOp) == 2 ); + + // put operand addresses in tape + addr_t p = taddr_; + if( ! dyn_left ) + p = tape->Rec_.put_con_par(left); + tape->Rec_.PutArg(p, right.taddr_); + + // put operator in the tape + taddr_ = tape->Rec_.PutOp(local::MulpvOp); + + // make this a variable + tape_id_ = tape_id; + ad_type_ = variable_enum; + } + } + else if( dyn_left | dyn_right ) + { addr_t arg0 = taddr_; + addr_t arg1 = right.taddr_; + if( ! dyn_left ) + arg0 = tape->Rec_.put_con_par(left); + if( ! dyn_right ) + arg1 = tape->Rec_.put_con_par(right.value_); + // + // parameters with a dynamic parameter results + taddr_ = tape->Rec_.put_dyn_par( + value_, local::mul_dyn, arg0, arg1 + ); + tape_id_ = tape_id; + ad_type_ = dynamic_enum; + } + return *this; +} + +CPPAD_FOLD_ASSIGNMENT_OPERATOR(*=) + +} // END CppAD namespace + +# endif diff --git a/build-config/cppad/include/cppad/core/near_equal_ext.hpp b/build-config/cppad/include/cppad/core/near_equal_ext.hpp new file mode 100644 index 00000000..aa6003f8 --- /dev/null +++ b/build-config/cppad/include/cppad/core/near_equal_ext.hpp @@ -0,0 +1,187 @@ +# ifndef CPPAD_CORE_NEAR_EQUAL_EXT_HPP +# define CPPAD_CORE_NEAR_EQUAL_EXT_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-17 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ +/* +$begin NearEqualExt$$ +$spell + cout + endl + Microsoft + std + Cpp + namespace + const + bool +$$ + +$section Compare AD and Base Objects for Nearly Equal$$ + + +$head Syntax$$ +$icode%b% = NearEqual(%x%, %y%, %r%, %a%)%$$ + + +$head Purpose$$ +The routine $cref NearEqual$$ determines if two objects of +the same type are nearly. +This routine is extended to the case where one object can have type +$icode Type$$ while the other can have type +$codei%AD<%Type%>%$$ or +$codei%AD< std::complex<%Type%> >%$$. + +$head x$$ +The arguments $icode x$$ +has one of the following possible prototypes: +$codei% + const %Type% &%x% + const AD<%Type%> &%x% + const AD< std::complex<%Type%> > &%x% +%$$ + +$head y$$ +The arguments $icode y$$ +has one of the following possible prototypes: +$codei% + const %Type% &%y% + const AD<%Type%> &%y% + const AD< std::complex<%Type%> > &%x% +%$$ + + +$head r$$ +The relative error criteria $icode r$$ has prototype +$codei% + const %Type% &%r% +%$$ +It must be greater than or equal to zero. +The relative error condition is defined as: +$latex \[ + \frac{ | x - y | } { |x| + |y| } \leq r +\] $$ + +$head a$$ +The absolute error criteria $icode a$$ has prototype +$codei% + const %Type% &%a% +%$$ +It must be greater than or equal to zero. +The absolute error condition is defined as: +$latex \[ + | x - y | \leq a +\] $$ + +$head b$$ +The return value $icode b$$ has prototype +$codei% + bool %b% +%$$ +If either $icode x$$ or $icode y$$ is infinite or not a number, +the return value is false. +Otherwise, if either the relative or absolute error +condition (defined above) is satisfied, the return value is true. +Otherwise, the return value is false. + +$head Type$$ +The type $icode Type$$ must be a +$cref NumericType$$. +The routine $cref CheckNumericType$$ will generate +an error message if this is not the case. +If $icode a$$ and $icode b$$ have type $icode Type$$, +the following operation must be defined +$table +$bold Operation$$ $cnext + $bold Description$$ $rnext +$icode%a% <= %b%$$ $cnext + less that or equal operator (returns a $code bool$$ object) +$tend + +$head Operation Sequence$$ +The result of this operation is not an +$cref/AD of Base/glossary/AD of Base/$$ object. +Thus it will not be recorded as part of an +AD of $icode Base$$ +$cref/operation sequence/glossary/Operation/Sequence/$$. + +$head Example$$ +$children% + example/general/near_equal_ext.cpp +%$$ +The file $cref near_equal_ext.cpp$$ contains an example +and test of this extension of $cref NearEqual$$. +It return true if it succeeds and false otherwise. + +$end + +*/ +// BEGIN CppAD namespace +namespace CppAD { +// ------------------------------------------------------------------------ + +// fold into base type and then use +template +CPPAD_INLINE_FRIEND_TEMPLATE_FUNCTION +bool NearEqual( +const AD &x, const AD &y, const Base &r, const Base &a) +{ return NearEqual(x.value_, y.value_, r, a); +} + +template +CPPAD_INLINE_FRIEND_TEMPLATE_FUNCTION +bool NearEqual( +const Base &x, const AD &y, const Base &r, const Base &a) +{ return NearEqual(x, y.value_, r, a); +} + +template +CPPAD_INLINE_FRIEND_TEMPLATE_FUNCTION +bool NearEqual( +const AD &x, const Base &y, const Base &r, const Base &a) +{ return NearEqual(x.value_, y, r, a); +} + +// fold into AD type and then use cases above +template +CPPAD_INLINE_FRIEND_TEMPLATE_FUNCTION +bool NearEqual( + const VecAD_reference &x, const VecAD_reference &y, + const Base &r, const Base &a) +{ return NearEqual(x.ADBase(), y.ADBase(), r, a); +} +template +CPPAD_INLINE_FRIEND_TEMPLATE_FUNCTION +bool NearEqual(const VecAD_reference &x, const AD &y, + const Base &r, const Base &a) +{ return NearEqual(x.ADBase(), y, r, a); +} +template +CPPAD_INLINE_FRIEND_TEMPLATE_FUNCTION +bool NearEqual(const VecAD_reference &x, const Base &y, + const Base &r, const Base &a) +{ return NearEqual(x.ADBase(), y, r, a); +} +template +CPPAD_INLINE_FRIEND_TEMPLATE_FUNCTION +bool NearEqual(const AD &x, const VecAD_reference &y, + const Base &r, const Base &a) +{ return NearEqual(x, y.ADBase(), r, a); +} +template +CPPAD_INLINE_FRIEND_TEMPLATE_FUNCTION +bool NearEqual(const Base &x, const VecAD_reference &y, + const Base &r, const Base &a) +{ return NearEqual(x, y.ADBase(), r, a); +} + +} // END CppAD namespace + +# endif diff --git a/build-config/cppad/include/cppad/core/new_dynamic.hpp b/build-config/cppad/include/cppad/core/new_dynamic.hpp new file mode 100644 index 00000000..441d577a --- /dev/null +++ b/build-config/cppad/include/cppad/core/new_dynamic.hpp @@ -0,0 +1,139 @@ +# ifndef CPPAD_CORE_NEW_DYNAMIC_HPP +# define CPPAD_CORE_NEW_DYNAMIC_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-18 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +/* +$begin new_dynamic$$ +$spell + const + Taylor + cpp + dyn + ind +$$ + +$section Change the Dynamic Parameters$$ + +$head Syntax$$ +$icode%f%.new_dynamic(%dynamic%)%$$ + +$head Purpose$$ +Often one is only interested in computing derivatives with respect +to a subset of arguments to a function. +In this case, it is easier to make all the arguments to the function +$cref/independent variables/glossary/Tape/Independent Variable/$$. +It is more efficient, +will use less memory and be faster, +if the only the argument were are computing derivatives with respect to +are independent variables and the other arguments are +$cref/dynamic/glossary/Parameter/Dynamic/$$ parameters. +The $code new_dynamic$$ method is used to change the value +of the dynamic parameters in $icode f$$. + +$head f$$ +The object $icode f$$ has prototype +$codei% + ADFun<%Base%> %f% +%$$ +Note that the $cref ADFun$$ object $icode f$$ is not $code const$$. + +$head dynamic$$ +This argument has prototype +$codei% + const %BaseVector%& %dynamic% +%$$ +(see $icode BaseVector$$ below). +It specifies a new value for the independent +$cref/dynamic/glossary/Parameter/Dynamic/$$ parameters. +It size must be the same as the size of the independent +$cref/dynamic/Independent/dynamic/$$ parameter vector +in the call to $code Independent$$ that started +the recording for $icode f$$; see +$cref/size_dyn_ind/seq_property/size_dyn_ind/$$. + +$head BaseVector$$ +The type $icode BaseVector$$ must be a $cref SimpleVector$$ class with +$cref/elements of type/SimpleVector/Elements of Specified Type/$$ +$icode Base$$. + +$head Taylor Coefficients$$ +The Taylor coefficients computed by previous calls to +$cref/f.Forward/Forward/$$ are lost after this operation; including the +order zero coefficients (because they may depend on the dynamic parameters). +In order words; +$cref/f.size_order/size_order/$$ returns zero directly after +$icode%f%.new_dynamic%$$ is called. + +$children% + example/general/new_dynamic.cpp +%$$ +$head Example$$ +The file $cref new_dynamic.cpp$$ +contains an example and test of this operation. + +$end +*/ +# include + +namespace CppAD { // BEGIN_CPPAD_NAMESPACE +/*! +\file new_dynamic.hpp +User interface to ADFun dynamic_parameter member function. +*/ + +/*! +Change the dynamic parameters in this ADFun object + +\param dynamic +is the vector of new values for the dynamic parameters. +*/ +template +template +void ADFun::new_dynamic(const BaseVector& dynamic) +{ using local::pod_vector; + CPPAD_ASSERT_KNOWN( + size_t( dynamic.size() ) == play_.num_dynamic_ind() , + "f.new_dynamic: dynamic.size() different from corresponding " + "call to Independent" + ); + // check BaseVector is Simple Vector class with Base elements + CheckSimpleVector(); + + // retrieve player information about the dynamic parameters + local::pod_vector_maybe& all_par_vec( play_.all_par_vec() ); + const pod_vector& dyn_par_is ( play_.dyn_par_is() ); + const pod_vector& dyn_par_op ( play_.dyn_par_op() ); + const pod_vector& dyn_par_arg( play_.dyn_par_arg() ); + const pod_vector& dyn_ind2par_ind ( play_.dyn_ind2par_ind() ); + + // set the dependent dynamic parameters + RecBase not_used_rec_base(0.0); + local::sweep::dynamic( + all_par_vec , + dynamic , + dyn_par_is , + dyn_ind2par_ind , + dyn_par_op , + dyn_par_arg , + not_used_rec_base + ); + + // the existing Taylor coefficients are no longer valid + num_order_taylor_ = 0; + + return; +} + + +} // END_CPPAD_NAMESPACE +# endif diff --git a/build-config/cppad/include/cppad/core/num_skip.hpp b/build-config/cppad/include/cppad/core/num_skip.hpp new file mode 100644 index 00000000..2d0697bb --- /dev/null +++ b/build-config/cppad/include/cppad/core/num_skip.hpp @@ -0,0 +1,124 @@ +# ifndef CPPAD_CORE_NUM_SKIP_HPP +# define CPPAD_CORE_NUM_SKIP_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-18 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +/* +$begin number_skip$$ +$spell + optimizer + var + taylor_ +$$ + + +$section Number of Variables that Can be Skipped$$ + +$head Syntax$$ +$icode%n% = %f%.number_skip()%$$ + +$subhead See Also$$ +$cref seq_property$$ + +$head Purpose$$ +The $cref/conditional expressions/CondExp/$$ use either the +$cref/if_true/CondExp/$$ or $cref/if_false/CondExp/$$. +Hence, some terms only need to be evaluated +depending on the value of the comparison in the conditional expression. +The $cref optimize$$ option is capable of detecting some of these +case and determining variables that can be skipped. +This routine returns the number such variables. + +$head n$$ +The return value $icode n$$ has type $code size_t$$ +is the number of variables that the optimizer has determined can be skipped +(given the independent variable values specified by the previous call to +$cref/f.Forward/Forward/$$ for order zero). + +$head f$$ +The object $icode f$$ has prototype +$codei% + ADFun<%Base%> %f% +%$$ + +$children% + example/general/number_skip.cpp +%$$ +$head Example$$ +The file $cref number_skip.cpp$$ +contains an example and test of this function. + +$end +----------------------------------------------------------------------------- +*/ + +# include + +// BEGIN CppAD namespace +namespace CppAD { + +// This routine is not const because it runs through the operations sequence +// 2DO: compute this value during zero order forward operations. +template +size_t ADFun::number_skip(void) +{ // must pass through operation sequence to map operations to variables + + // information defined by atomic forward + size_t atom_index=0, atom_old=0, atom_m=0, atom_n=0; + + // number of variables skipped + size_t num_var_skip = 0; + + // start playback + local::play::const_sequential_iterator itr = play_.begin(); + local::OpCode op; + size_t i_var; + const addr_t* arg; + itr.op_info(op, arg, i_var); + CPPAD_ASSERT_UNKNOWN(op == local::BeginOp) + while(op != local::EndOp) + { // next op + (++itr).op_info(op, arg, i_var); + // + if( op == local::AFunOp ) + { // skip only appears at front or back AFunOp of atomic function call + bool skip_call = cskip_op_[ itr.op_index() ]; + local::play::atom_op_info( + op, arg, atom_index, atom_old, atom_m, atom_n + ); + CPPAD_ASSERT_UNKNOWN( NumRes(op) == 0 ); + size_t num_op = atom_m + atom_n + 1; + for(size_t i = 0; i < num_op; i++) + { CPPAD_ASSERT_UNKNOWN( + op != local::CSkipOp && op != local::CSumOp + ); + (++itr).op_info(op, arg, i_var); + if( skip_call ) + num_var_skip += NumRes(op); + } + CPPAD_ASSERT_UNKNOWN( op == local::AFunOp ); + } + else + { if( cskip_op_[ itr.op_index() ] ) + num_var_skip += NumRes(op); + // + if( (op == local::CSkipOp) | (op == local::CSumOp) ) + itr.correct_before_increment(); + } + } + return num_var_skip; +} + +} // END CppAD namespace + + +# endif diff --git a/build-config/cppad/include/cppad/core/numeric_limits.hpp b/build-config/cppad/include/cppad/core/numeric_limits.hpp new file mode 100644 index 00000000..c96e020b --- /dev/null +++ b/build-config/cppad/include/cppad/core/numeric_limits.hpp @@ -0,0 +1,215 @@ +# ifndef CPPAD_CORE_NUMERIC_LIMITS_HPP +# define CPPAD_CORE_NUMERIC_LIMITS_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-18 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +/* +------------------------------------------------------------------------------ +$begin numeric_limits$$ +$spell + std + eps + CppAD + namespace + const +$$ + +$section Numeric Limits For an AD and Base Types$$ + +$head Syntax$$ +$icode%eps% = numeric_limits<%Float%>::epsilon() +%$$ +$icode%min% = numeric_limits<%Float%>::min() +%$$ +$icode%max% = numeric_limits<%Float%>::max() +%$$ +$icode%nan% = numeric_limits<%Float%>::quiet_NaN() +%$$ +$codei%numeric_limits<%Float%>::digits10%$$ + +$head CppAD::numeric_limits$$ +These functions and have the prototype +$codei% + static %Float% CppAD::numeric_limits<%Float%>::%fun%(%void%) +%$$ +where $icode fun$$ is +$code epsilon$$, $code min$$, $code max$$, and $code quiet_NaN$$. +(Note that $code digits10$$ is member variable and not a function.) + +$head std::numeric_limits$$ +CppAD does not use a specialization of $code std::numeric_limits$$ +because this would be to restrictive. +The C++ standard specifies that Non-fundamental standard +types, such as +$cref/std::complex/base_complex.hpp/$$ shall not have specializations +of $code std::numeric_limits$$; see Section 18.2 of +ISO/IEC 14882:1998(E). +In addition, since C++11, a only literal types can have a specialization +of $code std::numeric_limits$$. + +$head Float$$ +These functions are defined for all $codei%AD<%Base%>%$$, +and for all corresponding $icode Base$$ types; +see $icode Base$$ type $cref base_limits$$. + +$head epsilon$$ +The result $icode eps$$ is equal to machine epsilon and has prototype +$codei% + %Float% %eps% +%$$ +The file $cref num_limits.cpp$$ +tests the value $icode eps$$ by checking that the following are true +$codei% + 1 != 1 + %eps% + 1 == 1 + %eps% / 2 +%$$ +where all the values, and calculations, are done with the precision +corresponding to $icode Float$$. + +$head min$$ +The result $icode min$$ is equal to +the minimum positive normalized value and has prototype +$codei% + %Float% %min% +%$$ +The file $cref num_limits.cpp$$ +tests the value $icode min$$ by checking that the following are true +$codei% + abs( ((%min% / 100) * 100) / %min% - 1 ) > 3 * %eps% + abs( ((%min% * 100) / 100) / %min% - 1 ) < 3 * %eps% +%$$ +where all the values, and calculations, are done with the precision +corresponding to $icode Float$$. + +$head max$$ +The result $icode max$$ is equal to +the maximum finite value and has prototype +$codei% + %Float% %max% +%$$ +The file $cref num_limits.cpp$$ +tests the value $icode max$$ by checking that the following are true +$codei% + abs( ((%max% * 100) / 100) / %max% - 1 ) > 3 * %eps% + abs( ((%max% / 100) * 100) / %max% - 1 ) < 3 * %eps% +%$$ +where all the values, and calculations, are done with the precision +corresponding to $icode Float$$. + +$head quiet_NaN$$ +The result $icode nan$$ is not a number and has prototype +$codei% + %Float% %nan% +%$$ +The file $cref num_limits.cpp$$ +tests the value $icode nan$$ by checking that the following is true +$codei% + %nan% != %nan% +%$$ + +$head digits10$$ +The member variable $code digits10$$ has prototype +$codei% + static const int numeric_limits<%Float%>::digits10 +%$$ +It is the number of decimal digits that can be represented by a +$icode Float$$ value. A number with this many decimal digits can be +converted to $icode Float$$ and back to a string, +without change due to rounding or overflow. + + +$head Example$$ +$children% + example/general/num_limits.cpp +%$$ +The file +$cref num_limits.cpp$$ +contains an example and test of these functions. + +$end +------------------------------------------------------------------------------ +*/ +# include + +# include +# include +# include +# include + +namespace CppAD { // BEGIN_CPPAD_NAMESPACE +/*! +\file numeric_limits.hpp +File that defines CppAD numeric_limits for AD types +*/ + +/// All tthese defaults correspond to errors +template +class numeric_limits { +public: + /// machine epsilon + static Float epsilon(void) + { CPPAD_ASSERT_KNOWN( + false, + "numeric_limits::epsilon() is not specialized for this Float" + ); + return Float(0); + } + /// minimum positive normalized value + static Float min(void) + { CPPAD_ASSERT_KNOWN( + false, + "numeric_limits::min() is not specialized for this Float" + ); + return Float(0); + } + /// maximum finite value + static Float max(void) + { CPPAD_ASSERT_KNOWN( + false, + "numeric_limits::max() is not specialized for this Float" + ); + return Float(0); + } + /// not a number + static Float quiet_NaN(void) + { CPPAD_ASSERT_KNOWN( + false, + "numeric_limits::quiet_NaN() is not specialized for this Float" + ); + return Float(0); + } + /// number of decimal digits + static const int digits10 = -1; +}; + +/// Partial specialization that defines limits for for all AD types +template +class numeric_limits< AD > { +public: + /// machine epsilon + static AD epsilon(void) + { return AD( numeric_limits::epsilon() ); } + /// minimum positive normalized value + static AD min(void) + { return AD( numeric_limits::min() ); } + /// maximum finite value + static AD max(void) + { return AD( numeric_limits::max() ); } + /// not a number + static AD quiet_NaN(void) + { return AD( numeric_limits::quiet_NaN() ); } + /// number of decimal digits + static const int digits10 = numeric_limits::digits10; +}; + +} // END_CPPAD_NAMESPACE +# endif diff --git a/build-config/cppad/include/cppad/core/omp_max_thread.hpp b/build-config/cppad/include/cppad/core/omp_max_thread.hpp new file mode 100644 index 00000000..200f2153 --- /dev/null +++ b/build-config/cppad/include/cppad/core/omp_max_thread.hpp @@ -0,0 +1,93 @@ +# ifndef CPPAD_CORE_OMP_MAX_THREAD_HPP +# define CPPAD_CORE_OMP_MAX_THREAD_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-16 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ +/* +$begin omp_max_thread$$ +$spell + alloc + num + omp + OpenMp + CppAD +$$ + +$section OpenMP Parallel Setup$$ + +$head Deprecated 2011-06-23$$ +Use $cref/thread_alloc::parallel_setup/ta_parallel_setup/$$ +to set the number of threads. + +$head Syntax$$ +$codei%AD<%Base%>::omp_max_thread(%number%) +%$$ + +$head Purpose$$ +By default, for each $codei%AD<%Base%>%$$ class there is only one +tape that records $cref/AD of Base/glossary/AD of Base/$$ operations. +This tape is a global variable and hence it cannot be used +by multiple OpenMP threads at the same time. +The $code omp_max_thread$$ function is used to set the +maximum number of OpenMP threads that can be active. +In this case, there is a different tape corresponding to each +$codei%AD<%Base%>%$$ class and thread pair. + +$head number$$ +The argument $icode number$$ has prototype +$codei% + size_t %number% +%$$ +It must be greater than zero and specifies the maximum number of +OpenMp threads that will be active at one time. + + +$head Independent$$ +Each call to $cref/Independent(x)/Independent/$$ +creates a new $cref/active/glossary/Tape/Active/$$ tape. +All of the operations with the corresponding variables +must be preformed by the same OpenMP thread. +This includes the corresponding call to +$cref/f.Dependent(x,y)/Dependent/$$ or the +$cref/ADFun f(x, y)/FunConstruct/Sequence Constructor/$$ +during which the tape stops recording and the variables +become parameters. + +$head Restriction$$ +No tapes can be +$cref/active/glossary/Tape/Active/$$ when this function is called. + +$end +----------------------------------------------------------------------------- +*/ + +// BEGIN CppAD namespace +namespace CppAD { + +template +void AD::omp_max_thread(size_t number) +{ +# ifdef _OPENMP + thread_alloc::parallel_setup( + number, omp_alloc::in_parallel, omp_alloc::get_thread_num + ); +# else + CPPAD_ASSERT_KNOWN( + number == 1, + "omp_max_thread: number > 1 and _OPENMP is not defined" + ); +# endif + parallel_ad(); +} + +} // END CppAD namespace + +# endif diff --git a/build-config/cppad/include/cppad/core/opt_val_hes.hpp b/build-config/cppad/include/cppad/core/opt_val_hes.hpp new file mode 100644 index 00000000..b57f8e75 --- /dev/null +++ b/build-config/cppad/include/cppad/core/opt_val_hes.hpp @@ -0,0 +1,522 @@ +# ifndef CPPAD_CORE_OPT_VAL_HES_HPP +# define CPPAD_CORE_OPT_VAL_HES_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-17 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ +/* +$begin opt_val_hes$$ +$spell + hes + sy + Jacobian + hes + signdet + jac + Bradley + const + CppAD +$$ + + + +$section Jacobian and Hessian of Optimal Values$$ + +$head Syntax$$ +$icode%signdet% = opt_val_hes(%x%, %y%, %fun%, %jac%, %hes%)%$$ + +$head See Also$$ +$cref BenderQuad$$ + +$head Reference$$ +Algorithmic differentiation of implicit functions and optimal values, +Bradley M. Bell and James V. Burke, Advances in Automatic Differentiation, +2008, Springer. + +$head Purpose$$ +We are given a function +$latex S : \B{R}^n \times \B{R}^m \rightarrow \B{R}^\ell$$ +and we define $latex F : \B{R}^n \times \B{R}^m \rightarrow \B{R}$$ +and $latex V : \B{R}^n \rightarrow \B{R} $$ by +$latex \[ +\begin{array}{rcl} + F(x, y) & = & \sum_{k=0}^{\ell-1} S_k ( x , y) + \\ + V(x) & = & F [ x , Y(x) ] + \\ + 0 & = & \partial_y F [x , Y(x) ] +\end{array} +\] $$ +We wish to compute the Jacobian +and possibly also the Hessian, of $latex V (x)$$. + +$head BaseVector$$ +The type $icode BaseVector$$ must be a +$cref SimpleVector$$ class. +We use $icode Base$$ to refer to the type of the elements of +$icode BaseVector$$; i.e., +$codei% + %BaseVector%::value_type +%$$ + +$head x$$ +The argument $icode x$$ has prototype +$codei% + const %BaseVector%& %x% +%$$ +and its size must be equal to $icode n$$. +It specifies the point at which we evaluating +the Jacobian $latex V^{(1)} (x)$$ +(and possibly the Hessian $latex V^{(2)} (x)$$). + + +$head y$$ +The argument $icode y$$ has prototype +$codei% + const %BaseVector%& %y% +%$$ +and its size must be equal to $icode m$$. +It must be equal to $latex Y(x)$$; i.e., +it must solve the implicit equation +$latex \[ + 0 = \partial_y F ( x , y) +\] $$ + +$head Fun$$ +The argument $icode fun$$ is an object of type $icode Fun$$ +which must support the member functions listed below. +CppAD will may be recording operations of the type $codei%AD<%Base%>%$$ +when these member functions are called. +These member functions must not stop such a recording; e.g., +they must not call $cref/AD::abort_recording/abort_recording/$$. + +$subhead Fun::ad_vector$$ +The type $icode%Fun%::ad_vector%$$ must be a +$cref SimpleVector$$ class with elements of type $codei%AD<%Base%>%$$; i.e. +$codei% + %Fun%::ad_vector::value_type +%$$ +is equal to $codei%AD<%Base%>%$$. + +$subhead fun.ell$$ +The type $icode Fun$$ must support the syntax +$codei% + %ell% = %fun%.ell() +%$$ +where $icode ell$$ has prototype +$codei% + size_t %ell% +%$$ +and is the value of $latex \ell$$; i.e., +the number of terms in the summation. +$pre + +$$ +One can choose $icode ell$$ equal to one, and have +$latex S(x,y)$$ the same as $latex F(x, y)$$. +Each of the functions $latex S_k (x , y)$$, +(in the summation defining $latex F(x, y)$$) +is differentiated separately using AD. +For very large problems, breaking $latex F(x, y)$$ into the sum +of separate simpler functions may reduce the amount of memory necessary for +algorithmic differentiation and there by speed up the process. + +$subhead fun.s$$ +The type $icode Fun$$ must support the syntax +$codei% + %s_k% = %fun%.s(%k%, %x%, %y%) +%$$ +The $icode%fun%.s%$$ argument $icode k$$ has prototype +$codei% + size_t %k% +%$$ +and is between zero and $icode%ell% - 1%$$. +The argument $icode x$$ to $icode%fun%.s%$$ has prototype +$codei% + const %Fun%::ad_vector& %x% +%$$ +and its size must be equal to $icode n$$. +The argument $icode y$$ to $icode%fun%.s%$$ has prototype +$codei% + const %Fun%::ad_vector& %y% +%$$ +and its size must be equal to $icode m$$. +The $icode%fun%.s%$$ result $icode s_k$$ has prototype +$codei% + AD<%Base%> %s_k% +%$$ +and its value must be given by $latex s_k = S_k ( x , y )$$. + +$subhead fun.sy$$ +The type $icode Fun$$ must support the syntax +$codei% + %sy_k% = %fun%.sy(%k%, %x%, %y%) +%$$ +The argument $icode k$$ to $icode%fun%.sy%$$ has prototype +$codei% + size_t %k% +%$$ +The argument $icode x$$ to $icode%fun%.sy%$$ has prototype +$codei% + const %Fun%::ad_vector& %x% +%$$ +and its size must be equal to $icode n$$. +The argument $icode y$$ to $icode%fun%.sy%$$ has prototype +$codei% + const %Fun%::ad_vector& %y% +%$$ +and its size must be equal to $icode m$$. +The $icode%fun%.sy%$$ result $icode sy_k$$ has prototype +$codei% + %Fun%::ad_vector %sy_k% +%$$ +its size must be equal to $icode m$$, +and its value must be given by $latex sy_k = \partial_y S_k ( x , y )$$. + +$head jac$$ +The argument $icode jac$$ has prototype +$codei% + %BaseVector%& %jac% +%$$ +and has size $icode n$$ or zero. +The input values of its elements do not matter. +If it has size zero, it is not affected. Otherwise, on output +it contains the Jacobian of $latex V (x)$$; i.e., +for $latex j = 0 , \ldots , n-1$$, +$latex \[ + jac[ j ] = V^{(1)} (x)_j +\] $$ +where $icode x$$ is the first argument to $code opt_val_hes$$. + +$head hes$$ +The argument $icode hes$$ has prototype +$codei% + %BaseVector%& %hes% +%$$ +and has size $icode%n% * %n%$$ or zero. +The input values of its elements do not matter. +If it has size zero, it is not affected. Otherwise, on output +it contains the Hessian of $latex V (x)$$; i.e., +for $latex i = 0 , \ldots , n-1$$, and +$latex j = 0 , \ldots , n-1$$, +$latex \[ + hes[ i * n + j ] = V^{(2)} (x)_{i,j} +\] $$ + + +$head signdet$$ +If $icode%hes%$$ has size zero, $icode signdet$$ is not defined. +Otherwise +the return value $icode signdet$$ is the sign of the determinant for +$latex \partial_{yy}^2 F(x , y) $$. +If it is zero, then the matrix is singular and +the Hessian is not computed ($icode hes$$ is not changed). + +$head Example$$ +$children% + example/general/opt_val_hes.cpp +%$$ +The file +$cref opt_val_hes.cpp$$ +contains an example and test of this operation. + +$end +----------------------------------------------------------------------------- +*/ + +namespace CppAD { // BEGIN_CPPAD_NAMESPACE +/*! +\file opt_val_hes.hpp +\brief Computing Jabobians and Hessians of Optimal Values +*/ + +/*! +Computing Jabobians and Hessians of Optimal Values + +We are given a function +\f$ S : {\rm R}^n \times {\rm R}^m \rightarrow {\rm R}^\ell \f$ +and we define \f$ F : {\rm R}^n \times {\rm R}^m \rightarrow {\rm R} \f$ +and \f$ V : {\rm R}^n \rightarrow {\rm R} \f$ by +\f[ +\begin{array}{rcl} + F(x, y) & = & \sum_{k=0}^{\ell-1} S_k ( x , y) + \\ + V(x) & = & F [ x , Y(x) ] + \\ + 0 & = & \partial_y F [x , Y(x) ] +\end{array} +\f] +We wish to compute the Jacobian +and possibly also the Hessian, of \f$ V (x) \f$. + +\tparam BaseVector +The type BaseVector must be a SimpleVector class. +We use Base to refer to the type of the elements of + BaseVector; i.e., +BaseVector::value_type. + +\param x +is a vector with size n. +It specifies the point at which we evaluating +the Jacobian \f$ V^{(1)} (x) \f$ +(and possibly the Hessian \f$ V^{(2)} (x) \f$). + + +\param y +is a vector with size m. +It must be equal to \f$ Y(x) \f$; i.e., +it must solve the implicit equation +\f[ + 0 = \partial_y F ( x , y) +\f] + +\param fun +The argument fun is an object of type Fun +wich must support the member functions listed below. +CppAD will may be recording operations of the type AD +when these member functions are called. +These member functions must not stop such a recording; e.g., +they must not call AD::abort_recording. + +\par Fun::ad_vector +The type Fun::ad_vector must be a +SimpleVector class with elements of type AD; i.e. +Fun::ad_vector::value_type +is equal to AD. + +\par fun.ell +the type Fun must support the syntax +\verbatim + ell = fun.ell() +\endverbatim +where ell is a size_t value that is set to \f$ \ell \f$; i.e., +the number of terms in the summation. + +\par fun.s +The type Fun must support the syntax +\verbatim + s_k = fun.s(k, x, y) +\endverbatim +The argument k has prototype size_t k. +The argument x has prototype const Fun::ad_vector& x +and its size must be equal to n. +The argument y has prototype const Fun::ad_vector& y +and its size must be equal to m. +The return value s_k has prototype AD s_k +and its value must be given by \f$ s_k = S_k ( x , y ) \f$. + +\par fun.sy +The type Fun must support the syntax +\verbatim + sy_k = fun.sy(k, x, y) +\endverbatim +The argument k has prototype size_t k. +The argument x has prototype const Fun::ad_vector& x +and its size must be equal to n. +The argument y has prototype const Fun::ad_vector& y +and its size must be equal to m. +The return value sy_k has prototype Fun::ad_vector& sy_k, +its size is m +and its value must be given by \f$ sy_k = \partial_y S_k ( x , y ) \f$. + +\param jac +is a vector with size n or zero. +The input values of its elements do not matter. +If it has size zero, it is not affected. Otherwise, on output +it contains the Jacobian of \f$ V (x) \f$; i.e., +for \f$ j = 0 , \ldots , n-1 \f$, +\f[ + jac[ j ] = V^{(1)} (x)_j +\f] $$ +where x is the first argument to opt_val_hes. + +\param hes +is a vector with size n * n or zero. +The input values of its elements do not matter. +If it has size zero, it is not affected. Otherwise, on output +it contains the Hessian of \f$ V (x) \f$; i.e., +for \f$ i = 0 , \ldots , n-1 \f$, and +\f$ j = 0 , \ldots , n-1 \f$, +\f[ + hes[ i * n + j ] = V^{(2)} (x)_{i,j} +\f] + +\return +If hes.size() == 0, the return value is not defined. +Otherwise, +the return value is the sign of the determinant for +\f$ \partial_{yy}^2 F(x , y) \f$$. +If it is zero, then the matrix is singular and hes is not set +to its specified value. +*/ + + +template +int opt_val_hes( + const BaseVector& x , + const BaseVector& y , + Fun fun , + BaseVector& jac , + BaseVector& hes ) +{ // determine the base type + typedef typename BaseVector::value_type Base; + + // check that BaseVector is a SimpleVector class with Base elements + CheckSimpleVector(); + + // determine the AD vector type + typedef typename Fun::ad_vector ad_vector; + + // check that ad_vector is a SimpleVector class with AD elements + CheckSimpleVector< AD , ad_vector >(); + + // size of the x and y spaces + size_t n = size_t(x.size()); + size_t m = size_t(y.size()); + + // number of terms in the summation + size_t ell = fun.ell(); + + // check size of return values + CPPAD_ASSERT_KNOWN( + size_t(jac.size()) == n || jac.size() == 0, + "opt_val_hes: size of the vector jac is not equal to n or zero" + ); + CPPAD_ASSERT_KNOWN( + size_t(hes.size()) == n * n || hes.size() == 0, + "opt_val_hes: size of the vector hes is not equal to n * n or zero" + ); + + // some temporary indices + size_t i, j, k; + + // AD version of S_k(x, y) + ad_vector s_k(1); + + // ADFun version of S_k(x, y) + ADFun S_k; + + // AD version of x + ad_vector a_x(n); + + // AD version of y + ad_vector a_y(n); + + if( jac.size() > 0 ) + { // this is the easy part, computing the V^{(1)} (x) which is equal + // to \partial_x F (x, y) (see Thoerem 2 of the reference). + + // copy x and y to AD version + for(j = 0; j < n; j++) + a_x[j] = x[j]; + for(j = 0; j < m; j++) + a_y[j] = y[j]; + + // initialize summation + for(j = 0; j < n; j++) + jac[j] = Base(0.); + + // add in \partial_x S_k (x, y) + for(k = 0; k < ell; k++) + { // start recording + Independent(a_x); + // record + s_k[0] = fun.s(k, a_x, a_y); + // stop recording and store in S_k + S_k.Dependent(a_x, s_k); + // compute partial of S_k with respect to x + BaseVector jac_k = S_k.Jacobian(x); + // add \partial_x S_k (x, y) to jac + for(j = 0; j < n; j++) + jac[j] += jac_k[j]; + } + } + // check if we are done + if( hes.size() == 0 ) + return 0; + + /* + In this case, we need to compute the Hessian. Using Theorem 1 of the + reference: + Y^{(1)}(x) = - F_yy (x, y)^{-1} F_yx (x, y) + Using Theorem 2 of the reference: + V^{(2)}(x) = F_xx (x, y) + F_xy (x, y) Y^{(1)}(x) + */ + // Base and AD version of xy + BaseVector xy(n + m); + ad_vector a_xy(n + m); + for(j = 0; j < n; j++) + a_xy[j] = xy[j] = x[j]; + for(j = 0; j < m; j++) + a_xy[n+j] = xy[n+j] = y[j]; + + // Initialization summation for Hessian of F + size_t nm_sq = (n + m) * (n + m); + BaseVector F_hes(nm_sq); + for(j = 0; j < nm_sq; j++) + F_hes[j] = Base(0.); + BaseVector hes_k(nm_sq); + + // add in Hessian of S_k to hes + for(k = 0; k < ell; k++) + { // start recording + Independent(a_xy); + // split out x + for(j = 0; j < n; j++) + a_x[j] = a_xy[j]; + // split out y + for(j = 0; j < m; j++) + a_y[j] = a_xy[n+j]; + // record + s_k[0] = fun.s(k, a_x, a_y); + // stop recording and store in S_k + S_k.Dependent(a_xy, s_k); + // when computing the Hessian it pays to optimize the tape + S_k.optimize(); + // compute Hessian of S_k + hes_k = S_k.Hessian(xy, 0); + // add \partial_x S_k (x, y) to jac + for(j = 0; j < nm_sq; j++) + F_hes[j] += hes_k[j]; + } + // Extract F_yx + BaseVector F_yx(m * n); + for(i = 0; i < m; i++) + { for(j = 0; j < n; j++) + F_yx[i * n + j] = F_hes[ (i+n)*(n+m) + j ]; + } + // Extract F_yy + BaseVector F_yy(n * m); + for(i = 0; i < m; i++) + { for(j = 0; j < m; j++) + F_yy[i * m + j] = F_hes[ (i+n)*(n+m) + j + n ]; + } + + // compute - Y^{(1)}(x) = F_yy (x, y)^{-1} F_yx (x, y) + BaseVector neg_Y_x(m * n); + Base logdet; + int signdet = CppAD::LuSolve(m, n, F_yy, F_yx, neg_Y_x, logdet); + if( signdet == 0 ) + return signdet; + + // compute hes = F_xx (x, y) + F_xy (x, y) Y^{(1)}(x) + for(i = 0; i < n; i++) + { for(j = 0; j < n; j++) + { hes[i * n + j] = F_hes[ i*(n+m) + j ]; + for(k = 0; k < m; k++) + hes[i*n+j] -= F_hes[i*(n+m) + k+n] * neg_Y_x[k*n+j]; + } + } + return signdet; +} + +} // END_CPPAD_NAMESPACE + +# endif diff --git a/build-config/cppad/include/cppad/core/optimize.hpp b/build-config/cppad/include/cppad/core/optimize.hpp new file mode 100644 index 00000000..67f4e41a --- /dev/null +++ b/build-config/cppad/include/cppad/core/optimize.hpp @@ -0,0 +1,376 @@ +# ifndef CPPAD_CORE_OPTIMIZE_HPP +# define CPPAD_CORE_OPTIMIZE_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +# define CPPAD_CORE_OPTIMIZE_PRINT_RESULT 0 + +/* +$begin optimize$$ +$spell + enum + jac + bool + Taylor + CppAD + cppad + std + const + onetape + op + optimizer +$$ + +$section Optimize an ADFun Object Tape$$ + + +$head Syntax$$ +$icode%f%.optimize() +%$$ +$icode%f%.optimize(%options%) +%$$ +$icode%flag% = %f%.exceed_collision_limit() +%$$ + +$head Purpose$$ +The operation sequence corresponding to an $cref ADFun$$ object can +be very large and involve many operations; see the +size functions in $cref seq_property$$. +The $icode%f%.optimize%$$ procedure reduces the number of operations, +and thereby the time and the memory, required to +compute function and derivative values. + +$head f$$ +The object $icode f$$ has prototype +$codei% + ADFun<%Base%> %f% +%$$ + +$head options$$ +This argument has prototype +$codei% + const std::string& %options% +%$$ +The default for $icode options$$ is the empty string. +If it is present, it must consist of one or more of the options below +separated by a single space character. + +$subhead no_conditional_skip$$ +The $code optimize$$ function can create conditional skip operators +to improve the speed of conditional expressions; see +$cref/optimize/CondExp/Optimize/$$. +If the sub-string $code no_conditional_skip$$ appears in $icode options$$, +conditional skip operations are not be generated. +This may make the optimize routine use significantly less memory +and take less time to optimize $icode f$$. +If conditional skip operations are generated, +it may save a significant amount of time when +using $icode f$$ for $cref forward$$ or $cref reverse$$ mode calculations; +see $cref number_skip$$. + +$subhead no_compare_op$$ +If the sub-string $code no_compare_op$$ appears in $icode options$$, +comparison operators will be removed from the optimized function. +These operators are necessary for the +$cref compare_change$$ functions to be meaningful. +On the other hand, they are not necessary, and take extra time, +when the compare_change functions are not used. + +$subhead no_print_for_op$$ +If the sub-string $code no_compare_op$$ appears in $icode options$$, +$cref PrintFor$$ operations will be removed form the optimized function. +These operators are useful for reporting problems evaluating derivatives +at independent variable values different from those used to record a function. + +$subhead no_cumulative_sum_op$$ +If this sub-string appears, +no cumulative sum operations will be generated during the optimization; see +$cref optimize_cumulative_sum.cpp$$. + +$subhead collision_limit=value$$ +If this substring appears, +where $icode value$$ is a sequence of decimal digits, +the optimizer's hash code collision limit will be set to $icode value$$. +When the collision limit is reached, the expressions with that hash code +are removed and a new lists of expressions with that has code is started. +The larger $icode value$$, the more identical expressions the optimizer +can recognize, but the slower the optimizer may run. +The default for $icode value$$ is $code 10$$. + +$head Re-Optimize$$ +Before 2019-06-28, optimizing twice was not supported and would fail +if cumulative sum operators were present after the first optimization. +This is now supported but it is not expected to have much benefit. +If you find a case where it does have a benefit, please inform the CppAD +developers of this. + +$head Efficiency$$ +If a $cref/zero order forward/forward_zero/$$ calculation is done during +the construction of $icode f$$, it will require more memory +and time than required after the optimization procedure. +In addition, it will need to be redone. +For this reason, it is more efficient to use +$codei% + ADFun<%Base%> %f%; + %f%.Dependent(%x%, %y%); + %f%.optimize(); +%$$ +instead of +$codei% + ADFun<%Base%> %f%(%x%, %y%) + %f%.optimize(); +%$$ +See the discussion about +$cref/sequence constructors/FunConstruct/Sequence Constructor/$$. + +$head Taylor Coefficients$$ +Any Taylor coefficients in the function object are lost; i.e., +$cref/f.size_order()/size_order/$$ after the optimization is zero. +(See the discussion about efficiency above.) + +$head Speed Testing$$ +You can run the CppAD $cref/speed/speed_main/$$ tests and see +the corresponding changes in number of variables and execution time. +Note that there is an interaction between using +$cref/optimize/speed_main/Global Options/optimize/$$ and +$cref/onetape/speed_main/Global Options/onetape/$$. +If $icode onetape$$ is true and $icode optimize$$ is true, +the optimized tape will be reused many times. +If $icode onetape$$ is false and $icode optimize$$ is true, +the tape will be re-optimized for each test. + +$head Atomic Functions$$ +There are some subtitle issue with optimized $cref atomic$$ functions +$latex v = g(u)$$: + +$subhead rev_sparse_jac$$ +The $cref atomic_two_rev_sparse_jac$$ function is be used to determine +which components of $icode u$$ affect the dependent variables of $icode f$$. +For each atomic operation, the current +$cref/atomic_sparsity/atomic_two_option/atomic_sparsity/$$ setting is used +to determine if $code pack_sparsity_enum$$, $code bool_sparsity_enum$$, +or $code set_sparsity_enum$$ is used to determine dependency relations +between argument and result variables. + +$subhead nan$$ +If $icode%u%[%i%]%$$ does not affect the value of +the dependent variables for $icode f$$, +the value of $icode%u%[%i%]%$$ is set to $cref nan$$. + +$head Checking Optimization$$ +If $cref/NDEBUG/Faq/Speed/NDEBUG/$$ is not defined, +and $cref/f.size_order()/size_order/$$ is greater than zero, +a $cref forward_zero$$ calculation is done using the optimized version +of $icode f$$ and the results are checked to see that they are +the same as before. +If they are not the same, the +$cref ErrorHandler$$ is called with a known error message +related to $icode%f%.optimize()%$$. + +$head exceed_collision_limit$$ +If the return value $icode flag$$ is true (false), +the previous call to $icode%f%.optimize%$$ exceed the +$cref/collision_limit/optimize/options/collision_limit=value/$$. + +$head Examples$$ +$comment childtable without Example instead of Contents for header$$ +$children% + example/optimize/optimize_twice.cpp + %example/optimize/forward_active.cpp + %example/optimize/reverse_active.cpp + %example/optimize/compare_op.cpp + %example/optimize/print_for.cpp + %example/optimize/conditional_skip.cpp + %example/optimize/nest_conditional.cpp + %example/optimize/cumulative_sum.cpp +%$$ +$table +$rref optimize_twice.cpp$$ +$rref optimize_forward_active.cpp$$ +$rref optimize_reverse_active.cpp$$ +$rref optimize_compare_op.cpp$$ +$rref optimize_print_for.cpp$$ +$rref optimize_conditional_skip.cpp$$ +$rref optimize_nest_conditional.cpp$$ +$rref optimize_cumulative_sum.cpp$$ +$tend + +$end +----------------------------------------------------------------------------- +*/ +# include +/*! +\file optimize.hpp +Optimize a player object operation sequence +*/ +namespace CppAD { // BEGIN_CPPAD_NAMESPACE +/*! +Optimize a player object operation sequence + +The operation sequence for this object is replaced by one with fewer operations +but the same funcition and derivative values. + +\tparam Base +base type for the operator; i.e., this operation was recorded +using AD and computations by this routine are done using type + Base. + +\param options +\li +If the sub-string "no_conditional_skip" appears, +conditional skip operations will not be generated. +This may make the optimize routine use significantly less memory +and take significantly less time. +\li +If the sub-string "no_compare_op" appears, +then comparison operators will be removed from the optimized tape. +These operators are necessary for the compare_change function to be +be meaningful in the resulting recording. +On the other hand, they are not necessary and take extra time +when compare_change is not used. +*/ +template +void ADFun::optimize(const std::string& options) +{ +# if CPPAD_CORE_OPTIMIZE_PRINT_RESULT + // size of operation sequence before optimizatiton + size_t size_op_before = size_op(); +# endif + + // place to store the optimized version of the recording + local::recorder rec; + + // number of independent variables + size_t n = ind_taddr_.size(); + +# ifndef NDEBUG + size_t i, j, m = dep_taddr_.size(); + CppAD::vector x(n), y(m), check(m); + Base max_taylor(0); + bool check_zero_order = num_order_taylor_ > 0; + if( check_zero_order ) + { // zero order coefficients for independent vars + for(j = 0; j < n; j++) + { CPPAD_ASSERT_UNKNOWN( play_.GetOp(j+1) == local::InvOp ); + CPPAD_ASSERT_UNKNOWN( ind_taddr_[j] == j+1 ); + x[j] = taylor_[ ind_taddr_[j] * cap_order_taylor_ + 0]; + } + // zero order coefficients for dependent vars + for(i = 0; i < m; i++) + { CPPAD_ASSERT_UNKNOWN( dep_taddr_[i] < num_var_tape_ ); + y[i] = taylor_[ dep_taddr_[i] * cap_order_taylor_ + 0]; + } + // maximum zero order coefficient not counting BeginOp at beginning + // (which is correpsonds to uninitialized memory). + for(i = 1; i < num_var_tape_; i++) + { if( abs_geq(taylor_[i*cap_order_taylor_+0] , max_taylor) ) + max_taylor = taylor_[i*cap_order_taylor_+0]; + } + } +# endif + + // create the optimized recording + size_t exceed = false; + switch( play_.address_type() ) + { + case local::play::unsigned_short_enum: + exceed = local::optimize::optimize_run( + options, n, dep_taddr_, &play_, &rec + ); + break; + + case local::play::unsigned_int_enum: + exceed = local::optimize::optimize_run( + options, n, dep_taddr_, &play_, &rec + ); + break; + + case local::play::size_t_enum: + exceed = local::optimize::optimize_run( + options, n, dep_taddr_, &play_, &rec + ); + break; + + default: + CPPAD_ASSERT_UNKNOWN(false); + } + exceed_collision_limit_ = exceed; + + // number of variables in the recording + num_var_tape_ = rec.num_var_rec(); + + // now replace the recording + play_.get_recording(rec, n); + + // set flag so this function knows it has been optimized + has_been_optimized_ = true; + + // free memory allocated for sparse Jacobian calculation + // (the results are no longer valid) + for_jac_sparse_pack_.resize(0, 0); + for_jac_sparse_set_.resize(0,0); + + // free old Taylor coefficient memory + taylor_.clear(); + num_order_taylor_ = 0; + cap_order_taylor_ = 0; + + // resize and initilaize conditional skip vector + // (must use player size because it now has the recoreder information) + cskip_op_.resize( play_.num_op_rec() ); + + // resize subgraph_info_ + subgraph_info_.resize( + ind_taddr_.size(), // n_ind + dep_taddr_.size(), // n_dep + play_.num_op_rec(), // n_op + play_.num_var_rec() // n_var + ); + +# ifndef NDEBUG + if( check_zero_order ) + { std::stringstream s; + // + // zero order forward calculation using new operation sequence + check = Forward(0, x, s); + + // check results + Base eps99 = Base(99) * CppAD::numeric_limits::epsilon(); + for(i = 0; i < m; i++) + if( ! abs_geq( eps99 * max_taylor , check[i] - y[i] ) ) + { std::string msg = "Error during check of f.optimize()."; + msg += "\neps99 * max_taylor = " + to_string(eps99 * max_taylor); + msg += "\ncheck[i] = " + to_string(check[i]); + msg += "\ny[i] = " + to_string(y[i]); + CPPAD_ASSERT_KNOWN( + abs_geq( eps99 * max_taylor , check[i] - y[i] ) , + msg.c_str() + ); + } + + // Erase memory that this calculation was done so NDEBUG gives + // same final state for this object (from users perspective) + num_order_taylor_ = 0; + } +# endif +# if CPPAD_CORE_OPTIMIZE_PRINT_RESULT + // size of operation sequence after optimizatiton + size_t size_op_after = size_op(); + std::cout << "optimize: size_op: before = " << + size_op_before << ", after = " << size_op_after << "\n"; +# endif +} + +} // END_CPPAD_NAMESPACE + +# undef CPPAD_CORE_OPTIMIZE_PRINT_RESULT +# endif diff --git a/build-config/cppad/include/cppad/core/ordered.hpp b/build-config/cppad/include/cppad/core/ordered.hpp new file mode 100644 index 00000000..4f08934c --- /dev/null +++ b/build-config/cppad/include/cppad/core/ordered.hpp @@ -0,0 +1,100 @@ +# ifndef CPPAD_CORE_ORDERED_HPP +# define CPPAD_CORE_ORDERED_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-18 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +# include + +namespace CppAD { // BEGIN_CPPAD_NAMESPACE + +/*! +\file ordered.hpp +Check and AD values ordering properties relative to zero. +*/ + +// GreaterThanZero ============================================================ +/*! +Check if an AD is greater than zero. + +\param x +value we are checking. + +\return +returns true iff the x is greater than zero. +*/ +template +CPPAD_INLINE_FRIEND_TEMPLATE_FUNCTION +bool GreaterThanZero(const AD &x) +{ return GreaterThanZero(x.value_); } +// GreaterThanOrZero ========================================================= +/*! +Check if an AD is greater than or equal zero. + +\param x +value we are checking. + +\return +returns true iff the x is greater than or equal zero. +*/ +template +CPPAD_INLINE_FRIEND_TEMPLATE_FUNCTION +bool GreaterThanOrZero(const AD &x) +{ return GreaterThanOrZero(x.value_); } +// LessThanZero ============================================================ +/*! +Check if an AD is less than zero. + +\param x +value we are checking. + +\return +returns true iff the x is less than zero. +*/ +template +CPPAD_INLINE_FRIEND_TEMPLATE_FUNCTION +bool LessThanZero(const AD &x) +{ return LessThanZero(x.value_); } +// LessThanOrZero ========================================================= +/*! +Check if an AD is less than or equal zero. + +\param x +value we are checking. + +\return +returns true iff the x is less than or equal zero. +*/ +template +CPPAD_INLINE_FRIEND_TEMPLATE_FUNCTION +bool LessThanOrZero(const AD &x) +{ return LessThanOrZero(x.value_); } +// abs_geq ========================================================= +/*! +Check if absolute value of one AD is greater or equal another. + +\param x +value we are checking if it is greater than or equal other. + +\param y +value we are checking if it is less than other. + +\return +returns true iff the absolute value of x is greater than or equal +absolute value of y. +*/ +template +CPPAD_INLINE_FRIEND_TEMPLATE_FUNCTION +bool abs_geq(const AD& x, const AD& y) +{ return abs_geq(x.value_, y.value_); } +// ============================================================================ +} // END_CPPAD_NAMESPACE +# endif diff --git a/build-config/cppad/include/cppad/core/parallel_ad.hpp b/build-config/cppad/include/cppad/core/parallel_ad.hpp new file mode 100644 index 00000000..34b3a52a --- /dev/null +++ b/build-config/cppad/include/cppad/core/parallel_ad.hpp @@ -0,0 +1,117 @@ +# ifndef CPPAD_CORE_PARALLEL_AD_HPP +# define CPPAD_CORE_PARALLEL_AD_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ +/* +$begin parallel_ad$$ +$spell + CppAD + num + std +$$ + +$section Enable AD Calculations During Parallel Mode$$ + +$head Syntax$$ +$codei%parallel_ad<%Base%>()%$$ + +$head Purpose$$ +The function +$codei%parallel_ad<%Base%>()%$$ +must be called before any $codei%AD<%Base>%$$ objects are used +in $cref/parallel/ta_in_parallel/$$ mode. +In addition, if this routine is called after one is done using +parallel mode, it will free extra memory used to keep track of +the multiple $codei%AD<%Base%>%$$ tapes required for parallel execution. + +$head Discussion$$ +By default, for each $codei%AD<%Base%>%$$ class there is only one +tape that records $cref/AD of Base/glossary/AD of Base/$$ operations. +This tape is a global variable and hence it cannot be used +by multiple threads at the same time. +The $cref/parallel_setup/ta_parallel_setup/$$ function informs CppAD of the +maximum number of threads that can be active in parallel mode. +This routine does extra setup +(and teardown) for the particular $icode Base$$ type. + +$head CheckSimpleVector$$ +This routine has the side effect of calling the routines +$codei% + CheckSimpleVector< %Type%, CppAD::vector<%Type%> >() +%$$ +where $icode Type$$ is $icode Base$$ and $codei%AD<%Base%>%$$. + +$head Example$$ +The files +$cref team_openmp.cpp$$, +$cref team_bthread.cpp$$, and +$cref team_pthread.cpp$$, +contain examples and tests that implement this function. + +$head Restriction$$ +This routine cannot be called in parallel mode or while +there is a tape recording $codei%AD<%Base%>%$$ operations. + +$end +----------------------------------------------------------------------------- +*/ + +# include + +// BEGIN CppAD namespace +namespace CppAD { + +/*! +Enable parallel execution mode with AD by initializing +static variables that my be used. +*/ + +template +void parallel_ad(void) +{ CPPAD_ASSERT_KNOWN( + ! thread_alloc::in_parallel() , + "parallel_ad must be called before entering parallel execution mode." + ); + CPPAD_ASSERT_KNOWN( + AD::tape_ptr() == nullptr , + "parallel_ad cannot be called while a tape recording is in progress" + ); + + // ensure statics in following functions are initialized + elapsed_seconds(); + ErrorHandler::Current(); + local::NumArg(local::BeginOp); + local::NumRes(local::BeginOp); + local::one_element_std_set(); + local::two_element_std_set(); + + // the sparse_pack class has member functions with static data + local::sparse::pack_setvec sp; + sp.resize(1, 1); // so can call add_element + sp.add_element(0, 0); // has static data + sp.clear(0); // has static data + sp.is_element(0, 0); // has static data + local::sparse::pack_setvec::const_iterator itr(sp, 0); // has static data + ++itr; // has static data + + // statics that depend on the value of Base + AD::tape_id_ptr(0); + AD::tape_handle(0); + discrete::List(); + CheckSimpleVector< Base, CppAD::vector >(); + CheckSimpleVector< AD, CppAD::vector< AD > >(); + +} + +} // END CppAD namespace + +# endif diff --git a/build-config/cppad/include/cppad/core/pow.hpp b/build-config/cppad/include/cppad/core/pow.hpp new file mode 100644 index 00000000..5f510c67 --- /dev/null +++ b/build-config/cppad/include/cppad/core/pow.hpp @@ -0,0 +1,295 @@ +# ifndef CPPAD_CORE_POW_HPP +# define CPPAD_CORE_POW_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +/* +$begin pow$$ +$spell + Vec + std + namespace + CppAD + const +$$ + + +$section The AD Power Function$$ + +$head Syntax$$ +$icode%z% = pow(%x%, %y%)%$$ + +$head See Also$$ +$cref pow_int$$ + + +$head Purpose$$ +Determines the value of the power function which is defined by +$latex \[ + {\rm pow} (x, y) = x^y +\] $$ +This version of the $code pow$$ function may use +logarithms and exponentiation to compute derivatives. +This will not work if $icode x$$ is less than or equal zero. +If the value of $icode y$$ is an integer, +the $cref pow_int$$ function is used to compute this value +using only multiplication (and division if $icode y$$ is negative). +(This will work even if $icode x$$ is less than or equal zero.) + +$head x$$ +The argument $icode x$$ has one of the following prototypes +$codei% + const %Base%& %x% + const AD<%Base%>& %x% + const VecAD<%Base%>::reference& %x% +%$$ + +$head y$$ +The argument $icode y$$ has one of the following prototypes +$codei% + const %Base%& %y% + const AD<%Base%>& %y% + const VecAD<%Base%>::reference& %y% +%$$ + +$head z$$ +If both $icode x$$ and $icode y$$ are $icode Base$$ objects, +the result $icode z$$ is also a $icode Base$$ object. +Otherwise, it has prototype +$codei% + AD<%Base%> %z% +%$$ + +$head Operation Sequence$$ +This is an AD of $icode Base$$ +$cref/atomic operation/glossary/Operation/Atomic/$$ +and hence is part of the current +AD of $icode Base$$ +$cref/operation sequence/glossary/Operation/Sequence/$$. + +$head Example$$ +$children% + example/general/pow.cpp +%$$ +The file +$cref pow.cpp$$ +is an examples and tests of this function. + +$end +------------------------------------------------------------------------------- +*/ + +// BEGIN CppAD namespace +namespace CppAD { + +// case where x and y are AD ----------------------------------------- +template AD +pow(const AD& x, const AD& y) +{ + // compute the Base part + AD result; + result.value_ = pow(x.value_, y.value_); + CPPAD_ASSERT_UNKNOWN( Parameter(result) ); + + // check if there is a recording in progress + local::ADTape* tape = AD::tape_ptr(); + if( tape == nullptr ) + return result; + tape_id_t tape_id = tape->id_; + // tape_id cannot match the default value for tape_id_; i.e., 0 + CPPAD_ASSERT_UNKNOWN( tape_id > 0 ); + + // check if x and y tapes match + bool match_x = x.tape_id_ == tape_id; + bool match_y = y.tape_id_ == tape_id; + + // check if x and y are dynamic parameters + bool dyn_x = match_x & (x.ad_type_ == dynamic_enum); + bool dyn_y = match_y & (y.ad_type_ == dynamic_enum); + + // check if x and y are variables + bool var_x = match_x & (x.ad_type_ != dynamic_enum); + bool var_y = match_y & (y.ad_type_ != dynamic_enum); + + CPPAD_ASSERT_KNOWN( + x.tape_id_ == y.tape_id_ || ! match_x || ! match_y , + "pow: AD variables or dynamic parameters on different threads." + ); + if( var_x ) + { if( var_y ) + { // result = variable^variable + CPPAD_ASSERT_UNKNOWN( local::NumRes(local::PowvvOp) == 3 ); + CPPAD_ASSERT_UNKNOWN( local::NumArg(local::PowvvOp) == 2 ); + + // put operand addresses in tape + tape->Rec_.PutArg(x.taddr_, y.taddr_); + + // put operator in the tape + result.taddr_ = tape->Rec_.PutOp(local::PowvvOp); + + // make result a variable + result.tape_id_ = tape_id; + result.ad_type_ = variable_enum; + } + else if( IdenticalZero( y.value_ ) ) + { // result = variable^0 + } + else + { // result = variable^parameter + CPPAD_ASSERT_UNKNOWN( local::NumRes(local::PowvpOp) == 3 ); + CPPAD_ASSERT_UNKNOWN( local::NumArg(local::PowvpOp) == 2 ); + + // put operand addresses in tape + addr_t p = y.taddr_; + if( ! dyn_y ) + p = tape->Rec_.put_con_par(y.value_); + tape->Rec_.PutArg(x.taddr_, p); + + // put operator in the tape + result.taddr_ = tape->Rec_.PutOp(local::PowvpOp); + + // make result a variable + result.tape_id_ = tape_id; + result.ad_type_ = variable_enum; + } + } + else if( var_y ) + { if( IdenticalZero(x.value_) ) + { // result = 0^variable + } + else + { // result = parameter^variable + CPPAD_ASSERT_UNKNOWN( local::NumRes(local::PowpvOp) == 3 ); + CPPAD_ASSERT_UNKNOWN( local::NumArg(local::PowpvOp) == 2 ); + + // put operand addresses in tape + addr_t p = x.taddr_; + if( ! dyn_x ) + p = tape->Rec_.put_con_par(x.value_); + tape->Rec_.PutArg(p, y.taddr_); + + // put operator in the tape + result.taddr_ = tape->Rec_.PutOp(local::PowpvOp); + + // make result a variable + result.tape_id_ = tape_id; + result.ad_type_ = variable_enum; + } + } + else if( dyn_x | dyn_y ) + { addr_t arg0 = x.taddr_; + addr_t arg1 = y.taddr_; + if( ! dyn_x ) + arg0 = tape->Rec_.put_con_par(x.value_); + if( ! dyn_y ) + arg1 = tape->Rec_.put_con_par(y.value_); + // + // parameters with a dynamic parameter result + result.taddr_ = tape->Rec_.put_dyn_par( + result.value_, local::pow_dyn, arg0, arg1 + ); + result.tape_id_ = tape_id; + result.ad_type_ = dynamic_enum; + } + else + { CPPAD_ASSERT_KNOWN( ! (dyn_x | dyn_y) , + "pow: one operand is a dynamic parameter and other not a variable" + ); + } + return result; +} +// ========================================================================= +// Fold operations in same way as CPPAD_FOLD_AD_VALUED_BINARY_OPERATOR(Op) +// ------------------------------------------------------------------------- +// Operations with VecAD_reference and AD only + +template AD +pow(const AD& x, const VecAD_reference& y) +{ return pow(x, y.ADBase()); } + +template AD +pow(const VecAD_reference& x, const VecAD_reference& y) +{ return pow(x.ADBase(), y.ADBase()); } + +template AD +pow(const VecAD_reference& x, const AD& y) +{ return pow(x.ADBase(), y); } +// ------------------------------------------------------------------------- +// Operations with Base + +template AD +pow(const Base& x, const AD& y) +{ return pow(AD(x), y); } + +template AD +pow(const Base& x, const VecAD_reference& y) +{ return pow(AD(x), y.ADBase()); } + +template AD +pow(const AD& x, const Base& y) +{ return pow(x, AD(y)); } + +template AD +pow(const VecAD_reference& x, const Base& y) +{ return pow(x.ADBase(), AD(y)); } +// ------------------------------------------------------------------------- +// Operations with double + +template AD +pow(const double& x, const AD& y) +{ return pow(AD(x), y); } + +template AD +pow(const double& x, const VecAD_reference& y) +{ return pow(AD(x), y.ADBase()); } + +template AD +pow(const AD& x, const double& y) +{ return pow(x, AD(y)); } + +template AD +pow(const VecAD_reference& x, const double& y) +{ return pow(x.ADBase(), AD(y)); } +// ------------------------------------------------------------------------- +// Special case to avoid ambuigity when Base is double + +inline AD +pow(const double& x, const AD& y) +{ return pow(AD(x), y); } + +inline AD +pow(const double& x, const VecAD_reference& y) +{ return pow(AD(x), y.ADBase()); } + +inline AD +pow(const AD& x, const double& y) +{ return pow(x, AD(y)); } + +inline AD +pow(const VecAD_reference& x, const double& y) +{ return pow(x.ADBase(), AD(y)); } + +// ========================================================================= +// Fold operations for the cases where x is an int, +// but let cppad/utility/pow_int.hpp handle the cases where y is an int. +// ------------------------------------------------------------------------- +template AD pow +(const int& x, const VecAD_reference& y) +{ return pow(AD(x), y.ADBase()); } + +template AD pow +(const int& x, const AD& y) +{ return pow(AD(x), y); } + +} // END CppAD namespace + +# endif diff --git a/build-config/cppad/include/cppad/core/print_for.hpp b/build-config/cppad/include/cppad/core/print_for.hpp new file mode 100644 index 00000000..01eaad6d --- /dev/null +++ b/build-config/cppad/include/cppad/core/print_for.hpp @@ -0,0 +1,228 @@ +# ifndef CPPAD_CORE_PRINT_FOR_HPP +# define CPPAD_CORE_PRINT_FOR_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +/* +$begin PrintFor$$ +$spell + notpos + var + VecAD + std + cout + const +$$ + + +$section Printing AD Values During Forward Mode$$ + +$head Syntax$$ +$icode%f%.Forward(0, %x%) +%$$ +$icode%f%.Forward(0, %x%, %s%) +%$$ +$codei%PrintFor(%before%, %value%) +%$$ +$codei%PrintFor(%notpos%, %before%, %value%, %after%) +%$$ + +$head See Also$$ +$cref ad_output$$ + +$head Purpose$$ +The $cref/zero order forward/forward_zero/$$ mode command +$codei% + %f%.Forward(0, %x%) +%$$ +sets the +$cref/independent variable/glossary/Tape/Independent Variable/$$ vector +equal to $icode x$$. +It then computes a value for all of the dependent variables in the +$cref/operation sequence/glossary/Operation/Sequence/$$ corresponding +to $icode f$$. +Putting a $code PrintFor$$ in the operation sequence, +prints $icode value$$, corresponding to $icode x$$, +to be printed during zero order forward operations. + +$head f.Forward(0, x)$$ +The objects $icode f$$, $icode x$$, and the purpose +for this operation, are documented in $cref Forward$$. + +$head notpos$$ +If present, the argument $icode notpos$$ has one of the following prototypes +$codei% + const AD<%Base%>& %notpos% + const VecAD<%Base%>::reference& %notpos% +%$$ +In this case +the text and $icode value$$ will be printed if and only if +$icode notpos$$ is not positive (greater than zero) and a finite number. + +$head before$$ +The argument $icode before$$ has prototype +$codei% + const char* %before% +%$$ +This text is written to $code std::cout$$ before $icode value$$. + +$head value$$ +The argument $icode value$$ has one of the following prototypes +$codei% + const AD<%Base%>& %value% + const VecAD<%Base%>::reference& %value% +%$$ +The $icode value$$, that corresponds to $icode x$$, +is written to $code std::cout$$ during the execution of +$codei% + %f%.Forward(0, %x%) +%$$ +Note that $icode value$$ may be a +$cref/variable/glossary/Variable/$$ or +$cref/parameter/glossary/Parameter/$$. +If a parameter is +$cref/dynamic/glossary/Parameter/Dynamic/$$ its value +will depend on the previous call to $cref new_dynamic$$. + +$head after$$ +The argument $icode after$$ has prototype +$codei% + const char* %after% +%$$ +This text is written to $code std::cout$$ after $icode value$$. + +$head s$$ +You can redirect this output to any standard output stream using the syntax +$codei% + %f%.Forward(0, %x%, %s%) +%$$ +see $cref/s/forward_zero/s/$$ in the zero order forward mode documentation. + +$head Discussion$$ +This is helpful for understanding why tape evaluations have trouble. +For example, if one of the operations in $icode f$$ is +$codei%log(%value%)%$$ and $icode%value% < 0%$$, +the corresponding result will $cref nan$$. + +$head Example$$ +$children% + example/print_for/print_for.cpp% + example/general/print_for.cpp +%$$ +The program +$cref print_for_cout.cpp$$ +is an example and test that prints to standard output. +The output of this program +states the conditions for passing and failing the test. +The function +$cref print_for_string.cpp$$ +is an example and test that prints to an standard string stream. +This function automatically check for correct output. + +$end +------------------------------------------------------------------------------ +*/ + +# include + +namespace CppAD { + template + void PrintFor( + const AD& notpos , + const char* before , + const AD& value , + const char* after ) + { CPPAD_ASSERT_NARG_NRES(local::PriOp, 5, 0); + + // check for case where we are not recording operations + local::ADTape* tape = AD::tape_ptr(); + if( tape == nullptr ) + return; + + CPPAD_ASSERT_KNOWN( + std::strlen(before) <= 1000 , + "PrintFor: length of before is greater than 1000 characters" + ); + CPPAD_ASSERT_KNOWN( + std::strlen(after) <= 1000 , + "PrintFor: length of after is greater than 1000 characters" + ); + addr_t arg0, arg1, arg2, arg3, arg4; + + // arg[0] = base 2 representation of [Var(notpos), Var(value)] + arg0 = 0; + + // arg[1] = address for notpos + if( Constant(notpos) ) + arg1 = tape->Rec_.put_con_par(notpos.value_); + else if( Dynamic(notpos) ) + arg1 = notpos.taddr_; + else + { arg0 += 1; + arg1 = notpos.taddr_; + } + + // arg[2] = address of before + arg2 = tape->Rec_.PutTxt(before); + + // arg[3] = address for value + if( Constant(value) ) + arg3 = tape->Rec_.put_con_par(value.value_); + else if( Dynamic(value) ) + arg3 = value.taddr_; + else + { arg0 += 2; + arg3 = value.taddr_; + } + + // arg[4] = address of after + arg4 = tape->Rec_.PutTxt(after); + + // put the operator in the tape + tape->Rec_.PutArg(arg0, arg1, arg2, arg3, arg4); + tape->Rec_.PutOp(local::PriOp); + } + // Fold all other cases into the case above + template + void PrintFor(const char* before, const AD& value) + { PrintFor(AD(0), before, value, "" ); } + // + template + void PrintFor(const char* before, const VecAD_reference& value) + { PrintFor(AD(0), before, value.ADBase(), "" ); } + // + template + void PrintFor( + const VecAD_reference& notpos , + const char *before , + const VecAD_reference& value , + const char *after ) + { PrintFor(notpos.ADBase(), before, value.ADBase(), after); } + // + template + void PrintFor( + const VecAD_reference& notpos , + const char *before , + const AD& value , + const char *after ) + { PrintFor(notpos.ADBase(), before, value, after); } + // + template + void PrintFor( + const AD& notpos , + const char *before , + const VecAD_reference& value , + const char *after ) + { PrintFor(notpos, before, value.ADBase(), after); } +} + +# endif diff --git a/build-config/cppad/include/cppad/core/rev_hes_sparsity.hpp b/build-config/cppad/include/cppad/core/rev_hes_sparsity.hpp new file mode 100644 index 00000000..4bac9e41 --- /dev/null +++ b/build-config/cppad/include/cppad/core/rev_hes_sparsity.hpp @@ -0,0 +1,253 @@ +# ifndef CPPAD_CORE_REV_HES_SPARSITY_HPP +# define CPPAD_CORE_REV_HES_SPARSITY_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ +/* +$begin rev_hes_sparsity$$ +$spell + Jacobian + Hessian + jac + hes + bool + const + rc + cpp +$$ + +$section Reverse Mode Hessian Sparsity Patterns$$ + +$head Syntax$$ +$icode%f%.rev_hes_sparsity( + %select_range%, %transpose%, %internal_bool%, %pattern_out% +)%$$ + +$head Purpose$$ +We use $latex F : \B{R}^n \rightarrow \B{R}^m$$ to denote the +$cref/AD function/glossary/AD Function/$$ corresponding to +the operation sequence stored in $icode f$$. +Fix $latex R \in \B{R}^{n \times \ell}$$, $latex s \in \B{R}^m$$ +and define the function +$latex \[ + H(x) = ( s^\R{T} F )^{(2)} ( x ) R +\] $$ +Given a $cref/sparsity pattern/glossary/Sparsity Pattern/$$ for $latex R$$ +and for the vector $latex s$$, +$code rev_hes_sparsity$$ computes a sparsity pattern for $latex H(x)$$. + +$head x$$ +Note that the sparsity pattern $latex H(x)$$ corresponds to the +operation sequence stored in $icode f$$ and does not depend on +the argument $icode x$$. + +$head BoolVector$$ +The type $icode BoolVector$$ is a $cref SimpleVector$$ class with +$cref/elements of type/SimpleVector/Elements of Specified Type/$$ +$code bool$$. + +$head SizeVector$$ +The type $icode SizeVector$$ is a $cref SimpleVector$$ class with +$cref/elements of type/SimpleVector/Elements of Specified Type/$$ +$code size_t$$. + +$head f$$ +The object $icode f$$ has prototype +$codei% + ADFun<%Base%> %f% +%$$ + +$head R$$ +The sparsity pattern for the matrix $latex R$$ is specified by +$cref/pattern_in/for_jac_sparsity/pattern_in/$$ in the previous call +$codei% + %f%.for_jac_sparsity( + %pattern_in%, %transpose%, %dependency%, %internal_bool%, %pattern_out% +)%$$ + +$head select_range$$ +The argument $icode select_range$$ has prototype +$codei% + const %BoolVector%& %select_range% +%$$ +It has size $latex m$$ and specifies which components of the vector +$latex s$$ are non-zero; i.e., $icode%select_range%[%i%]%$$ is true +if and only if $latex s_i$$ is possibly non-zero. + +$head transpose$$ +This argument has prototype +$codei% + bool %transpose% +%$$ +See $cref/pattern_out/rev_hes_sparsity/pattern_out/$$ below. + +$head internal_bool$$ +If this is true, calculations are done with sets represented by a vector +of boolean values. Otherwise, a vector of sets of integers is used. +This must be the same as in the previous call to +$icode%f%.for_jac_sparsity%$$. + +$head pattern_out$$ +This argument has prototype +$codei% + sparse_rc<%SizeVector%>& %pattern_out% +%$$ +This input value of $icode pattern_out$$ does not matter. +If $icode transpose$$ it is false (true), +upon return $icode pattern_out$$ is a sparsity pattern for +$latex H(x)$$ ($latex H(x)^\R{T}$$). + +$head Sparsity for Entire Hessian$$ +Suppose that $latex R$$ is the $latex n \times n$$ identity matrix. +In this case, $icode pattern_out$$ is a sparsity pattern for +$latex (s^\R{T} F) F^{(2)} ( x )$$. + +$head Example$$ +$children% + example/sparse/rev_hes_sparsity.cpp +%$$ +The file +$cref rev_hes_sparsity.cpp$$ +contains an example and test of this operation. + +$end +----------------------------------------------------------------------------- +*/ +# include +# include + +namespace CppAD { // BEGIN_CPPAD_NAMESPACE + +/*! +Reverse Hessian sparsity patterns. + +\tparam Base +is the base type for this recording. + +\tparam BoolVector +is the simple vector with elements of type bool that is used for +sparsity for the vector s. + +\tparam SizeVector +is the simple vector with elements of type size_t that is used for +row, column index sparsity patterns. + +\param select_range +is a sparsity pattern for for s. + +\param transpose +Is the returned sparsity pattern transposed. + +\param internal_bool +If this is true, calculations are done with sets represented by a vector +of boolean values. Otherwise, a vector of standard sets is used. + +\param pattern_out +The value of transpose is false (true), +the return value is a sparsity pattern for H(x) ( H(x)^T ) where +\f[ + H(x) = R * F^{(1)} (x) +\f] +Here F is the function corresponding to the operation sequence +and x is any argument value. +*/ +template +template +void ADFun::rev_hes_sparsity( + const BoolVector& select_range , + bool transpose , + bool internal_bool , + sparse_rc& pattern_out ) +{ + // used to identify the RecBase type in calls to sweeps + RecBase not_used_rec_base(0.0); + // + size_t n = Domain(); + size_t m = Range(); + // + CPPAD_ASSERT_KNOWN( + size_t( select_range.size() ) == m, + "rev_hes_sparsity: size of select_range is not equal to " + "number of dependent variables" + ); + // + // vector that holds reverse Jacobian sparsity flag + local::pod_vector rev_jac_pattern(num_var_tape_); + for(size_t i = 0; i < num_var_tape_; i++) + rev_jac_pattern[i] = false; + // + // initialize rev_jac_pattern for dependent variables + for(size_t i = 0; i < m; i++) + rev_jac_pattern[ dep_taddr_[i] ] = select_range[i]; + // + // + if( internal_bool ) + { CPPAD_ASSERT_KNOWN( + for_jac_sparse_pack_.n_set() > 0, + "rev_hes_sparsity: previous call to for_jac_sparsity did not " + "use bool for interanl sparsity patterns." + ); + // column dimension of internal sparstiy pattern + size_t ell = for_jac_sparse_pack_.end(); + // + // allocate memory for bool sparsity calculation + // (sparsity pattern is emtpy after a resize) + local::sparse::pack_setvec internal_hes; + internal_hes.resize(num_var_tape_, ell); + // + // compute the Hessian sparsity pattern + local::sweep::rev_hes( + &play_, + n, + num_var_tape_, + for_jac_sparse_pack_, + rev_jac_pattern.data(), + internal_hes, + not_used_rec_base + ); + // get sparstiy pattern for independent variables + local::sparse::get_internal_pattern( + transpose, ind_taddr_, internal_hes, pattern_out + ); + } + else + { CPPAD_ASSERT_KNOWN( + for_jac_sparse_set_.n_set() > 0, + "rev_hes_sparsity: previous call to for_jac_sparsity did not " + "use bool for interanl sparsity patterns." + ); + // column dimension of internal sparstiy pattern + size_t ell = for_jac_sparse_set_.end(); + // + // allocate memory for bool sparsity calculation + // (sparsity pattern is emtpy after a resize) + local::sparse::list_setvec internal_hes; + internal_hes.resize(num_var_tape_, ell); + // + // compute the Hessian sparsity pattern + local::sweep::rev_hes( + &play_, + n, + num_var_tape_, + for_jac_sparse_set_, + rev_jac_pattern.data(), + internal_hes, + not_used_rec_base + ); + // get sparstiy pattern for independent variables + local::sparse::get_internal_pattern( + transpose, ind_taddr_, internal_hes, pattern_out + ); + } + return; +} +} // END_CPPAD_NAMESPACE +# endif diff --git a/build-config/cppad/include/cppad/core/rev_jac_sparsity.hpp b/build-config/cppad/include/cppad/core/rev_jac_sparsity.hpp new file mode 100644 index 00000000..cc34d5f7 --- /dev/null +++ b/build-config/cppad/include/cppad/core/rev_jac_sparsity.hpp @@ -0,0 +1,258 @@ +# ifndef CPPAD_CORE_REV_JAC_SPARSITY_HPP +# define CPPAD_CORE_REV_JAC_SPARSITY_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ +/* +$begin rev_jac_sparsity$$ +$spell + Jacobian + jac + bool + const + rc + cpp +$$ + +$section Reverse Mode Jacobian Sparsity Patterns$$ + +$head Syntax$$ +$icode%f%.rev_jac_sparsity( + %pattern_in%, %transpose%, %dependency%, %internal_bool%, %pattern_out% +)%$$ + +$head Purpose$$ +We use $latex F : \B{R}^n \rightarrow \B{R}^m$$ to denote the +$cref/AD function/glossary/AD Function/$$ corresponding to +the operation sequence stored in $icode f$$. +Fix $latex R \in \B{R}^{\ell \times m}$$ and define the function +$latex \[ + J(x) = R * F^{(1)} ( x ) +\] $$ +Given the $cref/sparsity pattern/glossary/Sparsity Pattern/$$ for $latex R$$, +$code rev_jac_sparsity$$ computes a sparsity pattern for $latex J(x)$$. + +$head x$$ +Note that the sparsity pattern $latex J(x)$$ corresponds to the +operation sequence stored in $icode f$$ and does not depend on +the argument $icode x$$. +(The operation sequence may contain +$cref CondExp$$ and $cref VecAD$$ operations.) + +$head SizeVector$$ +The type $icode SizeVector$$ is a $cref SimpleVector$$ class with +$cref/elements of type/SimpleVector/Elements of Specified Type/$$ +$code size_t$$. + +$head f$$ +The object $icode f$$ has prototype +$codei% + ADFun<%Base%> %f% +%$$ + +$head pattern_in$$ +The argument $icode pattern_in$$ has prototype +$codei% + const sparse_rc<%SizeVector%>& %pattern_in% +%$$ +see $cref sparse_rc$$. +If $icode transpose$$ it is false (true), +$icode pattern_in$$ is a sparsity pattern for $latex R$$ ($latex R^\R{T}$$). + +$head transpose$$ +This argument has prototype +$codei% + bool %transpose% +%$$ +See $cref/pattern_in/rev_jac_sparsity/pattern_in/$$ above and +$cref/pattern_out/rev_jac_sparsity/pattern_out/$$ below. + +$head dependency$$ +This argument has prototype +$codei% + bool %dependency% +%$$ +see $cref/pattern_out/rev_jac_sparsity/pattern_out/$$ below. + +$head internal_bool$$ +If this is true, calculations are done with sets represented by a vector +of boolean values. Otherwise, a vector of sets of integers is used. + +$head pattern_out$$ +This argument has prototype +$codei% + sparse_rc<%SizeVector%>& %pattern_out% +%$$ +This input value of $icode pattern_out$$ does not matter. +If $icode transpose$$ it is false (true), +upon return $icode pattern_out$$ is a sparsity pattern for +$latex J(x)$$ ($latex J(x)^\R{T}$$). +If $icode dependency$$ is true, $icode pattern_out$$ is a +$cref/dependency pattern/dependency.cpp/Dependency Pattern/$$ +instead of sparsity pattern. + +$head Sparsity for Entire Jacobian$$ +Suppose that +$latex R$$ is the $latex m \times m$$ identity matrix. +In this case, $icode pattern_out$$ is a sparsity pattern for +$latex F^{(1)} ( x )$$ ( $latex F^{(1)} (x)^\R{T}$$ ) +if $icode transpose$$ is false (true). + +$head Example$$ +$children% + example/sparse/rev_jac_sparsity.cpp +%$$ +The file +$cref rev_jac_sparsity.cpp$$ +contains an example and test of this operation. + +$end +----------------------------------------------------------------------------- +*/ +# include +# include + +namespace CppAD { // BEGIN_CPPAD_NAMESPACE + +/*! +Reverse Jacobian sparsity patterns. + +\tparam Base +is the base type for this recording. + +\tparam SizeVector +is the simple vector with elements of type size_t that is used for +row, column index sparsity patterns. + +\param pattern_in +is the sparsity pattern for for R or R^T depending on transpose. + +\param transpose +Is the input and returned sparsity pattern transposed. + +\param dependency +Are the derivatives with respect to left and right of the expression below +considered to be non-zero: +\code + CondExpRel(left, right, if_true, if_false) +\endcode +This is used by the optimizer to obtain the correct dependency relations. + +\param internal_bool +If this is true, calculations are done with sets represented by a vector +of boolean values. Otherwise, a vector of standard sets is used. + +\param pattern_out +The value of transpose is false (true), +the return value is a sparsity pattern for J(x) ( J(x)^T ) where +\f[ + J(x) = R * F^{(1)} (x) +\f] +Here F is the function corresponding to the operation sequence +and x is any argument value. +*/ +template +template +void ADFun::rev_jac_sparsity( + const sparse_rc& pattern_in , + bool transpose , + bool dependency , + bool internal_bool , + sparse_rc& pattern_out ) +{ + // used to identify the RecBase type in calls to sweeps + RecBase not_used_rec_base(0.0); + // + // number or rows, columns, and non-zeros in pattern_in + size_t nr_in = pattern_in.nr(); + size_t nc_in = pattern_in.nc(); + // + size_t ell = nr_in; + size_t m = nc_in; + if( transpose ) + std::swap(ell, m); + // + CPPAD_ASSERT_KNOWN( + m == Range() , + "rev_jac_sparsity: number columns in R " + "is not equal number of dependent variables." + ); + // number of independent variables + size_t n = Domain(); + // + bool zero_empty = true; + bool input_empty = true; + if( internal_bool ) + { // allocate memory for bool sparsity calculation + // (sparsity pattern is emtpy after a resize) + local::sparse::pack_setvec internal_jac; + internal_jac.resize(num_var_tape_, ell); + // + // set sparsity patttern for dependent variables + local::sparse::set_internal_pattern( + zero_empty , + input_empty , + ! transpose , + dep_taddr_ , + internal_jac , + pattern_in + ); + + // compute sparsity for other variables + local::sweep::rev_jac( + &play_, + dependency, + n, + num_var_tape_, + internal_jac, + not_used_rec_base + + ); + // get sparstiy pattern for independent variables + local::sparse::get_internal_pattern( + ! transpose, ind_taddr_, internal_jac, pattern_out + ); + } + else + { // allocate memory for bool sparsity calculation + // (sparsity pattern is emtpy after a resize) + local::sparse::list_setvec internal_jac; + internal_jac.resize(num_var_tape_, ell); + // + // set sparsity patttern for dependent variables + local::sparse::set_internal_pattern( + zero_empty , + input_empty , + ! transpose , + dep_taddr_ , + internal_jac , + pattern_in + ); + + // compute sparsity for other variables + local::sweep::rev_jac( + &play_, + dependency, + n, + num_var_tape_, + internal_jac, + not_used_rec_base + + ); + // get sparstiy pattern for independent variables + local::sparse::get_internal_pattern( + ! transpose, ind_taddr_, internal_jac, pattern_out + ); + } + return; +} +} // END_CPPAD_NAMESPACE +# endif diff --git a/build-config/cppad/include/cppad/core/rev_one.hpp b/build-config/cppad/include/cppad/core/rev_one.hpp new file mode 100644 index 00000000..9c702b3c --- /dev/null +++ b/build-config/cppad/include/cppad/core/rev_one.hpp @@ -0,0 +1,161 @@ +# ifndef CPPAD_CORE_REV_ONE_HPP +# define CPPAD_CORE_REV_ONE_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-18 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +/* +$begin RevOne$$ +$spell + dw + Taylor + const +$$ + + + + +$section First Order Derivative: Driver Routine$$ + +$head Syntax$$ +$icode%dw% = %f%.RevOne(%x%, %i%)%$$ + + +$head Purpose$$ +We use $latex F : \B{R}^n \rightarrow \B{R}^m$$ to denote the +$cref/AD function/glossary/AD Function/$$ corresponding to $icode f$$. +The syntax above sets $icode dw$$ to the +derivative of $latex F_i$$ with respect to $latex x$$; i.e., +$latex \[ +dw = +F_i^{(1)} (x) += \left[ + \D{ F_i }{ x_0 } (x) , \cdots , \D{ F_i }{ x_{n-1} } (x) +\right] +\] $$ + +$head f$$ +The object $icode f$$ has prototype +$codei% + ADFun<%Base%> %f% +%$$ +Note that the $cref ADFun$$ object $icode f$$ is not $code const$$ +(see $cref/RevOne Uses Forward/RevOne/RevOne Uses Forward/$$ below). + +$head x$$ +The argument $icode x$$ has prototype +$codei% + const %Vector% &%x% +%$$ +(see $cref/Vector/RevOne/Vector/$$ below) +and its size +must be equal to $icode n$$, the dimension of the +$cref/domain/seq_property/Domain/$$ space for $icode f$$. +It specifies +that point at which to evaluate the derivative. + +$head i$$ +The index $icode i$$ has prototype +$codei% + size_t %i% +%$$ +and is less than $latex m$$, the dimension of the +$cref/range/seq_property/Range/$$ space for $icode f$$. +It specifies the +component of $latex F$$ that we are computing the derivative of. + +$head dw$$ +The result $icode dw$$ has prototype +$codei% + %Vector% %dw% +%$$ +(see $cref/Vector/RevOne/Vector/$$ below) +and its size is $icode n$$, the dimension of the +$cref/domain/seq_property/Domain/$$ space for $icode f$$. +The value of $icode dw$$ is the derivative of $latex F_i$$ +evaluated at $icode x$$; i.e., +for $latex j = 0 , \ldots , n - 1 $$ +$latex \[. + dw[ j ] = \D{ F_i }{ x_j } ( x ) +\] $$ + +$head Vector$$ +The type $icode Vector$$ must be a $cref SimpleVector$$ class with +$cref/elements of type/SimpleVector/Elements of Specified Type/$$ +$icode Base$$. +The routine $cref CheckSimpleVector$$ will generate an error message +if this is not the case. + +$head RevOne Uses Forward$$ +After each call to $cref Forward$$, +the object $icode f$$ contains the corresponding +$cref/Taylor coefficients/glossary/Taylor Coefficient/$$. +After a call to $code RevOne$$, +the zero order Taylor coefficients correspond to +$icode%f%.Forward(0, %x%)%$$ +and the other coefficients are unspecified. + +$head Example$$ +$children% + example/general/rev_one.cpp +%$$ +The routine +$cref/RevOne/rev_one.cpp/$$ is both an example and test. +It returns $code true$$, if it succeeds and $code false$$ otherwise. + +$end +----------------------------------------------------------------------------- +*/ + +// BEGIN CppAD namespace +namespace CppAD { + +template +template +Vector ADFun::RevOne(const Vector &x, size_t i) +{ size_t i1; + + size_t n = Domain(); + size_t m = Range(); + + // check Vector is Simple Vector class with Base type elements + CheckSimpleVector(); + + CPPAD_ASSERT_KNOWN( + x.size() == n, + "RevOne: Length of x not equal domain dimension for f" + ); + CPPAD_ASSERT_KNOWN( + i < m, + "RevOne: the index i is not less than range dimension for f" + ); + + // point at which we are evaluating the derivative + Forward(0, x); + + // component which are are taking the derivative of + Vector w(m); + for(i1 = 0; i1 < m; i1++) + w[i1] = 0.; + w[i] = Base(1.0); + + // dimension the return value + Vector dw(n); + + // compute the return value + dw = Reverse(1, w); + + return dw; +} + +} // END CppAD namespace + +# endif diff --git a/build-config/cppad/include/cppad/core/rev_sparse_hes.hpp b/build-config/cppad/include/cppad/core/rev_sparse_hes.hpp new file mode 100644 index 00000000..6e11d187 --- /dev/null +++ b/build-config/cppad/include/cppad/core/rev_sparse_hes.hpp @@ -0,0 +1,643 @@ +# ifndef CPPAD_CORE_REV_SPARSE_HES_HPP +# define CPPAD_CORE_REV_SPARSE_HES_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +/* +$begin RevSparseHes$$ +$spell + std + VecAD + Jacobian + Jac + Hessian + Hes + const + Bool + Dep + proportional + var + cpp +$$ + +$section Hessian Sparsity Pattern: Reverse Mode$$ + +$head Syntax$$ +$icode%h% = %f%.RevSparseHes(%q%, %s%) +%$$ +$icode%h% = %f%.RevSparseHes(%q%, %s%, %transpose%)%$$ + +$head Purpose$$ +We use $latex F : \B{R}^n \rightarrow \B{R}^m$$ to denote the +$cref/AD function/glossary/AD Function/$$ corresponding to $icode f$$. +For a fixed matrix $latex R \in \B{R}^{n \times q}$$ +and a fixed vector $latex S \in \B{R}^{1 \times m}$$, +we define +$latex \[ +\begin{array}{rcl} +H(x) +& = & \partial_x \left[ \partial_u S * F[ x + R * u ] \right]_{u=0} +\\ +& = & R^\R{T} * (S * F)^{(2)} ( x ) +\\ +H(x)^\R{T} +& = & (S * F)^{(2)} ( x ) * R +\end{array} +\] $$ +Given a +$cref/sparsity pattern/glossary/Sparsity Pattern/$$ +for the matrix $latex R$$ and the vector $latex S$$, +$code RevSparseHes$$ returns a sparsity pattern for the $latex H(x)$$. + +$head f$$ +The object $icode f$$ has prototype +$codei% + const ADFun<%Base%> %f% +%$$ + +$head x$$ +If the operation sequence in $icode f$$ is +$cref/independent/glossary/Operation/Independent/$$ of +the independent variables in $latex x \in \B{R}^n$$, +the sparsity pattern is valid for all values of +(even if it has $cref CondExp$$ or $cref VecAD$$ operations). + +$head q$$ +The argument $icode q$$ has prototype +$codei% + size_t %q% +%$$ +It specifies the number of columns in $latex R \in \B{R}^{n \times q}$$ +and the number of rows in $latex H(x) \in \B{R}^{q \times n}$$. +It must be the same value as in the previous $cref ForSparseJac$$ call +$codei% + %f%.ForSparseJac(%q%, %r%, %r_transpose%) +%$$ +Note that if $icode r_transpose$$ is true, $icode r$$ in the call above +corresponding to $latex R^\R{T} \in \B{R}^{q \times n}$$ + +$head transpose$$ +The argument $icode transpose$$ has prototype +$codei% + bool %transpose% +%$$ +The default value $code false$$ is used when $icode transpose$$ is not present. + + +$head r$$ +The matrix $latex R$$ is specified by the previous call +$codei% + %f%.ForSparseJac(%q%, %r%, %transpose%) +%$$ +see $cref/r/ForSparseJac/r/$$. +The type of the elements of +$cref/SetVector/RevSparseHes/SetVector/$$ must be the +same as the type of the elements of $icode r$$. + +$head s$$ +The argument $icode s$$ has prototype +$codei% + const %SetVector%& %s% +%$$ +(see $cref/SetVector/RevSparseHes/SetVector/$$ below) +If it has elements of type $code bool$$, +its size is $latex m$$. +If it has elements of type $code std::set$$, +its size is one and all the elements of $icode%s%[0]%$$ +are between zero and $latex m - 1$$. +It specifies a +$cref/sparsity pattern/glossary/Sparsity Pattern/$$ +for the vector $icode S$$. + +$head h$$ +The result $icode h$$ has prototype +$codei% + %SetVector%& %h% +%$$ +(see $cref/SetVector/RevSparseHes/SetVector/$$ below). + +$subhead transpose false$$ +If $icode h$$ has elements of type $code bool$$, +its size is $latex q * n$$. +If it has elements of type $code std::set$$, +its size is $latex q$$ and all the set elements are between +zero and $icode%n%-1%$$ inclusive. +It specifies a +$cref/sparsity pattern/glossary/Sparsity Pattern/$$ +for the matrix $latex H(x)$$. + +$subhead transpose true$$ +If $icode h$$ has elements of type $code bool$$, +its size is $latex n * q$$. +If it has elements of type $code std::set$$, +its size is $latex n$$ and all the set elements are between +zero and $icode%q%-1%$$ inclusive. +It specifies a +$cref/sparsity pattern/glossary/Sparsity Pattern/$$ +for the matrix $latex H(x)^\R{T}$$. + +$head SetVector$$ +The type $icode SetVector$$ must be a $cref SimpleVector$$ class with +$cref/elements of type/SimpleVector/Elements of Specified Type/$$ +$code bool$$ or $code std::set$$; +see $cref/sparsity pattern/glossary/Sparsity Pattern/$$ for a discussion +of the difference. +The type of the elements of +$cref/SetVector/RevSparseHes/SetVector/$$ must be the +same as the type of the elements of $icode r$$. + +$head Entire Sparsity Pattern$$ +Suppose that $latex q = n$$ and +$latex R \in \B{R}^{n \times n}$$ is the $latex n \times n$$ identity matrix. +Further suppose that the $latex S$$ is the $th k$$ +$cref/elementary vector/glossary/Elementary Vector/$$; i.e. +$latex \[ +S_j = \left\{ \begin{array}{ll} + 1 & {\rm if} \; j = k + \\ + 0 & {\rm otherwise} +\end{array} \right. +\] $$ +In this case, +the corresponding value $icode h$$ is a +sparsity pattern for the Hessian matrix +$latex F_k^{(2)} (x) \in \B{R}^{n \times n}$$. + +$head Example$$ +$children% + example/sparse/rev_sparse_hes.cpp + %example/sparse/sparsity_sub.cpp +%$$ +The file +$cref rev_sparse_hes.cpp$$ +contains an example and test of this operation. +The file +$cref/sparsity_sub.cpp/sparsity_sub.cpp/RevSparseHes/$$ +contains an example and test of using $code RevSparseHes$$ +to compute the sparsity pattern for a subset of the Hessian. + +$end +----------------------------------------------------------------------------- +*/ +# include +# include +# include + +namespace CppAD { // BEGIN_CPPAD_NAMESPACE +/*! +\file core/rev_sparse_hes.hpp +Reverse mode Hessian sparsity patterns. +*/ +// =========================================================================== +// RevSparseHesCase +/*! +Private helper function for RevSparseHes(q, s) bool sparsity. + +All of the description in the public member function RevSparseHes(q, s) +applies. + +\param set_type +is a bool value. This argument is used to dispatch to the proper source +code depending on the vlaue of SetVector::value_type. + +\param transpose +See RevSparseHes(q, s). + +\param q +See RevSparseHes(q, s). + +\param s +See RevSparseHes(q, s). + +\param h +is the return value for the corresponging call to RevSparseJac(q, s). +*/ +template +template +void ADFun::RevSparseHesCase( + bool set_type , + bool transpose , + size_t q , + const SetVector& s , + SetVector& h ) +{ + // used to identify the RecBase type in calls to sweeps + RecBase not_used_rec_base(0.0); + // + size_t n = Domain(); + size_t m = Range(); + // + h.resize(q * n ); + + CPPAD_ASSERT_KNOWN( + for_jac_sparse_pack_.n_set() > 0, + "RevSparseHes: previous stored call to ForSparseJac did not " + "use bool for the elements of r." + ); + CPPAD_ASSERT_UNKNOWN( for_jac_sparse_set_.n_set() == 0 ); + CPPAD_ASSERT_UNKNOWN( for_jac_sparse_pack_.n_set() == num_var_tape_ ); + // + // temporary indices + size_t i, j; + + // check Vector is Simple SetVector class with bool elements + CheckSimpleVector(); + + CPPAD_ASSERT_KNOWN( + q == for_jac_sparse_pack_.end(), + "RevSparseHes: q is not equal to its value\n" + "in the previous call to ForSparseJac with this ADFun object." + ); + CPPAD_ASSERT_KNOWN( + size_t(s.size()) == m, + "RevSparseHes: size of s is not equal to\n" + "range dimension for ADFun object." + ); + + // Array that will hold reverse Jacobian dependency flag. + // Initialize as true for the dependent variables. + local::pod_vector RevJac(num_var_tape_); + for(i = 0; i < num_var_tape_; i++) + RevJac[i] = false; + for(i = 0; i < m; i++) + { CPPAD_ASSERT_UNKNOWN( dep_taddr_[i] < num_var_tape_ ); + RevJac[ dep_taddr_[i] ] = s[i]; + } + + // vector of sets that will hold reverse Hessain values + local::sparse::pack_setvec rev_hes_pattern; + rev_hes_pattern.resize(num_var_tape_, q); + + // compute the Hessian sparsity patterns + local::sweep::rev_hes( + &play_, + n, + num_var_tape_, + for_jac_sparse_pack_, + RevJac.data(), + rev_hes_pattern, + not_used_rec_base + + ); + + // return values corresponding to independent variables + CPPAD_ASSERT_UNKNOWN( size_t(h.size()) == n * q ); + for(j = 0; j < n; j++) + { for(i = 0; i < q; i++) + { if( transpose ) + h[ j * q + i ] = false; + else + h[ i * n + j ] = false; + } + } + + // j is index corresponding to reverse mode partial + for(j = 0; j < n; j++) + { CPPAD_ASSERT_UNKNOWN( ind_taddr_[j] < num_var_tape_ ); + + // ind_taddr_[j] is operator taddr for j-th independent variable + CPPAD_ASSERT_UNKNOWN( ind_taddr_[j] == j + 1 ); + CPPAD_ASSERT_UNKNOWN( play_.GetOp( ind_taddr_[j] ) == local::InvOp ); + + // extract the result from rev_hes_pattern + CPPAD_ASSERT_UNKNOWN( rev_hes_pattern.end() == q ); + local::sparse::pack_setvec::const_iterator itr(rev_hes_pattern, j + 1); + i = *itr; + while( i < q ) + { if( transpose ) + h[ j * q + i ] = true; + else + h[ i * n + j ] = true; + i = *(++itr); + } + } +} +/*! +Private helper function for RevSparseHes(q, s) set sparsity. + +All of the description in the public member function RevSparseHes(q, s) +applies. + +\param set_type +is a std::set value. +This argument is used to dispatch to the proper source +code depending on the vlaue of SetVector::value_type. + +\param transpose +See RevSparseHes(q, s). + +\param q +See RevSparseHes(q, s). + +\param s +See RevSparseHes(q, s). + +\param h +is the return value for the corresponging call to RevSparseJac(q, s). +*/ +template +template +void ADFun::RevSparseHesCase( + const std::set& set_type , + bool transpose , + size_t q , + const SetVector& s , + SetVector& h ) +{ + // used to identify the RecBase type in calls to sweeps + RecBase not_used_rec_base(0.0); + // + size_t n = Domain(); +# ifndef NDEBUG + size_t m = Range(); +# endif + // + if( transpose ) + h.resize(n); + else + h.resize(q); + + CPPAD_ASSERT_KNOWN( + for_jac_sparse_set_.n_set() > 0, + "RevSparseHes: previous stored call to ForSparseJac did not " + "use std::set for the elements of r." + ); + CPPAD_ASSERT_UNKNOWN( for_jac_sparse_pack_.n_set() == 0 ); + CPPAD_ASSERT_UNKNOWN( for_jac_sparse_set_.n_set() == num_var_tape_ ); + // + // temporary indices + size_t i, j; + std::set::const_iterator itr_1; + + // check SetVector is Simple Vector class with sets for elements + CheckSimpleVector, SetVector>( + local::one_element_std_set(), local::two_element_std_set() + ); + + CPPAD_ASSERT_KNOWN( + q == for_jac_sparse_set_.end(), + "RevSparseHes: q is not equal to its value\n" + "in the previous call to ForSparseJac with this ADFun object." + ); + CPPAD_ASSERT_KNOWN( + s.size() == 1, + "RevSparseHes: size of s is not equal to one." + ); + + // Array that will hold reverse Jacobian dependency flag. + // Initialize as true for the dependent variables. + local::pod_vector RevJac(num_var_tape_); + for(i = 0; i < num_var_tape_; i++) + RevJac[i] = false; + itr_1 = s[0].begin(); + while( itr_1 != s[0].end() ) + { i = *itr_1++; + CPPAD_ASSERT_KNOWN( + i < m, + "RevSparseHes: an element of the set s[0] has value " + "greater than or equal m" + ); + CPPAD_ASSERT_UNKNOWN( dep_taddr_[i] < num_var_tape_ ); + RevJac[ dep_taddr_[i] ] = true; + } + + + // vector of sets that will hold reverse Hessain values + local::sparse::list_setvec rev_hes_pattern; + rev_hes_pattern.resize(num_var_tape_, q); + + // compute the Hessian sparsity patterns + local::sweep::rev_hes( + &play_, + n, + num_var_tape_, + for_jac_sparse_set_, + RevJac.data(), + rev_hes_pattern, + not_used_rec_base + + ); + + // return values corresponding to independent variables + // j is index corresponding to reverse mode partial + CPPAD_ASSERT_UNKNOWN( size_t(h.size()) == q || transpose ); + CPPAD_ASSERT_UNKNOWN( size_t(h.size()) == n || ! transpose ); + for(j = 0; j < n; j++) + { CPPAD_ASSERT_UNKNOWN( ind_taddr_[j] < num_var_tape_ ); + CPPAD_ASSERT_UNKNOWN( ind_taddr_[j] == j + 1 ); + CPPAD_ASSERT_UNKNOWN( play_.GetOp( ind_taddr_[j] ) == local::InvOp ); + + // extract the result from rev_hes_pattern + // and add corresponding elements to result sets in h + CPPAD_ASSERT_UNKNOWN( rev_hes_pattern.end() == q ); + local::sparse::list_setvec::const_iterator itr_2(rev_hes_pattern, j+1); + i = *itr_2; + while( i < q ) + { if( transpose ) + h[j].insert(i); + else + h[i].insert(j); + i = *(++itr_2); + } + } +} + +// =========================================================================== +// RevSparseHes + +/*! +User API for Hessian sparsity patterns using reverse mode. + +The C++ source code corresponding to this operation is +\verbatim + h = f.RevSparseHes(q, r) +\endverbatim + +\tparam Base +is the base type for this recording. + +\tparam SetVector +is a simple vector with elements of type bool +or std::set. + +\param transpose +is true (false) if is is equal to \f$ H(x) \f$ (\f$ H(x)^T \f$) +where +\f[ + H(x) = R^T (S * F)^{(2)} (x) +\f] +where \f$ F \f$ is the function corresponding to the operation sequence +and x is any argument value. + +\param q +is the value of q in the +by the previous call of the form +\verbatim + f.ForSparseJac(q, r, packed) +\endverbatim +The value r in this call is a sparsity pattern for the matrix \f$ R \f$. +The type of the element of r for the previous call to ForSparseJac +must be the same as the type of the elements of s. + +\param s +is a vector with size m that specifies the sparsity pattern +for the vector \f$ S \f$, +where m is the number of dependent variables +corresponding to the operation sequence stored in play. + +\return +If transpose is false (true), +the return vector is a sparsity pattern for \f$ H(x) \f$ (\f$ H(x)^T \f$). +\f[ + H(x) = R^T ( S * F)^{(2)} (x) +\f] +where \f$ F \f$ is the function corresponding to the operation sequence +and x is any argument value. +*/ + +template +template +SetVector ADFun::RevSparseHes( + size_t q, const SetVector& s, bool transpose +) +{ + SetVector h; + typedef typename SetVector::value_type Set_type; + + // Should check to make sure q is same as in previous call to + // forward sparse Jacobian. + RevSparseHesCase( + Set_type() , + transpose , + q , + s , + h + ); + + return h; +} +// =========================================================================== +// RevSparseHesCheckpoint +/*! +Hessian sparsity patterns calculation used by checkpoint functions. + +\tparam Base +is the base type for this recording. + +\param transpose +is true (false) h is equal to \f$ H(x) \f$ (\f$ H(x)^T \f$) +where +\f[ + H(x) = R^T (S * F)^{(2)} (x) +\f] +where \f$ F \f$ is the function corresponding to the operation sequence +and \f$ x \f$ is any argument value. + +\param q +is the value of q in the by the previous call of the form +\verbatim + f.ForSparseJac(q, r) +\endverbatim +The value r in this call is a sparsity pattern for the matrix \f$ R \f$. + +\param s +is a vector with size m that specifies the sparsity pattern +for the vector \f$ S \f$, +where m is the number of dependent variables +corresponding to the operation sequence stored in play_. + +\param h +The input size and elements of h do not matter. +On output, h is the sparsity pattern for the matrix \f$ H(x) \f$ +or \f$ H(x)^T \f$ depending on transpose. + +\par Assumptions +The forward jacobian sparsity pattern must be currently stored +in this ADFUN object. +*/ +template +void ADFun::RevSparseHesCheckpoint( + size_t q , + vector& s , + bool transpose , + local::sparse::list_setvec& h ) +{ + // used to identify the RecBase type in calls to sweeps + RecBase not_used_rec_base(0.0); + // + size_t n = Domain(); + size_t m = Range(); + + // checkpoint functions should get this right + CPPAD_ASSERT_UNKNOWN( for_jac_sparse_pack_.n_set() == 0 ); + CPPAD_ASSERT_UNKNOWN( for_jac_sparse_set_.n_set() == num_var_tape_ ); + CPPAD_ASSERT_UNKNOWN( for_jac_sparse_set_.end() == q ); + CPPAD_ASSERT_UNKNOWN( s.size() == m ); + + // Array that holds the reverse Jacobiain dependcy flags. + // Initialize as true for dependent variables, flase for others. + local::pod_vector RevJac(num_var_tape_); + for(size_t i = 0; i < num_var_tape_; i++) + RevJac[i] = false; + for(size_t i = 0; i < m; i++) + { CPPAD_ASSERT_UNKNOWN( dep_taddr_[i] < num_var_tape_ ) + RevJac[ dep_taddr_[i] ] = s[i]; + } + + // holds reverse Hessian sparsity pattern for all variables + local::sparse::list_setvec rev_hes_pattern; + rev_hes_pattern.resize(num_var_tape_, q); + + // compute Hessian sparsity pattern for all variables + local::sweep::rev_hes( + &play_, + n, + num_var_tape_, + for_jac_sparse_set_, + RevJac.data(), + rev_hes_pattern, + not_used_rec_base + + ); + + // dimension the return value + if( transpose ) + h.resize(n, q); + else + h.resize(q, n); + + // j is index corresponding to reverse mode partial + for(size_t j = 0; j < n; j++) + { CPPAD_ASSERT_UNKNOWN( ind_taddr_[j] < num_var_tape_ ); + + // ind_taddr_[j] is operator taddr for j-th independent variable + CPPAD_ASSERT_UNKNOWN( ind_taddr_[j] == j + 1 ); + CPPAD_ASSERT_UNKNOWN( play_.GetOp( ind_taddr_[j] ) == local::InvOp ); + + // extract the result from rev_hes_pattern + CPPAD_ASSERT_UNKNOWN( rev_hes_pattern.end() == q ); + local::sparse::list_setvec::const_iterator itr(rev_hes_pattern, j + 1); + size_t i = *itr; + while( i < q ) + { if( transpose ) + h.post_element(j, i); + else + h.post_element(i, j); + i = *(++itr); + } + } + for(size_t i = 0; i < h.n_set(); ++i) + h.process_post(i); +} + +} // END_CPPAD_NAMESPACE +# endif diff --git a/build-config/cppad/include/cppad/core/rev_sparse_jac.hpp b/build-config/cppad/include/cppad/core/rev_sparse_jac.hpp new file mode 100644 index 00000000..8ea33422 --- /dev/null +++ b/build-config/cppad/include/cppad/core/rev_sparse_jac.hpp @@ -0,0 +1,654 @@ +# ifndef CPPAD_CORE_REV_SPARSE_JAC_HPP +# define CPPAD_CORE_REV_SPARSE_JAC_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +/* +$begin RevSparseJac$$ +$spell + optimizer + nz + CondExpRel + std + VecAD + var + Jacobian + Jac + const + Bool + Dep + proportional +$$ + +$section Jacobian Sparsity Pattern: Reverse Mode$$ + +$head Syntax$$ +$icode%s% = %f%.RevSparseJac(%q%, %r%) +%$$ +$icode%s% = %f%.RevSparseJac(%q%, %r%, %transpose%, %dependency%)%$$ + +$head Purpose$$ +We use $latex F : \B{R}^n \rightarrow \B{R}^m$$ to denote the +$cref/AD function/glossary/AD Function/$$ corresponding to $icode f$$. +For a fixed matrix $latex R \in \B{R}^{q \times m}$$, +the Jacobian of $latex R * F( x )$$ +with respect to $latex x$$ is +$latex \[ + S(x) = R * F^{(1)} ( x ) +\] $$ +Given a +$cref/sparsity pattern/glossary/Sparsity Pattern/$$ +for $latex R$$, +$code RevSparseJac$$ returns a sparsity pattern for the $latex S(x)$$. + +$head f$$ +The object $icode f$$ has prototype +$codei% + ADFun<%Base%> %f% +%$$ + +$head x$$ +If the operation sequence in $icode f$$ is +$cref/independent/glossary/Operation/Independent/$$ of +the independent variables in $latex x \in \B{R}^n$$, +the sparsity pattern is valid for all values of +(even if it has $cref CondExp$$ or $cref VecAD$$ operations). + +$head q$$ +The argument $icode q$$ has prototype +$codei% + size_t %q% +%$$ +It specifies the number of rows in +$latex R \in \B{R}^{q \times m}$$ and the +Jacobian $latex S(x) \in \B{R}^{q \times n}$$. + +$head transpose$$ +The argument $icode transpose$$ has prototype +$codei% + bool %transpose% +%$$ +The default value $code false$$ is used when $icode transpose$$ is not present. + +$head dependency$$ +The argument $icode dependency$$ has prototype +$codei% + bool %dependency% +%$$ +If $icode dependency$$ is true, +the $cref/dependency pattern/dependency.cpp/Dependency Pattern/$$ +(instead of sparsity pattern) is computed. + +$head r$$ +The argument $icode s$$ has prototype +$codei% + const %SetVector%& %r% +%$$ +see $cref/SetVector/RevSparseJac/SetVector/$$ below. + +$subhead transpose false$$ +If $icode r$$ has elements of type $code bool$$, +its size is $latex q * m$$. +If it has elements of type $code std::set$$, +its size is $icode q$$ and all its set elements are between +zero and $latex m - 1$$. +It specifies a +$cref/sparsity pattern/glossary/Sparsity Pattern/$$ +for the matrix $latex R \in \B{R}^{q \times m}$$. + +$subhead transpose true$$ +If $icode r$$ has elements of type $code bool$$, +its size is $latex m * q$$. +If it has elements of type $code std::set$$, +its size is $icode m$$ and all its set elements are between +zero and $latex q - 1$$. +It specifies a +$cref/sparsity pattern/glossary/Sparsity Pattern/$$ +for the matrix $latex R^\R{T} \in \B{R}^{m \times q}$$. + +$head s$$ +The return value $icode s$$ has prototype +$codei% + %SetVector% %s% +%$$ +see $cref/SetVector/RevSparseJac/SetVector/$$ below. + +$subhead transpose false$$ +If it has elements of type $code bool$$, +its size is $latex q * n$$. +If it has elements of type $code std::set$$, +its size is $icode q$$ and all its set elements are between +zero and $latex n - 1$$. +It specifies a +$cref/sparsity pattern/glossary/Sparsity Pattern/$$ +for the matrix $latex S(x) \in {q \times n}$$. + +$subhead transpose true$$ +If it has elements of type $code bool$$, +its size is $latex n * q$$. +If it has elements of type $code std::set$$, +its size is $icode n$$ and all its set elements are between +zero and $latex q - 1$$. +It specifies a +$cref/sparsity pattern/glossary/Sparsity Pattern/$$ +for the matrix $latex S(x)^\R{T} \in {n \times q}$$. + +$head SetVector$$ +The type $icode SetVector$$ must be a $cref SimpleVector$$ class with +$cref/elements of type/SimpleVector/Elements of Specified Type/$$ +$code bool$$ or $code std::set$$; +see $cref/sparsity pattern/glossary/Sparsity Pattern/$$ for a discussion +of the difference. + +$head Entire Sparsity Pattern$$ +Suppose that $latex q = m$$ and +$latex R$$ is the $latex m \times m$$ identity matrix. +In this case, +the corresponding value for $icode s$$ is a +sparsity pattern for the Jacobian $latex S(x) = F^{(1)} ( x )$$. + +$head Example$$ +$children% + example/sparse/rev_sparse_jac.cpp +%$$ +The file +$cref rev_sparse_jac.cpp$$ +contains an example and test of this operation. + +$end +----------------------------------------------------------------------------- +*/ + +# include + +namespace CppAD { // BEGIN_CPPAD_NAMESPACE +/*! +\file core/rev_sparse_jac.hpp +Reverse mode Jacobian sparsity patterns. +*/ +// ========================================================================= +// RevSparseJacCase + +/*! +Private helper function for RevSparseJac(q, r, transpose) boolean sparsity. + +All of the description in the public member function + RevSparseJac(q, r, transpose) apply. + +\param set_type +is a bool value. +This argument is used to dispatch to the proper source code +depending on the value of SetVector::value_type. + +\param transpose +See RevSparseJac(q, r, transpose, dependency) + +\param dependency +See RevSparseJac(q, r, transpose, dependency) + +\param q +See RevSparseJac(q, r, transpose, dependency) + +\param r +See RevSparseJac(q, r, transpose, dependency) + +\param s +is the return value for the corresponding call to +RevSparseJac(q, r, transpose). +*/ + +template +template +void ADFun::RevSparseJacCase( + bool set_type , + bool transpose , + bool dependency , + size_t q , + const SetVector& r , + SetVector& s ) +{ + // used to identify the RecBase type in calls to sweeps + RecBase not_used_rec_base(0.0); + // + size_t n = Domain(); + size_t m = Range(); + + // dimension of the result vector + s.resize( q * n ); + + // check SetVector is Simple Vector class with bool elements + CheckSimpleVector(); + // + CPPAD_ASSERT_KNOWN( + q > 0, + "RevSparseJac: q is not greater than zero" + ); + CPPAD_ASSERT_KNOWN( + size_t(r.size()) == q * m, + "RevSparseJac: size of r is not equal to\n" + "q times range dimension for ADFun object." + ); + // + // vector of sets that will hold the results + local::sparse::pack_setvec var_sparsity; + var_sparsity.resize(num_var_tape_, q); + + // The sparsity pattern corresponding to the dependent variables + for(size_t i = 0; i < m; i++) + { CPPAD_ASSERT_UNKNOWN( dep_taddr_[i] < num_var_tape_ ); + if( transpose ) + { for(size_t j = 0; j < q; j++) if( r[ i * q + j ] ) + var_sparsity.post_element( dep_taddr_[i], j ); + } + else + { for(size_t j = 0; j < q; j++) if( r[ j * m + i ] ) + var_sparsity.post_element( dep_taddr_[i], j ); + } + } + // process posts + for(size_t i = 0; i < m; i++) + var_sparsity.process_post( dep_taddr_[i] ); + + // evaluate the sparsity patterns + local::sweep::rev_jac( + &play_, + dependency, + n, + num_var_tape_, + var_sparsity, + not_used_rec_base + + ); + + // return values corresponding to dependent variables + CPPAD_ASSERT_UNKNOWN( size_t(s.size()) == q * n ); + for(size_t j = 0; j < n; j++) + { CPPAD_ASSERT_UNKNOWN( ind_taddr_[j] == (j+1) ); + + // ind_taddr_[j] is operator taddr for j-th independent variable + CPPAD_ASSERT_UNKNOWN( play_.GetOp( ind_taddr_[j] ) == local::InvOp ); + + // extract the result from var_sparsity + if( transpose ) + { for(size_t i = 0; i < q; i++) + s[ j * q + i ] = false; + } + else + { for(size_t i = 0; i < q; i++) + s[ i * n + j ] = false; + } + CPPAD_ASSERT_UNKNOWN( var_sparsity.end() == q ); + local::sparse::pack_setvec::const_iterator itr(var_sparsity, j+1); + size_t i = *itr; + while( i < q ) + { if( transpose ) + s[ j * q + i ] = true; + else + s[ i * n + j ] = true; + i = *(++itr); + } + } +} + +/*! +Private helper function for RevSparseJac(q, r, transpose) set sparsity + +All of the description in the public member function + RevSparseJac(q, r, transpose) apply. + +\param set_type +is a std::set object. +This argument is used to dispatch to the proper source code +depending on the value of SetVector::value_type. + +\param transpose +See RevSparseJac(q, r, transpose, dependency) + +\param dependency +See RevSparseJac(q, r, transpose, dependency) + +\param q +See RevSparseJac(q, r, transpose, dependency) + +\param r +See RevSparseJac(q, r, transpose, dependency) + +\param s +is the return value for the corresponding call to RevSparseJac(q, r, transpose) +*/ + +template +template +void ADFun::RevSparseJacCase( + const std::set& set_type , + bool transpose , + bool dependency , + size_t q , + const SetVector& r , + SetVector& s ) +{ + // used to identify the RecBase type in calls to sweeps + RecBase not_used_rec_base(0.0); + // + // dimension of the result vector + if( transpose ) + s.resize( Domain() ); + else + s.resize( q ); + + // temporary indices + std::set::const_iterator itr_1; + + // check SetVector is Simple Vector class with sets for elements + CheckSimpleVector, SetVector>( + local::one_element_std_set(), local::two_element_std_set() + ); + + // domain dimensions for F + size_t n = ind_taddr_.size(); + size_t m = dep_taddr_.size(); + + CPPAD_ASSERT_KNOWN( + q > 0, + "RevSparseJac: q is not greater than zero" + ); + CPPAD_ASSERT_KNOWN( + size_t(r.size()) == q || transpose, + "RevSparseJac: size of r is not equal to q and transpose is false." + ); + CPPAD_ASSERT_KNOWN( + size_t(r.size()) == m || ! transpose, + "RevSparseJac: size of r is not equal to m and transpose is true." + ); + + // vector of lists that will hold the results + local::sparse::list_setvec var_sparsity; + var_sparsity.resize(num_var_tape_, q); + + // The sparsity pattern corresponding to the dependent variables + if( transpose ) + { for(size_t i = 0; i < m; i++) + { itr_1 = r[i].begin(); + while(itr_1 != r[i].end()) + { size_t j = *itr_1++; + CPPAD_ASSERT_KNOWN( + j < q, + "RevSparseJac: transpose is true and element of the set\n" + "r[i] has value greater than or equal q." + ); + CPPAD_ASSERT_UNKNOWN( dep_taddr_[i] < num_var_tape_ ); + var_sparsity.post_element( dep_taddr_[i], j ); + } + } + } + else + { for(size_t i = 0; i < q; i++) + { itr_1 = r[i].begin(); + while(itr_1 != r[i].end()) + { size_t j = *itr_1++; + CPPAD_ASSERT_KNOWN( + j < m, + "RevSparseJac: transpose is false and element of the set\n" + "r[i] has value greater than or equal range dimension." + ); + CPPAD_ASSERT_UNKNOWN( dep_taddr_[j] < num_var_tape_ ); + var_sparsity.post_element( dep_taddr_[j], i ); + } + } + } + // process posts + for(size_t i = 0; i < m; i++) + var_sparsity.process_post( dep_taddr_[i] ); + + // evaluate the sparsity patterns + local::sweep::rev_jac( + &play_, + dependency, + n, + num_var_tape_, + var_sparsity, + not_used_rec_base + + ); + + // return values corresponding to dependent variables + CPPAD_ASSERT_UNKNOWN( size_t(s.size()) == q || transpose ); + CPPAD_ASSERT_UNKNOWN( size_t(s.size()) == n || ! transpose ); + for(size_t j = 0; j < n; j++) + { CPPAD_ASSERT_UNKNOWN( ind_taddr_[j] == (j+1) ); + + // ind_taddr_[j] is operator taddr for j-th independent variable + CPPAD_ASSERT_UNKNOWN( play_.GetOp( ind_taddr_[j] ) == local::InvOp ); + + CPPAD_ASSERT_UNKNOWN( var_sparsity.end() == q ); + local::sparse::list_setvec::const_iterator itr_2(var_sparsity, j+1); + size_t i = *itr_2; + while( i < q ) + { if( transpose ) + s[j].insert(i); + else + s[i].insert(j); + i = *(++itr_2); + } + } +} + +// ========================================================================= +// RevSparseJac +/*! +User API for Jacobian sparsity patterns using reverse mode. + +The C++ source code corresponding to this operation is +\verbatim + s = f.RevSparseJac(q, r, transpose, dependency) +\endverbatim + +\tparam Base +is the base type for this recording. + +\tparam SetVector +is a simple vector with elements of type bool. +or std::set. + +\param q +is the number of rows in the matrix \f$ R \f$. + +\param r +is a sparsity pattern for the matrix \f$ R \f$. + +\param transpose +are the sparsity patterns for \f$ R \f$ and \f$ S(x) \f$ transposed. + +\param dependency +Are the derivatives with respect to left and right of the expression below +considered to be non-zero: +\code + CondExpRel(left, right, if_true, if_false) +\endcode +This is used by the optimizer to obtain the correct dependency relations. + + +\return +If transpose is false (true), the return value is a sparsity pattern +for \f$ S(x) \f$ (\f$ S(x)^T \f$) where +\f[ + S(x) = R * F^{(1)} (x) +\f] +and \f$ F \f$ is the function corresponding to the operation sequence +and x is any argument value. +If SetVector::value_type is bool, +the return value has size \f$ q * n \f$ ( \f$ n * q \f$). +If SetVector::value_type is std::set, +the return value has size \f$ q \f$ ( \f$ n \f$) +and with all its elements between zero and \f$ n - 1 \f$ (\f$ q - 1 \f$). +*/ +template +template +SetVector ADFun::RevSparseJac( + size_t q , + const SetVector& r , + bool transpose , + bool dependency ) +{ + SetVector s; + typedef typename SetVector::value_type Set_type; + + RevSparseJacCase( + Set_type() , + transpose , + dependency , + q , + r , + s + ); + return s; +} +// =========================================================================== +// RevSparseJacCheckpoint +/*! +Reverse mode Jacobian sparsity calculation used by checkpoint functions. + +\tparam Base +is the base type for this recording. + +\param transpose +is true (false) s is equal to \f$ S(x) \f$ (\f$ S(x)^T \f$) +where +\f[ + S(x) = R * F^{(1)} (x) +\f] +where \f$ F \f$ is the function corresponding to the operation sequence +and \f$ x \f$ is any argument value. + +\param q +is the number of rows in the matrix \f$ R \f$. + +\param r +is a sparsity pattern for the matrix \f$ R \f$. + +\param transpose +are the sparsity patterns for \f$ R \f$ and \f$ S(x) \f$ transposed. + +\param dependency +Are the derivatives with respect to left and right of the expression below +considered to be non-zero: +\code + CondExpRel(left, right, if_true, if_false) +\endcode +This is used by the optimizer to obtain the correct dependency relations. + +\param s +The input size and elements of s do not matter. +On output, s is the sparsity pattern for the matrix \f$ S(x) \f$ +or \f$ S(x)^T \f$ depending on transpose. + +*/ +template +void ADFun::RevSparseJacCheckpoint( + size_t q , + const local::sparse::list_setvec& r , + bool transpose , + bool dependency , + local::sparse::list_setvec& s ) +{ + // used to identify the RecBase type in calls to sweeps + RecBase not_used_rec_base(0.0); + // + size_t n = Domain(); + size_t m = Range(); + +# ifndef NDEBUG + if( transpose ) + { CPPAD_ASSERT_UNKNOWN( r.n_set() == m ); + CPPAD_ASSERT_UNKNOWN( r.end() == q ); + } + else + { CPPAD_ASSERT_UNKNOWN( r.n_set() == q ); + CPPAD_ASSERT_UNKNOWN( r.end() == m ); + } + for(size_t i = 0; i < m; i++) + CPPAD_ASSERT_UNKNOWN( dep_taddr_[i] < num_var_tape_ ); +# endif + + // holds reverse Jacobian sparsity pattern for all variables + local::sparse::list_setvec var_sparsity; + var_sparsity.resize(num_var_tape_, q); + + // set sparsity pattern for dependent variables + if( transpose ) + { for(size_t i = 0; i < m; i++) + { local::sparse::list_setvec::const_iterator itr(r, i); + size_t j = *itr; + while( j < q ) + { var_sparsity.post_element( dep_taddr_[i], j ); + j = *(++itr); + } + } + } + else + { for(size_t j = 0; j < q; j++) + { local::sparse::list_setvec::const_iterator itr(r, j); + size_t i = *itr; + while( i < m ) + { var_sparsity.post_element( dep_taddr_[i], j ); + i = *(++itr); + } + } + } + // process posts + for(size_t i = 0; i < m; i++) + var_sparsity.process_post( dep_taddr_[i] ); + + // evaluate the sparsity pattern for all variables + local::sweep::rev_jac( + &play_, + dependency, + n, + num_var_tape_, + var_sparsity, + not_used_rec_base + + ); + + // dimension the return value + if( transpose ) + s.resize(n, m); + else + s.resize(m, n); + + // return values corresponding to independent variables + for(size_t j = 0; j < n; j++) + { CPPAD_ASSERT_UNKNOWN( ind_taddr_[j] == (j+1) ); + + // ind_taddr_[j] is operator taddr for j-th independent variable + CPPAD_ASSERT_UNKNOWN( play_.GetOp( ind_taddr_[j] ) == local::InvOp ); + + // extract the result from var_sparsity + CPPAD_ASSERT_UNKNOWN( var_sparsity.end() == q ); + local::sparse::list_setvec::const_iterator itr(var_sparsity, j+1); + size_t i = *itr; + while( i < q ) + { if( transpose ) + s.post_element(j, i); + else + s.post_element(i, j); + i = *(++itr); + } + } + // process posts + for(size_t i = 0; i < s.n_set(); i++) + s.process_post(i); + +} + +} // END_CPPAD_NAMESPACE +# endif diff --git a/build-config/cppad/include/cppad/core/rev_two.hpp b/build-config/cppad/include/cppad/core/rev_two.hpp new file mode 100644 index 00000000..43a928b8 --- /dev/null +++ b/build-config/cppad/include/cppad/core/rev_two.hpp @@ -0,0 +1,234 @@ +# ifndef CPPAD_CORE_REV_TWO_HPP +# define CPPAD_CORE_REV_TWO_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-18 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +/* +$begin RevTwo$$ +$spell + ddw + typename + Taylor + const +$$ + + + + + +$section Reverse Mode Second Partial Derivative Driver$$ + +$head Syntax$$ +$icode%ddw% = %f%.RevTwo(%x%, %i%, %j%)%$$ + + +$head Purpose$$ +We use $latex F : \B{R}^n \rightarrow \B{R}^m$$ to denote the +$cref/AD function/glossary/AD Function/$$ corresponding to $icode f$$. +The syntax above sets +$latex \[ + ddw [ k * p + \ell ] + = + \DD{ F_{i[ \ell ]} }{ x_{j[ \ell ]} }{ x_k } (x) +\] $$ +for $latex k = 0 , \ldots , n-1$$ +and $latex \ell = 0 , \ldots , p$$, +where $latex p$$ is the size of the vectors $icode i$$ and $icode j$$. + +$head f$$ +The object $icode f$$ has prototype +$codei% + ADFun<%Base%> %f% +%$$ +Note that the $cref ADFun$$ object $icode f$$ is not $code const$$ +(see $cref/RevTwo Uses Forward/RevTwo/RevTwo Uses Forward/$$ below). + +$head x$$ +The argument $icode x$$ has prototype +$codei% + const %BaseVector% &%x% +%$$ +(see $cref/BaseVector/RevTwo/BaseVector/$$ below) +and its size +must be equal to $icode n$$, the dimension of the +$cref/domain/seq_property/Domain/$$ space for $icode f$$. +It specifies +that point at which to evaluate the partial derivatives listed above. + +$head i$$ +The argument $icode i$$ has prototype +$codei% + const %SizeVector_t% &%i% +%$$ +(see $cref/SizeVector_t/RevTwo/SizeVector_t/$$ below) +We use $icode p$$ to denote the size of the vector $icode i$$. +All of the indices in $icode i$$ +must be less than $icode m$$, the dimension of the +$cref/range/seq_property/Range/$$ space for $icode f$$; i.e., +for $latex \ell = 0 , \ldots , p-1$$, $latex i[ \ell ] < m$$. + +$head j$$ +The argument $icode j$$ has prototype +$codei% + const %SizeVector_t% &%j% +%$$ +(see $cref/SizeVector_t/RevTwo/SizeVector_t/$$ below) +and its size must be equal to $icode p$$, +the size of the vector $icode i$$. +All of the indices in $icode j$$ +must be less than $icode n$$; i.e., +for $latex \ell = 0 , \ldots , p-1$$, $latex j[ \ell ] < n$$. + +$head ddw$$ +The result $icode ddw$$ has prototype +$codei% + %BaseVector% %ddw% +%$$ +(see $cref/BaseVector/RevTwo/BaseVector/$$ below) +and its size is $latex n * p$$. +It contains the requested partial derivatives; to be specific, +for $latex k = 0 , \ldots , n - 1 $$ +and $latex \ell = 0 , \ldots , p - 1$$ +$latex \[ + ddw [ k * p + \ell ] + = + \DD{ F_{i[ \ell ]} }{ x_{j[ \ell ]} }{ x_k } (x) +\] $$ + +$head BaseVector$$ +The type $icode BaseVector$$ must be a $cref SimpleVector$$ class with +$cref/elements of type Base/SimpleVector/Elements of Specified Type/$$. +The routine $cref CheckSimpleVector$$ will generate an error message +if this is not the case. + +$head SizeVector_t$$ +The type $icode SizeVector_t$$ must be a $cref SimpleVector$$ class with +$cref/elements of type size_t/SimpleVector/Elements of Specified Type/$$. +The routine $cref CheckSimpleVector$$ will generate an error message +if this is not the case. + +$head RevTwo Uses Forward$$ +After each call to $cref Forward$$, +the object $icode f$$ contains the corresponding +$cref/Taylor coefficients/glossary/Taylor Coefficient/$$. +After a call to $code RevTwo$$, +the zero order Taylor coefficients correspond to +$icode%f%.Forward(0, %x%)%$$ +and the other coefficients are unspecified. + +$head Examples$$ +$children% + example/general/rev_two.cpp +%$$ +The routine +$cref/RevTwo/rev_two.cpp/$$ is both an example and test. +It returns $code true$$, if it succeeds and $code false$$ otherwise. + +$end +----------------------------------------------------------------------------- +*/ + +// BEGIN CppAD namespace +namespace CppAD { + +template +template +BaseVector ADFun::RevTwo( + const BaseVector &x, + const SizeVector_t &i, + const SizeVector_t &j) +{ size_t i1; + size_t j1; + size_t k; + size_t l; + + size_t n = Domain(); + size_t m = Range(); + size_t p = i.size(); + + // check BaseVector is Simple Vector class with Base elements + CheckSimpleVector(); + + // check SizeVector_t is Simple Vector class with size_t elements + CheckSimpleVector(); + + CPPAD_ASSERT_KNOWN( + x.size() == n, + "RevTwo: Length of x not equal domain dimension for f." + ); + CPPAD_ASSERT_KNOWN( + i.size() == j.size(), + "RevTwo: Lenght of the i and j vectors are not equal." + ); + // point at which we are evaluating the second partials + Forward(0, x); + + // dimension the return value + BaseVector ddw(n * p); + + // direction vector in argument space + BaseVector dx(n); + for(j1 = 0; j1 < n; j1++) + dx[j1] = Base(0.0); + + // direction vector in range space + BaseVector w(m); + for(i1 = 0; i1 < m; i1++) + w[i1] = Base(0.0); + + // place to hold the results of a reverse calculation + BaseVector r(n * 2); + + // check the indices in i and j + for(l = 0; l < p; l++) + { i1 = i[l]; + j1 = j[l]; + CPPAD_ASSERT_KNOWN( + i1 < m, + "RevTwo: an eleemnt of i not less than range dimension for f." + ); + CPPAD_ASSERT_KNOWN( + j1 < n, + "RevTwo: an element of j not less than domain dimension for f." + ); + } + + // loop over all forward directions + for(j1 = 0; j1 < n; j1++) + { // first order forward mode calculation done + bool first_done = false; + for(l = 0; l < p; l++) if( j[l] == j1 ) + { if( ! first_done ) + { first_done = true; + + // first order forward mode in j1 direction + dx[j1] = Base(1.0); + Forward(1, dx); + dx[j1] = Base(0.0); + } + // execute a reverse in this component direction + i1 = i[l]; + w[i1] = Base(1.0); + r = Reverse(2, w); + w[i1] = Base(0.0); + + // place the reverse result in return value + for(k = 0; k < n; k++) + ddw[k * p + l] = r[k * 2 + 1]; + } + } + return ddw; +} + +} // END CppAD namespace + +# endif diff --git a/build-config/cppad/include/cppad/core/reverse.hpp b/build-config/cppad/include/cppad/core/reverse.hpp new file mode 100644 index 00000000..6ab09824 --- /dev/null +++ b/build-config/cppad/include/cppad/core/reverse.hpp @@ -0,0 +1,208 @@ +# ifndef CPPAD_CORE_REVERSE_HPP +# define CPPAD_CORE_REVERSE_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-21 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +# include +# include +# include + +namespace CppAD { // BEGIN_CPPAD_NAMESPACE +/*! +\file core/reverse.hpp +Compute derivatives using reverse mode. +*/ + + +/*! +Use reverse mode to compute derivative of forward mode Taylor coefficients. + +The function +\f$ X : {\bf R} \times {\bf R}^{n \times q} \rightarrow {\bf R} \f$ +is defined by +\f[ +X(t , u) = \sum_{k=0}^{q-1} u^{(k)} t^k +\f] +The function +\f$ Y : {\bf R} \times {\bf R}^{n \times q} \rightarrow {\bf R} \f$ +is defined by +\f[ +Y(t , u) = F[ X(t, u) ] +\f] +The function +\f$ W : {\bf R}^{n \times q} \rightarrow {\bf R} \f$ is defined by +\f[ +W(u) = \sum_{k=0}^{q-1} ( w^{(k)} )^{\rm T} +\frac{1}{k !} \frac{ \partial^k } { t^k } Y(0, u) +\f] + +\tparam Base +base type for the operator; i.e., this operation sequence was recorded +using AD< Base > and computations by this routine are done using type + Base. + +\tparam BaseVector +is a Simple Vector class with elements of type Base. + +\param q +is the number of the number of Taylor coefficients that are being +differentiated (per variable). + +\param w +is the weighting for each of the Taylor coefficients corresponding +to dependent variables. +If the argument w has size m * q , +for \f$ k = 0 , \ldots , q-1 \f$ and \f$ i = 0, \ldots , m-1 \f$, +\f[ + w_i^{(k)} = w [ i * q + k ] +\f] +If the argument w has size m , +for \f$ k = 0 , \ldots , q-1 \f$ and \f$ i = 0, \ldots , m-1 \f$, +\f[ +w_i^{(k)} = \left\{ \begin{array}{ll} + w [ i ] & {\rm if} \; k = q-1 + \\ + 0 & {\rm otherwise} +\end{array} \right. +\f] + +\return +Is a vector \f$ dw \f$ such that +for \f$ j = 0 , \ldots , n-1 \f$ and +\f$ k = 0 , \ldots , q-1 \f$ +\f[ + dw[ j * q + k ] = W^{(1)} ( x )_{j,k} +\f] +where the matrix \f$ x \f$ is the value for \f$ u \f$ +that corresponding to the forward mode Taylor coefficients +for the independent variables as specified by previous calls to Forward. + +*/ +template +template +BaseVector ADFun::Reverse(size_t q, const BaseVector &w) +{ // used to identify the RecBase type in calls to sweeps + RecBase not_used_rec_base(0.0); + + // 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(); + + // check BaseVector is Simple Vector class with Base type elements + CheckSimpleVector(); + + 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 or dimension of range times q." + ); + CPPAD_ASSERT_KNOWN( + q > 0, + "The first argument to Reverse must be greater than zero." + ); + CPPAD_ASSERT_KNOWN( + num_order_taylor_ >= q, + "Less than 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 + local::pod_vector_maybe Partial(num_var_tape_ * q); + 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++) + 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_op2var_.size() == play_.num_var_load_rec() ); + local::play::const_sequential_iterator play_itr = play_.end(); + local::sweep::reverse( + q - 1, + n, + num_var_tape_, + &play_, + cap_order_taylor_, + taylor_.data(), + q, + Partial.data(), + cskip_op_.data(), + load_op2var_, + play_itr, + not_used_rec_base + ); + + // return the derivative values + BaseVector 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] ) == local::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; +} + + +} // END_CPPAD_NAMESPACE +# endif diff --git a/build-config/cppad/include/cppad/core/sign.hpp b/build-config/cppad/include/cppad/core/sign.hpp new file mode 100644 index 00000000..27188fea --- /dev/null +++ b/build-config/cppad/include/cppad/core/sign.hpp @@ -0,0 +1,121 @@ +# ifndef CPPAD_CORE_SIGN_HPP +# define CPPAD_CORE_SIGN_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +/* +$begin sign$$ +$spell + CppAD + Dirac +$$ +$section The Sign: sign$$ + +$head Syntax$$ +$icode%y% = sign(%x%)%$$ + +$head Description$$ +Evaluates the $code sign$$ function which is defined by +$latex \[ +{\rm sign} (x) = +\left\{ \begin{array}{rl} + +1 & {\rm if} \; x > 0 \\ + 0 & {\rm if} \; x = 0 \\ + -1 & {\rm if} \; x < 0 +\end{array} \right. +\] $$ + +$head x, y$$ +See the $cref/possible types/unary_standard_math/Possible Types/$$ +for a unary standard math function. + +$head Atomic$$ +This is an $cref/atomic operation/glossary/Operation/Atomic/$$. + +$head Derivative$$ +CppAD computes the derivative of the $code sign$$ function as zero for all +argument values $icode x$$. +The correct mathematical derivative is different and +is given by +$latex \[ + {\rm sign}^{(1)} (x) = 2 \delta (x) +\] $$ +where $latex \delta (x)$$ is the Dirac Delta function. + +$head Example$$ +$children% + example/general/sign.cpp +%$$ +The file +$cref sign.cpp$$ +contains an example and test of this function. + +$end +------------------------------------------------------------------------------- +*/ + +// BEGIN CppAD namespace +namespace CppAD { + +template +AD AD::sign_me (void) const +{ + AD result; + result.value_ = sign(value_); + CPPAD_ASSERT_UNKNOWN( Parameter(result) ); + + // check if there is a recording in progress + local::ADTape* tape = AD::tape_ptr(); + if( tape == nullptr ) + return result; + + // check if operand is a constant parameter + if( tape_id_ != tape->id_ ) + return result; + + if(ad_type_ == dynamic_enum) + { // dynamic paramter argument + result.taddr_ = tape->Rec_.put_dyn_par( + result.value_, local::sign_dyn, taddr_ + ); + result.tape_id_ = tape_id_; + result.ad_type_ = dynamic_enum; + } + else + { // variable argument + CPPAD_ASSERT_UNKNOWN( local::NumRes(local::SignOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( local::NumArg(local::SignOp) == 1 ); + + // corresponding operand address + tape->Rec_.PutArg(taddr_); + + // put operator in the tape + result.taddr_ = tape->Rec_.PutOp(local::SignOp); + + // make result a variable + result.tape_id_ = tape->id_; + result.ad_type_ = variable_enum; + } + return result; +} + +template +AD sign(const AD &x) +{ return x.sign_me(); +} +template +AD sign(const VecAD_reference &x) +{ return x.ADBase().sign_me(); } + +} // END CppAD namespace + +# endif diff --git a/build-config/cppad/include/cppad/core/sparse.hpp b/build-config/cppad/include/cppad/core/sparse.hpp new file mode 100644 index 00000000..7db70d82 --- /dev/null +++ b/build-config/cppad/include/cppad/core/sparse.hpp @@ -0,0 +1,38 @@ +# ifndef CPPAD_CORE_SPARSE_HPP +# define CPPAD_CORE_SPARSE_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-17 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +// +# include +# include +// +# include +# include +// +# include +# include +// +# include +# include +// +# include +# include +// +# include +# include +// +# include +# include +# include + +# endif diff --git a/build-config/cppad/include/cppad/core/sparse_hes.hpp b/build-config/cppad/include/cppad/core/sparse_hes.hpp new file mode 100644 index 00000000..15996a7d --- /dev/null +++ b/build-config/cppad/include/cppad/core/sparse_hes.hpp @@ -0,0 +1,544 @@ +# ifndef CPPAD_CORE_SPARSE_HES_HPP +# define CPPAD_CORE_SPARSE_HES_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +/* +$begin sparse_hes$$ +$spell + const + Taylor + rc + rcv + nr + nc + hes + std + cppad + colpack + cmake + Jacobian +$$ + +$section Computing Sparse Hessians$$ + +$head Syntax$$ +$icode%n_sweep% = %f%.sparse_hes( + %x%, %w%, %subset%, %pattern%, %coloring%, %work% +)%$$ + +$head Purpose$$ +We use $latex F : \B{R}^n \rightarrow \B{R}^m$$ to denote the +function corresponding to $icode f$$. +Here $icode n$$ is the $cref/domain/seq_property/Domain/$$ size, +and $icode m$$ is the $cref/range/seq_property/Range/$$ size, or $icode f$$. +The syntax above takes advantage of sparsity when computing the Hessian +$latex \[ + H(x) = \dpow{2}{x} \sum_{i=0}^{m-1} w_i F_i (x) +\] $$ +In the sparse case, this should be faster and take less memory than +$cref Hessian$$. +The matrix element $latex H_{i,j} (x)$$ is the second partial of +$latex w^\R{T} F (x)$$ with respect to $latex x_i$$ and $latex x_j$$. + +$head SizeVector$$ +The type $icode SizeVector$$ is a $cref SimpleVector$$ class with +$cref/elements of type/SimpleVector/Elements of Specified Type/$$ +$code size_t$$. + +$head BaseVector$$ +The type $icode BaseVector$$ is a $cref SimpleVector$$ class with +$cref/elements of type/SimpleVector/Elements of Specified Type/$$ +$code size_t$$. + +$head f$$ +This object has prototype +$codei% + ADFun<%Base%> %f% +%$$ +Note that the Taylor coefficients stored in $icode f$$ are affected +by this operation; see +$cref/uses forward/sparse_hes/Uses Forward/$$ below. + +$head x$$ +This argument has prototype +$codei% + const %BaseVector%& %x% +%$$ +and its size is $icode n$$. +It specifies the point at which to evaluate the Hessian +$latex H(x)$$. + +$head w$$ +This argument has prototype +$codei% + const %BaseVector%& %w% +%$$ +and its size is $icode m$$. +It specifies the weight for each of the components of $latex F(x)$$; +i.e. $latex w_i$$ is the weight for $latex F_i (x)$$. + +$head subset$$ +This argument has prototype +$codei% + sparse_rcv<%SizeVector%, %BaseVector%>& %subset% +%$$ +Its row size and column size is $icode n$$; i.e., +$icode%subset%.nr() == %n%$$ and $icode%subset%.nc() == %n%$$. +It specifies which elements of the Hessian are computed. +$list number$$ +The input value of its value vector +$icode%subset%.val()%$$ does not matter. +Upon return it contains the value of the corresponding elements +of the Hessian. +$lnext +All of the row, column pairs in $icode subset$$ must also appear in +$icode pattern$$; i.e., they must be possibly non-zero. +$lnext +The Hessian is symmetric, so one has a choice as to which off diagonal +elements to put in $icode subset$$. +It will probably be more efficient if one makes this choice so that +the there are more entries in each non-zero column of $icode subset$$; +see $cref/n_sweep/sparse_hes/n_sweep/$$ below. +$lend + +$head pattern$$ +This argument has prototype +$codei% + const sparse_rc<%SizeVector%>& %pattern% +%$$ +Its row size and column size is $icode n$$; i.e., +$icode%pattern%.nr() == %n%$$ and $icode%pattern%.nc() == %n%$$. +It is a sparsity pattern for the Hessian $latex H(x)$$. +If the $th i$$ row ($th j$$ column) does not appear in $icode subset$$, +the $th i$$ row ($th j$$ column) of $icode pattern$$ does not matter +and need not be computed. +This argument is not used (and need not satisfy any conditions), +when $cref/work/sparse_hes/work/$$ is non-empty. + +$subhead subset$$ +If the $th i$$ row and $th i$$ column do not appear in $icode subset$$, +the $th i$$ row and column of $icode pattern$$ do not matter. +In this case the $th i-th$$ row and column may have no entries in +$icode pattern$$ even though they are possibly non-zero in $latex H(x)$$. +(This can be used to reduce the amount of computation required to find +$icode pattern$$.) + +$head coloring$$ +The coloring algorithm determines which rows and columns +can be computed during the same sweep. +This field has prototype +$codei% + const std::string& %coloring% +%$$ +This value only matters when work is empty; i.e., +after the $icode work$$ constructor or $icode%work%.clear()%$$. + +$subhead cppad.symmetric$$ +This coloring takes advantage of the fact that the Hessian matrix +is symmetric when find a coloring that requires fewer +$cref/sweeps/sparse_hes/n_sweep/$$. + +$subhead cppad.general$$ +This is the same as the sparse Jacobian +$cref/cppad/sparse_jac/coloring/cppad/$$ method +which does not take advantage of symmetry. + +$subhead colpack.symmetric$$ +If $cref colpack_prefix$$ was specified on the +$cref/cmake command/cmake/CMake Command/$$ line, +you can set $icode coloring$$ to $code colpack.symmetric$$. +This also takes advantage of the fact that the Hessian matrix is symmetric. + +$subhead colpack.general$$ +If $cref colpack_prefix$$ was specified on the +$cref/cmake command/cmake/CMake Command/$$ line, +you can set $icode coloring$$ to $code colpack.general$$. +This is the same as the sparse Jacobian +$cref/colpack/sparse_jac/coloring/colpack/$$ method +which does not take advantage of symmetry. + +$subhead colpack.star Deprecated 2017-06-01$$ +The $code colpack.star$$ method is deprecated. +It is the same as the $code colpack.symmetric$$ method +which should be used instead. + + +$head work$$ +This argument has prototype +$codei% + sparse_hes_work& %work% +%$$ +We refer to its initial value, +and its value after $icode%work%.clear()%$$, as empty. +If it is empty, information is stored in $icode work$$. +This can be used to reduce computation when +a future call is for the same object $icode f$$, +and the same subset of the Hessian. +In fact, it can be used with a different $icode f$$ +and a different $icode subset$$ provided that Hessian sparsity pattern +for $icode f$$ and the sparsity pattern in $icode subset$$ are the same. +If either of these values change, use $icode%work%.clear()%$$ to +empty this structure. + +$head n_sweep$$ +The return value $icode n_sweep$$ has prototype +$codei% + size_t %n_sweep% +%$$ +It is the number of first order forward sweeps +used to compute the requested Hessian values. +Each first forward sweep is followed by a second order reverse sweep +so it is also the number of reverse sweeps. +It is also the number of colors determined by the coloring method +mentioned above. +This is proportional to the total computational work, +not counting the zero order forward sweep, +or combining multiple columns and rows into a single sweep. + +$head Uses Forward$$ +After each call to $cref Forward$$, +the object $icode f$$ contains the corresponding +$cref/Taylor coefficients/glossary/Taylor Coefficient/$$. +After a call to $code sparse_hes$$ +the zero order coefficients correspond to +$codei% + %f%.Forward(0, %x%) +%$$ +All the other forward mode coefficients are unspecified. + +$head Example$$ +$children% + example/sparse/sparse_hes.cpp +%$$ +The files $cref sparse_hes.cpp$$ +is an example and test of $code sparse_hes$$. +It returns $code true$$, if it succeeds, and $code false$$ otherwise. + +$head Subset Hessian$$ +The routine +$cref sparse_sub_hes.cpp$$ +is an example and test that compute a subset of a sparse Hessian. +It returns $code true$$, for success, and $code false$$ otherwise. + +$end +*/ +# include +# include +# include +# include + +/*! +\file sparse_hes.hpp +Sparse Hessian calculation routines. +*/ +namespace CppAD { // BEGIN_CPPAD_NAMESPACE + +/*! +Class used to hold information used by Sparse Hessian routine in this file, +so it does not need to be recomputed every time. +*/ +class sparse_hes_work { + public: + /// row and column indicies for return values + /// (some may be reflected by symmetric coloring algorithms) + CppAD::vector row; + CppAD::vector col; + /// indices that sort the row and col arrays by color + CppAD::vector order; + /// results of the coloring algorithm + CppAD::vector color; + + /// constructor + sparse_hes_work(void) + { } + /// inform CppAD that this information needs to be recomputed + void clear(void) + { + row.clear(); + col.clear(); + order.clear(); + color.clear(); + } +}; +// ---------------------------------------------------------------------------- +/*! +Calculate sparse Hessians using forward mode + +\tparam Base +the base type for the recording that is stored in the ADFun object. + +\tparam SizeVector +a simple vector class with elements of type size_t. + +\tparam BaseVector +a simple vector class with elements of type Base. + +\param x +a vector of length n, the number of independent variables in f +(this ADFun object). + +\param w +a vector of length m, the number of dependent variables in f +(this ADFun object). + +\param subset +specifices the subset of the sparsity pattern where the Hessian is evaluated. +subset.nr() == n, +subset.nc() == n. + +\param pattern +is a sparsity pattern for the Hessian of w^T * f; +pattern.nr() == n, +pattern.nc() == n, +where m is number of dependent variables in f. + +\param coloring +determines which coloring algorithm is used. +This must be cppad.symmetric, cppad.general, colpack.symmetic, +or colpack.star. + +\param work +this structure must be empty, or contain the information stored +by a previous call to sparse_hes. +The previous call must be for the same ADFun object f +and the same subset. + +\return +This is the number of first order forward +(and second order reverse) sweeps used to compute thhe Hessian. +*/ +template +template +size_t ADFun::sparse_hes( + const BaseVector& x , + const BaseVector& w , + sparse_rcv& subset , + const sparse_rc& pattern , + const std::string& coloring , + sparse_hes_work& work ) +{ size_t n = Domain(); + // + CPPAD_ASSERT_KNOWN( + subset.nr() == n, + "sparse_hes: subset.nr() not equal domain dimension for f" + ); + CPPAD_ASSERT_KNOWN( + subset.nc() == n, + "sparse_hes: subset.nc() not equal domain dimension for f" + ); + CPPAD_ASSERT_KNOWN( + size_t( x.size() ) == n, + "sparse_hes: x.size() not equal domain dimension for f" + ); + CPPAD_ASSERT_KNOWN( + size_t( w.size() ) == Range(), + "sparse_hes: w.size() not equal range dimension for f" + ); + // + // work information + vector& row(work.row); + vector& col(work.col); + vector& color(work.color); + vector& order(work.order); + // + // subset information + const SizeVector& subset_row( subset.row() ); + const SizeVector& subset_col( subset.col() ); + // + // point at which we are evaluationg the Hessian + Forward(0, x); + // + // number of elements in the subset + size_t K = subset.nnz(); + // + // check for case were there is nothing to do + // (except for call to Forward(0, x) + if( K == 0 ) + return 0; + // +# ifndef NDEBUG + if( color.size() != 0 ) + { CPPAD_ASSERT_KNOWN( + color.size() == n, + "sparse_hes: work is non-empty and conditions have changed" + ); + CPPAD_ASSERT_KNOWN( + row.size() == K, + "sparse_hes: work is non-empty and conditions have changed" + ); + CPPAD_ASSERT_KNOWN( + col.size() == K, + "sparse_hes: work is non-empty and conditions have changed" + ); + // + for(size_t k = 0; k < K; k++) + { bool ok = row[k] == subset_row[k] && col[k] == subset_col[k]; + ok |= row[k] == subset_col[k] && col[k] == subset_row[k]; + CPPAD_ASSERT_KNOWN( + ok, + "sparse_hes: work is non-empty and conditions have changed" + ); + } + } +# endif + // + // check for case where input work is empty + if( color.size() == 0 ) + { // compute work color and order vectors + CPPAD_ASSERT_KNOWN( + pattern.nr() == n, + "sparse_hes: pattern.nr() not equal domain dimension for f" + ); + CPPAD_ASSERT_KNOWN( + pattern.nc() == n, + "sparse_hes: pattern.nc() not equal domain dimension for f" + ); + // + // initialize work row, col to be same as subset row, col + row.resize(K); + col.resize(K); + // cannot assign vectors becasue may be of different types + // (SizeVector and CppAD::vector) + for(size_t k = 0; k < K; k++) + { row[k] = subset_row[k]; + col[k] = subset_col[k]; + } + // + // convert pattern to an internal version of its transpose + local::pod_vector internal_index(n); + for(size_t j = 0; j < n; j++) + internal_index[j] = j; + bool transpose = true; + bool zero_empty = false; + bool input_empty = true; + local::sparse::list_setvec internal_pattern; + internal_pattern.resize(n, n); + local::sparse::set_internal_pattern(zero_empty, input_empty, + transpose, internal_index, internal_pattern, pattern + ); + // + // execute coloring algorithm + // (we are using transpose becasue coloring groups rows, not columns) + color.resize(n); + if( coloring == "cppad.general" ) + local::color_general_cppad(internal_pattern, col, row, color); + else if( coloring == "cppad.symmetric" ) + local::color_symmetric_cppad(internal_pattern, col, row, color); + else if( coloring == "colpack.general" ) + { +# if CPPAD_HAS_COLPACK + local::color_general_colpack(internal_pattern, col, row, color); +# else + CPPAD_ASSERT_KNOWN( + false, + "sparse_hes: coloring = colpack.star " + "and colpack_prefix not in cmake command line." + ); +# endif + } + else if( + coloring == "colpack.symmetric" || + coloring == "colpack.star" + ) + { +# if CPPAD_HAS_COLPACK + local::color_symmetric_colpack(internal_pattern, col, row, color); +# else + CPPAD_ASSERT_KNOWN( + false, + "sparse_hes: coloring = colpack.symmetic or colpack.star " + "and colpack_prefix not in cmake command line." + ); +# endif + } + else CPPAD_ASSERT_KNOWN( + false, + "sparse_hes: coloring is not valid." + ); + // + // put sorting indices in color order + SizeVector key(K); + order.resize(K); + for(size_t k = 0; k < K; k++) + key[k] = color[ col[k] ]; + index_sort(key, order); + } + // Base versions of zero and one + Base one(1.0); + Base zero(0.0); + // + size_t n_color = 1; + for(size_t j = 0; j < n; j++) if( color[j] < n ) + n_color = std::max(n_color, color[j] + 1); + // + // initialize the return Hessian values as zero + for(size_t k = 0; k < K; k++) + subset.set(k, zero); + // + // direction vector for calls to first order forward + BaseVector dx(n); + // + // return values for calls to second order reverse + BaseVector ddw(2 * n); + // + // loop over colors + size_t k = 0; + for(size_t ell = 0; ell < n_color; ell++) + if( k == K ) + { // kludge because colpack returns colors that are not used + // (it does not know about the subset corresponding to row, col) + CPPAD_ASSERT_UNKNOWN( + coloring == "colpack.general" || + coloring == "colpack.symmetric" || + coloring == "colpack.star" + ); + } + else if( color[ col[ order[k] ] ] != ell ) + { // kludge because colpack returns colors that are not used + // (it does not know about the subset corresponding to row, col) + CPPAD_ASSERT_UNKNOWN( + coloring == "colpack.general" || + coloring == "colpack.symmetic" || + coloring == "colpack.star" + ); + } + else + { CPPAD_ASSERT_UNKNOWN( color[ col[ order[k] ] ] == ell ); + // + // combine all columns with this color + for(size_t j = 0; j < n; j++) + { dx[j] = zero; + if( color[j] == ell ) + dx[j] = one; + } + // call forward mode for all these rows at once + Forward(1, dx); + // + // evaluate derivative of w^T * F'(x) * dx + ddw = Reverse(2, w); + // + // set the corresponding components of the result + while( k < K && color[ col[order[k]] ] == ell ) + { size_t index = row[ order[k] ] * 2 + 1; + subset.set(order[k], ddw[index] ); + k++; + } + } + // check that all the required entries have been set + CPPAD_ASSERT_UNKNOWN( k == K ); + return n_color; +} + +} // END_CPPAD_NAMESPACE + +# endif diff --git a/build-config/cppad/include/cppad/core/sparse_hessian.hpp b/build-config/cppad/include/cppad/core/sparse_hessian.hpp new file mode 100644 index 00000000..94115da2 --- /dev/null +++ b/build-config/cppad/include/cppad/core/sparse_hessian.hpp @@ -0,0 +1,861 @@ +# ifndef CPPAD_CORE_SPARSE_HESSIAN_HPP +# define CPPAD_CORE_SPARSE_HESSIAN_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +/* +$begin sparse_hessian$$ +$spell + jacobian + recomputed + CppAD + valarray + std + Bool + hes + const + Taylor + cppad + cmake + colpack +$$ + +$section Sparse Hessian$$ + +$head Syntax$$ +$icode%hes% = %f%.SparseHessian(%x%, %w%) +%hes% = %f%.SparseHessian(%x%, %w%, %p%) +%n_sweep% = %f%.SparseHessian(%x%, %w%, %p%, %row%, %col%, %hes%, %work%) +%$$ + +$head Purpose$$ +We use $latex n$$ for the $cref/domain/seq_property/Domain/$$ size, +and $latex m$$ for the $cref/range/seq_property/Range/$$ size of $icode f$$. +We use $latex F : \B{R}^n \rightarrow \B{R}^m$$ do denote the +$cref/AD function/glossary/AD Function/$$ +corresponding to $icode f$$. +The syntax above sets $icode hes$$ to the Hessian +$latex \[ + H(x) = \dpow{2}{x} \sum_{i=1}^m w_i F_i (x) +\] $$ +This routine takes advantage of the sparsity of the Hessian +in order to reduce the amount of computation necessary. +If $icode row$$ and $icode col$$ are present, it also takes +advantage of the reduced set of elements of the Hessian that +need to be computed. +One can use speed tests (e.g. $cref speed_test$$) +to verify that results are computed faster +than when using the routine $cref Hessian$$. + +$head f$$ +The object $icode f$$ has prototype +$codei% + ADFun<%Base%> %f% +%$$ +Note that the $cref ADFun$$ object $icode f$$ is not $code const$$ +(see $cref/Uses Forward/sparse_hessian/Uses Forward/$$ below). + +$head x$$ +The argument $icode x$$ has prototype +$codei% + const %BaseVector%& %x% +%$$ +(see $cref/BaseVector/sparse_hessian/BaseVector/$$ below) +and its size +must be equal to $icode n$$, the dimension of the +$cref/domain/seq_property/Domain/$$ space for $icode f$$. +It specifies +that point at which to evaluate the Hessian. + +$head w$$ +The argument $icode w$$ has prototype +$codei% + const %BaseVector%& %w% +%$$ +and size $latex m$$. +It specifies the value of $latex w_i$$ in the expression +for $icode hes$$. +The more components of $latex w$$ that are identically zero, +the more sparse the resulting Hessian may be (and hence the more efficient +the calculation of $icode hes$$ may be). + +$head p$$ +The argument $icode p$$ is optional and has prototype +$codei% + const %SetVector%& %p% +%$$ +(see $cref/SetVector/sparse_hessian/SetVector/$$ below) +If it has elements of type $code bool$$, +its size is $latex n * n$$. +If it has elements of type $code std::set$$, +its size is $latex n$$ and all its set elements are between +zero and $latex n - 1$$. +It specifies a +$cref/sparsity pattern/glossary/Sparsity Pattern/$$ +for the Hessian $latex H(x)$$. + +$subhead Purpose$$ +If this sparsity pattern does not change between calls to +$codei SparseHessian$$, it should be faster to calculate $icode p$$ once and +pass this argument to $codei SparseHessian$$. +If you specify $icode p$$, CppAD will use the same +type of sparsity representation +(vectors of $code bool$$ or vectors of $code std::set$$) +for its internal calculations. +Otherwise, the representation +for the internal calculations is unspecified. + +$subhead work$$ +If you specify $icode work$$ in the calling sequence, +it is not necessary to keep the sparsity pattern; see the heading +$cref/p/sparse_hessian/work/p/$$ under the $icode work$$ description. + +$subhead Column Subset$$ +If the arguments $icode row$$ and $icode col$$ are present, +and $cref/color_method/sparse_hessian/work/color_method/$$ is +$code cppad.general$$ or $code cppad.symmetric$$, +it is not necessary to compute the entire sparsity pattern. +Only the following subset of column values will matter: +$codei% + { %col%[%k%] : %k% = 0 , %...% , %K%-1 } +%$$. + + +$head row, col$$ +The arguments $icode row$$ and $icode col$$ are optional and have prototype +$codei% + const %SizeVector%& %row% + const %SizeVector%& %col% +%$$ +(see $cref/SizeVector/sparse_hessian/SizeVector/$$ below). +They specify which rows and columns of $latex H (x)$$ are +returned and in what order. +We use $latex K$$ to denote the value $icode%hes%.size()%$$ +which must also equal the size of $icode row$$ and $icode col$$. +Furthermore, +for $latex k = 0 , \ldots , K-1$$, it must hold that +$latex row[k] < n$$ and $latex col[k] < n$$. +In addition, +all of the $latex (row[k], col[k])$$ pairs must correspond to a true value +in the sparsity pattern $icode p$$. + +$head hes$$ +The result $icode hes$$ has prototype +$codei% + %BaseVector% %hes% +%$$ +In the case where $icode row$$ and $icode col$$ are not present, +the size of $icode hes$$ is $latex n * n$$ and +its size is $latex n * n$$. +In this case, for $latex i = 0 , \ldots , n - 1 $$ +and $latex ell = 0 , \ldots , n - 1$$ +$latex \[ + hes [ j * n + \ell ] = \DD{ w^{\rm T} F }{ x_j }{ x_\ell } ( x ) +\] $$ +$pre + +$$ +In the case where the arguments $icode row$$ and $icode col$$ are present, +we use $latex K$$ to denote the size of $icode hes$$. +The input value of its elements does not matter. +Upon return, for $latex k = 0 , \ldots , K - 1$$, +$latex \[ + hes [ k ] = \DD{ w^{\rm T} F }{ x_j }{ x_\ell } (x) + \; , \; + \; {\rm where} \; + j = row[k] + \; {\rm and } \; + \ell = col[k] +\] $$ + +$head work$$ +If this argument is present, it has prototype +$codei% + sparse_hessian_work& %work% +%$$ +This object can only be used with the routines $code SparseHessian$$. +During its the first use, information is stored in $icode work$$. +This is used to reduce the work done by future calls to $code SparseHessian$$ +with the same $icode f$$, $icode p$$, $icode row$$, and $icode col$$. +If a future call is made where any of these values have changed, +you must first call $icode%work%.clear()%$$ +to inform CppAD that this information needs to be recomputed. + +$subhead color_method$$ +The coloring algorithm determines which rows and columns +can be computed during the same sweep. +This field has prototype +$codei% + std::string %work%.color_method +%$$ +This value only matters on the first call to $code sparse_hessian$$ that +follows the $icode work$$ constructor or a call to +$icode%work%.clear()%$$. +$codei% + +"cppad.symmetric" +%$$ +This is the default coloring method (after a constructor or $code clear()$$). +It takes advantage of the fact that the Hessian matrix +is symmetric to find a coloring that requires fewer +$cref/sweeps/sparse_hessian/n_sweep/$$. +$codei% + +"cppad.general" +%$$ +This is the same as the $code "cppad"$$ method for the +$cref/sparse_jacobian/sparse_jacobian/work/color_method/$$ calculation. +$codei% + +"colpack.symmetric" +%$$ +This method requires that +$cref colpack_prefix$$ was specified on the +$cref/cmake command/cmake/CMake Command/$$ line. +It also takes advantage of the fact that the Hessian matrix is symmetric. +$codei% + +"colpack.general" +%$$ +This is the same as the $code "colpack"$$ method for the +$cref/sparse_jacobian/sparse_jacobian/work/color_method/$$ calculation. + +$subhead colpack.star Deprecated 2017-06-01$$ +The $code colpack.star$$ method is deprecated. +It is the same as the $code colpack.symmetric$$ +which should be used instead. + +$subhead p$$ +If $icode work$$ is present, and it is not the first call after +its construction or a clear, +the sparsity pattern $icode p$$ is not used. +This enables one to free the sparsity pattern +and still compute corresponding sparse Hessians. + +$head n_sweep$$ +The return value $icode n_sweep$$ has prototype +$codei% + size_t %n_sweep% +%$$ +It is the number of first order forward sweeps +used to compute the requested Hessian values. +Each first forward sweep is followed by a second order reverse sweep +so it is also the number of reverse sweeps. +This is proportional to the total work that $code SparseHessian$$ does, +not counting the zero order forward sweep, +or the work to combine multiple columns into a single +forward-reverse sweep pair. + +$head BaseVector$$ +The type $icode BaseVector$$ must be a $cref SimpleVector$$ class with +$cref/elements of type/SimpleVector/Elements of Specified Type/$$ +$icode Base$$. +The routine $cref CheckSimpleVector$$ will generate an error message +if this is not the case. + +$head SetVector$$ +The type $icode SetVector$$ must be a $cref SimpleVector$$ class with +$cref/elements of type/SimpleVector/Elements of Specified Type/$$ +$code bool$$ or $code std::set$$; +see $cref/sparsity pattern/glossary/Sparsity Pattern/$$ for a discussion +of the difference. +The routine $cref CheckSimpleVector$$ will generate an error message +if this is not the case. + +$subhead Restrictions$$ +If $icode SetVector$$ has elements of $code std::set$$, +then $icode%p%[%i%]%$$ must return a reference (not a copy) to the +corresponding set. +According to section 26.3.2.3 of the 1998 C++ standard, +$code std::valarray< std::set >$$ does not satisfy +this condition. + +$head SizeVector$$ +The type $icode SizeVector$$ must be a $cref SimpleVector$$ class with +$cref/elements of type/SimpleVector/Elements of Specified Type/$$ +$code size_t$$. +The routine $cref CheckSimpleVector$$ will generate an error message +if this is not the case. + +$head Uses Forward$$ +After each call to $cref Forward$$, +the object $icode f$$ contains the corresponding +$cref/Taylor coefficients/glossary/Taylor Coefficient/$$. +After a call to any of the sparse Hessian routines, +the zero order Taylor coefficients correspond to +$icode%f%.Forward(0, %x%)%$$ +and the other coefficients are unspecified. + +$children% + example/sparse/sparse_hessian.cpp% + example/sparse/sub_sparse_hes.cpp% + example/sparse/sparse_sub_hes.cpp +%$$ + +$head Example$$ +The routine +$cref sparse_hessian.cpp$$ +is examples and tests of $code sparse_hessian$$. +It return $code true$$, if it succeeds and $code false$$ otherwise. + +$head Subset Hessian$$ +The routine +$cref sub_sparse_hes.cpp$$ +is an example and test that compute a sparse Hessian +for a subset of the variables. +It returns $code true$$, for success, and $code false$$ otherwise. + +$end +----------------------------------------------------------------------------- +*/ +# include +# include +# include + +namespace CppAD { // BEGIN_CPPAD_NAMESPACE +/*! +\file sparse_hessian.hpp +Sparse Hessian driver routine and helper functions. +*/ +// =========================================================================== +/*! +class used by SparseHessian to hold information +so it does not need to be recomputed. +*/ +class sparse_hessian_work { + public: + /// Coloring method: "cppad", or "colpack" + /// (this field is set by user) + std::string color_method; + /// row and column indicies for return values + /// (some may be reflected by star coloring algorithm) + CppAD::vector row; + CppAD::vector col; + /// indices that sort the user row and col arrays by color + CppAD::vector order; + /// results of the coloring algorithm + CppAD::vector color; + + /// constructor + sparse_hessian_work(void) : color_method("cppad.symmetric") + { } + /// inform CppAD that this information needs to be recomputed + void clear(void) + { color_method = "cppad.symmetric"; + row.clear(); + col.clear(); + order.clear(); + color.clear(); + } +}; +// =========================================================================== +/*! +Private helper function that does computation for all Sparse Hessian cases. + +\tparam Base +is the base type for the recording that is stored in this ADFun. + +\tparam SizeVector +is sparse_pack or sparse_list. + +\param x [in] +is a vector specifing the point at which to compute the Hessian. + +\param w [in] +is the weighting vector that defines a scalar valued function by +a weighted sum of the components of the vector valued function +$latex F(x)$$. + +\param sparsity [in] +is the sparsity pattern for the Hessian that we are calculating. + +\param user_row [in] +is the vector of row indices for the returned Hessian values. + +\param user_col [in] +is the vector of columns indices for the returned Hessian values. +It must have the same size as user_row. + +\param hes [out] +is the vector of Hessian values. +It must have the same size as user_row. +The return value hes[k] is the second partial of +\f$ w^{\rm T} F(x)\f$ with respect to the +row[k] and col[k] component of \f$ x\f$. + +\param work +This structure contains information that is computed by SparseHessianCompute. +If the sparsity pattern, row vector, or col vectors +are not the same between calls to SparseHessianCompute, + work.clear() must be called to reinitialize work. + +\return +Is the number of first order forward sweeps used to compute the +requested Hessian values. +(This is also equal to the number of second order reverse sweeps.) +The total work, not counting the zero order +forward sweep, or the time to combine computations, is proportional to this +return value. +*/ +template +template +size_t ADFun::SparseHessianCompute( + const BaseVector& x , + const BaseVector& w , + SetVector& sparsity , + const SizeVector& user_row , + const SizeVector& user_col , + BaseVector& hes , + sparse_hessian_work& work ) +{ + using CppAD::vectorBool; + size_t i, k, ell; + + CppAD::vector& row(work.row); + CppAD::vector& col(work.col); + CppAD::vector& color(work.color); + CppAD::vector& order(work.order); + + size_t n = Domain(); + + // some values + const Base zero(0); + const Base one(1); + + // check BaseVector is Simple Vector class with Base type elements + CheckSimpleVector(); + + // number of components of Hessian that are required + size_t K = hes.size(); + CPPAD_ASSERT_UNKNOWN( size_t( user_row.size() ) == K ); + CPPAD_ASSERT_UNKNOWN( size_t( user_col.size() ) == K ); + + CPPAD_ASSERT_UNKNOWN( size_t(x.size()) == n ); + CPPAD_ASSERT_UNKNOWN( color.size() == 0 || color.size() == n ); + CPPAD_ASSERT_UNKNOWN( row.size() == 0 || row.size() == K ); + CPPAD_ASSERT_UNKNOWN( col.size() == 0 || col.size() == K ); + + + // Point at which we are evaluating the Hessian + Forward(0, x); + + // check for case where nothing (except Forward above) to do + if( K == 0 ) + return 0; + + // Rows of the Hessian (i below) correspond to the forward mode index + // and columns (j below) correspond to the reverse mode index. + if( color.size() == 0 ) + { + CPPAD_ASSERT_UNKNOWN( sparsity.n_set() == n ); + CPPAD_ASSERT_UNKNOWN( sparsity.end() == n ); + + // copy user rwo and col to work space + row.resize(K); + col.resize(K); + for(k = 0; k < K; k++) + { row[k] = user_row[k]; + col[k] = user_col[k]; + } + + // execute coloring algorithm + color.resize(n); + if( work.color_method == "cppad.general" ) + local::color_general_cppad(sparsity, row, col, color); + else if( work.color_method == "cppad.symmetric" ) + local::color_symmetric_cppad(sparsity, row, col, color); + else if( work.color_method == "colpack.general" ) + { +# if CPPAD_HAS_COLPACK + local::color_general_colpack(sparsity, row, col, color); +# else + CPPAD_ASSERT_KNOWN( + false, + "SparseHessian: work.color_method = colpack.general " + "and colpack_prefix missing from cmake command line." + ); +# endif + } + else if( + work.color_method == "colpack.symmetric" || + work.color_method == "colpack.star" + ) + { +# if CPPAD_HAS_COLPACK + local::color_symmetric_colpack(sparsity, row, col, color); +# else + CPPAD_ASSERT_KNOWN( + false, + "SparseHessian: work.color_method is " + "colpack.symmetric or colpack.star\n" + "and colpack_prefix missing from cmake command line." + ); +# endif + } + else + { CPPAD_ASSERT_KNOWN( + false, + "SparseHessian: work.color_method is not valid." + ); + } + + // put sorting indices in color order + SizeVector key(K); + order.resize(K); + for(k = 0; k < K; k++) + key[k] = color[ row[k] ]; + index_sort(key, order); + + } + size_t n_color = 1; + for(ell = 0; ell < n; ell++) if( color[ell] < n ) + n_color = std::max(n_color, color[ell] + 1); + + // direction vector for calls to forward (rows of the Hessian) + BaseVector u(n); + + // location for return values from reverse (columns of the Hessian) + BaseVector ddw(2 * n); + + // initialize the return value + for(k = 0; k < K; k++) + hes[k] = zero; + + // loop over colors +# ifndef NDEBUG + const std::string& coloring = work.color_method; +# endif + k = 0; + for(ell = 0; ell < n_color; ell++) + if( k == K ) + { // kludge because colpack returns colors that are not used + // (it does not know about the subset corresponding to row, col) + CPPAD_ASSERT_UNKNOWN( + coloring == "colpack.general" || + coloring == "colpack.symmetic" || + coloring == "colpack.star" + ); + } + else if( color[ row[ order[k] ] ] != ell ) + { // kludge because colpack returns colors that are not used + // (it does not know about the subset corresponding to row, col) + CPPAD_ASSERT_UNKNOWN( + coloring == "colpack.general" || + coloring == "colpack.symmetic" || + coloring == "colpack.star" + ); + } + else + { CPPAD_ASSERT_UNKNOWN( color[ row[ order[k] ] ] == ell ); + + // combine all rows with this color + for(i = 0; i < n; i++) + { u[i] = zero; + if( color[i] == ell ) + u[i] = one; + } + // call forward mode for all these rows at once + Forward(1, u); + + // evaluate derivative of w^T * F'(x) * u + ddw = Reverse(2, w); + + // set the corresponding components of the result + while( k < K && color[ row[ order[k] ] ] == ell ) + { hes[ order[k] ] = ddw[ col[ order[k] ] * 2 + 1 ]; + k++; + } + } + return n_color; +} +// =========================================================================== +// Public Member Functions +// =========================================================================== +/*! +Compute user specified subset of a sparse Hessian. + +The C++ source code corresponding to this operation is +\verbatim + SparceHessian(x, w, p, row, col, hes, work) +\endverbatim + +\tparam Base +is the base type for the recording that is stored in this ADFun. + +\tparam SizeVector +is a simple vector class with elements of type size_t. + +\param x [in] +is a vector specifing the point at which to compute the Hessian. + +\param w [in] +is the weighting vector that defines a scalar valued function by +a weighted sum of the components of the vector valued function +$latex F(x)$$. + +\param p [in] +is the sparsity pattern for the Hessian that we are calculating. + +\param row [in] +is the vector of row indices for the returned Hessian values. + +\param col [in] +is the vector of columns indices for the returned Hessian values. +It must have the same size are r. + +\param hes [out] +is the vector of Hessian values. +It must have the same size are r. +The return value hes[k] is the second partial of +\f$ w^{\rm T} F(x)\f$ with respect to the +row[k] and col[k] component of \f$ x\f$. + +\param work +This structure contains information that is computed by SparseHessianCompute. +If the sparsity pattern, row vector, or col vectors +are not the same between calls to SparseHessian, + work.clear() must be called to reinitialize work. + +\return +Is the number of first order forward sweeps used to compute the +requested Hessian values. +(This is also equal to the number of second order reverse sweeps.) +The total work, not counting the zero order +forward sweep, or the time to combine computations, is proportional to this +return value. +*/ +template +template +size_t ADFun::SparseHessian( + const BaseVector& x , + const BaseVector& w , + const SetVector& p , + const SizeVector& row , + const SizeVector& col , + BaseVector& hes , + sparse_hessian_work& work ) +{ + size_t n = Domain(); + size_t K = hes.size(); +# ifndef NDEBUG + size_t k; + CPPAD_ASSERT_KNOWN( + size_t(x.size()) == n , + "SparseHessian: size of x not equal domain dimension for f." + ); + CPPAD_ASSERT_KNOWN( + size_t(row.size()) == K && size_t(col.size()) == K , + "SparseHessian: either r or c does not have the same size as ehs." + ); + CPPAD_ASSERT_KNOWN( + work.color.size() == 0 || work.color.size() == n, + "SparseHessian: invalid value in work." + ); + for(k = 0; k < K; k++) + { CPPAD_ASSERT_KNOWN( + row[k] < n, + "SparseHessian: invalid value in r." + ); + CPPAD_ASSERT_KNOWN( + col[k] < n, + "SparseHessian: invalid value in c." + ); + } + if( work.color.size() != 0 ) + for(size_t j = 0; j < n; j++) CPPAD_ASSERT_KNOWN( + work.color[j] <= n, + "SparseHessian: invalid value in work." + ); +# endif + // check for case where there is nothing to compute + size_t n_sweep = 0; + if( K == 0 ) + return n_sweep; + + typedef typename SetVector::value_type Set_type; + typedef typename local::sparse::internal_pattern::pattern_type Pattern_type; + Pattern_type s; + if( work.color.size() == 0 ) + { bool transpose = false; + const char* error_msg = "SparseHessian: sparsity pattern" + " does not have proper row or column dimension"; + sparsity_user2internal(s, p, n, n, transpose, error_msg); + } + n_sweep = SparseHessianCompute(x, w, s, row, col, hes, work); + return n_sweep; +} +/*! +Compute a sparse Hessian. + +The C++ source code coresponding to this operation is +\verbatim + hes = SparseHessian(x, w, p) +\endverbatim + + +\tparam Base +is the base type for the recording that is stored in this +ADFun. + +\param x [in] +is a vector specifing the point at which to compute the Hessian. + +\param w [in] +The Hessian is computed for a weighted sum of the components +of the function corresponding to this ADFun object. +The argument w specifies the weights for each component. +It must have size equal to the range dimension for this ADFun object. + +\param p [in] +is a sparsity pattern for the Hessian. + +\return +Will be a vector of size n * n containing the Hessian of +at the point specified by x +(where n is the domain dimension for this ADFun object). +*/ +template +template +BaseVector ADFun::SparseHessian( + const BaseVector& x, const BaseVector& w, const SetVector& p +) +{ size_t i, j, k; + + size_t n = Domain(); + BaseVector hes(n * n); + + CPPAD_ASSERT_KNOWN( + size_t(x.size()) == n, + "SparseHessian: size of x not equal domain size for f." + ); + + typedef typename SetVector::value_type Set_type; + typedef typename local::sparse::internal_pattern::pattern_type Pattern_type; + + // initialize the return value as zero + Base zero(0); + for(i = 0; i < n; i++) + for(j = 0; j < n; j++) + hes[i * n + j] = zero; + + // arguments to SparseHessianCompute + Pattern_type s; + CppAD::vector row; + CppAD::vector col; + sparse_hessian_work work; + bool transpose = false; + const char* error_msg = "SparseHessian: sparsity pattern" + " does not have proper row or column dimension"; + sparsity_user2internal(s, p, n, n, transpose, error_msg); + k = 0; + for(i = 0; i < n; i++) + { typename Pattern_type::const_iterator itr(s, i); + j = *itr; + while( j != s.end() ) + { row.push_back(i); + col.push_back(j); + k++; + j = *(++itr); + } + } + size_t K = k; + BaseVector H(K); + + // now we have folded this into the following case + SparseHessianCompute(x, w, s, row, col, H, work); + + // now set the non-zero return values + for(k = 0; k < K; k++) + hes[ row[k] * n + col[k] ] = H[k]; + + return hes; +} +/*! +Compute a sparse Hessian + +The C++ source code coresponding to this operation is +\verbatim + hes = SparseHessian(x, w) +\endverbatim + + +\tparam Base +is the base type for the recording that is stored in this +ADFun object. +The argument w specifies the weights for each component. +It must have size equal to the range dimension for this ADFun object. + +\return +Will be a vector of size n * n containing the Hessian of +at the point specified by x +(where n is the domain dimension for this ADFun object). +*/ +template +template +BaseVector ADFun::SparseHessian(const BaseVector &x, const BaseVector &w) +{ size_t i, j, k; + typedef CppAD::vectorBool BoolVector; + + size_t m = Range(); + size_t n = Domain(); + + // determine the sparsity pattern p for Hessian of w^T F + BoolVector r(n * n); + for(j = 0; j < n; j++) + { for(k = 0; k < n; k++) + r[j * n + k] = false; + r[j * n + j] = true; + } + ForSparseJac(n, r); + // + BoolVector s(m); + for(i = 0; i < m; i++) + s[i] = w[i] != 0; + BoolVector p = RevSparseHes(n, s); + + // compute sparse Hessian + return SparseHessian(x, w, p); +} + +} // END_CPPAD_NAMESPACE +# endif diff --git a/build-config/cppad/include/cppad/core/sparse_jac.hpp b/build-config/cppad/include/cppad/core/sparse_jac.hpp new file mode 100644 index 00000000..2dd1beb2 --- /dev/null +++ b/build-config/cppad/include/cppad/core/sparse_jac.hpp @@ -0,0 +1,629 @@ +# ifndef CPPAD_CORE_SPARSE_JAC_HPP +# define CPPAD_CORE_SPARSE_JAC_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +/* +$begin sparse_jac$$ +$spell + Jacobian + Jacobians + const + jac + Taylor + rc + rcv + nr + nc + std + Cppad + Colpack + cmake +$$ + +$section Computing Sparse Jacobians$$ + +$head Syntax$$ +$icode%n_color% = %f%.sparse_jac_for( + %group_max%, %x%, %subset%, %pattern%, %coloring%, %work% +) +%$$ +$icode%n_color% = %f%.sparse_jac_rev( + %x%, %subset%, %pattern%, %coloring%, %work% +)%$$ + +$head Purpose$$ +We use $latex F : \B{R}^n \rightarrow \B{R}^m$$ to denote the +function corresponding to $icode f$$. +Here $icode n$$ is the $cref/domain/seq_property/Domain/$$ size, +and $icode m$$ is the $cref/range/seq_property/Range/$$ size, or $icode f$$. +The syntax above takes advantage of sparsity when computing the Jacobian +$latex \[ + J(x) = F^{(1)} (x) +\] $$ +In the sparse case, this should be faster and take less memory than +$cref Jacobian$$. +We use the notation $latex J_{i,j} (x)$$ to denote the partial of +$latex F_i (x)$$ with respect to $latex x_j$$. + +$head SizeVector$$ +The type $icode SizeVector$$ is a $cref SimpleVector$$ class with +$cref/elements of type/SimpleVector/Elements of Specified Type/$$ +$code size_t$$. + +$head BaseVector$$ +The type $icode BaseVector$$ is a $cref SimpleVector$$ class with +$cref/elements of type/SimpleVector/Elements of Specified Type/$$ +$code size_t$$. + +$head sparse_jac_for$$ +This function uses first order forward mode sweeps $cref forward_one$$ +to compute multiple columns of the Jacobian at the same time. + +$head sparse_jac_rev$$ +This uses function first order reverse mode sweeps $cref reverse_one$$ +to compute multiple rows of the Jacobian at the same time. + +$head f$$ +This object has prototype +$codei% + ADFun<%Base%> %f% +%$$ +Note that the Taylor coefficients stored in $icode f$$ are affected +by this operation; see +$cref/uses forward/sparse_jac/Uses Forward/$$ below. + +$head group_max$$ +This argument has prototype +$codei% + size_t %group_max% +%$$ +and must be greater than zero. +It specifies the maximum number of colors to group during +a single forward sweep. +If a single color is in a group, +a single direction for of first order forward mode +$cref forward_one$$ is used for each color. +If multiple colors are in a group, +the multiple direction for of first order forward mode +$cref forward_dir$$ is used with one direction for each color. +This uses separate memory for each direction (more memory), +but my be significantly faster. + +$head x$$ +This argument has prototype +$codei% + const %BaseVector%& %x% +%$$ +and its size is $icode n$$. +It specifies the point at which to evaluate the Jacobian +$latex J(x)$$. + +$head subset$$ +This argument has prototype +$codei% + sparse_rcv<%SizeVector%, %BaseVector%>& %subset% +%$$ +Its row size is $icode%subset%.nr() == %m%$$, +and its column size is $icode%subset%.nc() == %n%$$. +It specifies which elements of the Jacobian are computed. +The input value of its value vector +$icode%subset%.val()%$$ does not matter. +Upon return it contains the value of the corresponding elements +of the Jacobian. +All of the row, column pairs in $icode subset$$ must also appear in +$icode pattern$$; i.e., they must be possibly non-zero. + +$head pattern$$ +This argument has prototype +$codei% + const sparse_rc<%SizeVector%>& %pattern% +%$$ +Its row size is $icode%pattern%.nr() == %m%$$, +and its column size is $icode%pattern%.nc() == %n%$$. +It is a sparsity pattern for the Jacobian $latex J(x)$$. +This argument is not used (and need not satisfy any conditions), +when $cref/work/sparse_jac/work/$$ is non-empty. + +$head coloring$$ +The coloring algorithm determines which rows (reverse) or columns (forward) +can be computed during the same sweep. +This field has prototype +$codei% + const std::string& %coloring% +%$$ +This value only matters when work is empty; i.e., +after the $icode work$$ constructor or $icode%work%.clear()%$$. + +$subhead cppad$$ +This uses a general purpose coloring algorithm written for Cppad. + +$subhead colpack$$ +If $cref colpack_prefix$$ is specified on the +$cref/cmake command/cmake/CMake Command/$$ line, +you can set $icode coloring$$ to $code colpack$$. +This uses a general purpose coloring algorithm that is part of Colpack. + +$head work$$ +This argument has prototype +$codei% + sparse_jac_work& %work% +%$$ +We refer to its initial value, +and its value after $icode%work%.clear()%$$, as empty. +If it is empty, information is stored in $icode work$$. +This can be used to reduce computation when +a future call is for the same object $icode f$$, +the same member function $code sparse_jac_for$$ or $code sparse_jac_rev$$, +and the same subset of the Jacobian. +In fact, it can be used with a different $icode f$$ +and a different $icode subset$$ provided that Jacobian sparsity pattern +for $icode f$$ and the sparsity pattern in $icode subset$$ are the same. +If any of these values change, use $icode%work%.clear()%$$ to +empty this structure. + +$head n_color$$ +The return value $icode n_color$$ has prototype +$codei% + size_t %n_color% +%$$ +If $code sparse_jac_for$$ ($code sparse_jac_rev$$) is used, +$icode n_color$$ is the number of first order forward directions +used to compute the requested Jacobian values. +It is also the number of colors determined by the coloring method +mentioned above. +This is proportional to the total computational work, +not counting the zero order forward sweep, +or combining multiple columns (rows) into a single sweep. +Note that if $icode%group_max% == 1%$$, +or if we are using $code sparse_jac_rev$$, +$icode n_color$$ is equal to the number of sweeps. + +$head Uses Forward$$ +After each call to $cref Forward$$, +the object $icode f$$ contains the corresponding +$cref/Taylor coefficients/glossary/Taylor Coefficient/$$. +After a call to $code sparse_jac_forward$$ or $code sparse_jac_rev$$, +the zero order coefficients correspond to +$codei% + %f%.Forward(0, %x%) +%$$ +All the other forward mode coefficients are unspecified. + +$head Example$$ +$children% + example/sparse/sparse_jac_for.cpp% + example/sparse/sparse_jac_rev.cpp +%$$ +The files $cref sparse_jac_for.cpp$$ and $cref sparse_jac_rev.cpp$$ +are examples and tests of $code sparse_jac_for$$ and $code sparse_jac_rev$$. +They return $code true$$, if they succeed, and $code false$$ otherwise. + +$end +*/ +# include +# include +# include +# include + +/*! +\file sparse_jac.hpp +Sparse Jacobian calculation routines. +*/ +namespace CppAD { // BEGIN_CPPAD_NAMESPACE +/*! +Class used to hold information used by Sparse Jacobian routines in this file, +so they do not need to be recomputed every time. +*/ +class sparse_jac_work { + public: + /// indices that sort the user row and col arrays by color + CppAD::vector order; + /// results of the coloring algorithm + CppAD::vector color; + // + /// constructor + sparse_jac_work(void) + { } + /// reset work to empty. + /// This informs CppAD that color and order need to be recomputed + void clear(void) + { order.clear(); + color.clear(); + } +}; +// ---------------------------------------------------------------------------- +/*! +Calculate sparse Jacobains using forward mode + +\tparam Base +the base type for the recording that is stored in the ADFun object. + +\tparam SizeVector +a simple vector class with elements of type size_t. + +\tparam BaseVector +a simple vector class with elements of type Base. + +\param group_max +specifies the maximum number of colors to group during a single forward sweep. +This must be greater than zero and group_max = 1 minimizes memory usage. + +\param x +a vector of length n, the number of independent variables in f +(this ADFun object). + +\param subset +specifices the subset of the sparsity pattern where the Jacobian is evaluated. +subset.nr() == m, +subset.nc() == n. + +\param pattern +is a sparsity pattern for the Jacobian of f; +pattern.nr() == m, +pattern.nc() == n, +where m is number of dependent variables in f. + +\param coloring +determines which coloring algorithm is used. +This must be cppad or colpack. + +\param work +this structure must be empty, or contain the information stored +by a previous call to sparse_jac_for. +The previous call must be for the same ADFun object f +and the same subset. + +\return +This is the number of first order forward sweeps used to compute +the Jacobian. +*/ +template +template +size_t ADFun::sparse_jac_for( + size_t group_max , + const BaseVector& x , + sparse_rcv& subset , + const sparse_rc& pattern , + const std::string& coloring , + sparse_jac_work& work ) +{ size_t m = Range(); + size_t n = Domain(); + // + CPPAD_ASSERT_KNOWN( + subset.nr() == m, + "sparse_jac_for: subset.nr() not equal range dimension for f" + ); + CPPAD_ASSERT_KNOWN( + subset.nc() == n, + "sparse_jac_for: subset.nc() not equal domain dimension for f" + ); + // + // row and column vectors in subset + const SizeVector& row( subset.row() ); + const SizeVector& col( subset.col() ); + // + vector& color(work.color); + vector& order(work.order); + CPPAD_ASSERT_KNOWN( + color.size() == 0 || color.size() == n, + "sparse_jac_for: work is non-empty and conditions have changed" + ); + // + // point at which we are evaluationg the Jacobian + Forward(0, x); + // + // number of elements in the subset + size_t K = subset.nnz(); + // + // check for case were there is nothing to do + // (except for call to Forward(0, x) + if( K == 0 ) + return 0; + // + // check for case where input work is empty + if( color.size() == 0 ) + { // compute work color and order vectors + CPPAD_ASSERT_KNOWN( + pattern.nr() == m, + "sparse_jac_for: pattern.nr() not equal range dimension for f" + ); + CPPAD_ASSERT_KNOWN( + pattern.nc() == n, + "sparse_jac_for: pattern.nc() not equal domain dimension for f" + ); + // + // convert pattern to an internal version of its transpose + local::pod_vector internal_index(n); + for(size_t j = 0; j < n; j++) + internal_index[j] = j; + bool transpose = true; + bool zero_empty = false; + bool input_empty = true; + local::sparse::list_setvec pattern_transpose; + pattern_transpose.resize(n, m); + local::sparse::set_internal_pattern(zero_empty, input_empty, + transpose, internal_index, pattern_transpose, pattern + ); + // + // execute coloring algorithm + // (we are using transpose because coloring groups rows, not columns). + color.resize(n); + if( coloring == "cppad" ) + local::color_general_cppad(pattern_transpose, col, row, color); + else if( coloring == "colpack" ) + { +# if CPPAD_HAS_COLPACK + local::color_general_colpack(pattern_transpose, col, row, color); +# else + CPPAD_ASSERT_KNOWN( + false, + "sparse_jac_for: coloring = colpack " + "and colpack_prefix missing from cmake command line." + ); +# endif + } + else CPPAD_ASSERT_KNOWN( + false, + "sparse_jac_for: coloring is not valid." + ); + // + // put sorting indices in color order + SizeVector key(K); + order.resize(K); + for(size_t k = 0; k < K; k++) + key[k] = color[ col[k] ]; + index_sort(key, order); + } + // Base versions of zero and one + Base one(1.0); + Base zero(0.0); + // + size_t n_color = 1; + for(size_t j = 0; j < n; j++) if( color[j] < n ) + n_color = std::max(n_color, color[j] + 1); + // + // initialize the return Jacobian values as zero + for(size_t k = 0; k < K; k++) + subset.set(k, zero); + // + // index in subset + size_t k = 0; + // number of colors computed so far + size_t color_count = 0; + // + while( color_count < n_color ) + { // number of colors that will be in this group + size_t group_size = std::min(group_max, n_color - color_count); + // + // forward mode values for independent and dependent variables + BaseVector dx(n * group_size), dy(m * group_size); + // + // set dx + for(size_t ell = 0; ell < group_size; ell++) + { // combine all columns with this color + for(size_t j = 0; j < n; j++) + { dx[j * group_size + ell] = zero; + if( color[j] == ell + color_count ) + dx[j * group_size + ell] = one; + } + } + if( group_size == 1 ) + dy = Forward(1, dx); + else + dy = Forward(1, group_size, dx); + // + // store results in subset + for(size_t ell = 0; ell < group_size; ell++) + { // color with index ell + color_count is in this group + while(k < K && color[ col[ order[k] ] ] == ell + color_count ) + { // subset element with index order[k] is included in this color + size_t r = row[ order[k] ]; + subset.set( order[k], dy[ r * group_size + ell ] ); + ++k; + } + } + // advance color count + color_count += group_size; + } + CPPAD_ASSERT_UNKNOWN( color_count == n_color ); + // + return n_color; +} +// ---------------------------------------------------------------------------- +/*! +Calculate sparse Jacobains using reverse mode + +\tparam Base +the base type for the recording that is stored in the ADFun object. + +\tparam SizeVector +a simple vector class with elements of type size_t. + +\tparam BaseVector +a simple vector class with elements of type Base. + +\param x +a vector of length n, the number of independent variables in f +(this ADFun object). + +\param subset +specifices the subset of the sparsity pattern where the Jacobian is evaluated. +subset.nr() == m, +subset.nc() == n. + +\param pattern +is a sparsity pattern for the Jacobian of f; +pattern.nr() == m, +pattern.nc() == n, +where m is number of dependent variables in f. + +\param coloring +determines which coloring algorithm is used. +This must be cppad or colpack. + +\param work +this structure must be empty, or contain the information stored +by a previous call to sparse_jac_rev. +The previous call must be for the same ADFun object f +and the same subset. + +\return +This is the number of first order reverse sweeps used to compute +the Jacobian. +*/ +template +template +size_t ADFun::sparse_jac_rev( + const BaseVector& x , + sparse_rcv& subset , + const sparse_rc& pattern , + const std::string& coloring , + sparse_jac_work& work ) +{ size_t m = Range(); + size_t n = Domain(); + // + CPPAD_ASSERT_KNOWN( + subset.nr() == m, + "sparse_jac_rev: subset.nr() not equal range dimension for f" + ); + CPPAD_ASSERT_KNOWN( + subset.nc() == n, + "sparse_jac_rev: subset.nc() not equal domain dimension for f" + ); + // + // row and column vectors in subset + const SizeVector& row( subset.row() ); + const SizeVector& col( subset.col() ); + // + vector& color(work.color); + vector& order(work.order); + CPPAD_ASSERT_KNOWN( + color.size() == 0 || color.size() == m, + "sparse_jac_rev: work is non-empty and conditions have changed" + ); + // + // point at which we are evaluationg the Jacobian + Forward(0, x); + // + // number of elements in the subset + size_t K = subset.nnz(); + // + // check for case were there is nothing to do + // (except for call to Forward(0, x) + if( K == 0 ) + return 0; + // + // check for case where input work is empty + if( color.size() == 0 ) + { // compute work color and order vectors + CPPAD_ASSERT_KNOWN( + pattern.nr() == m, + "sparse_jac_rev: pattern.nr() not equal range dimension for f" + ); + CPPAD_ASSERT_KNOWN( + pattern.nc() == n, + "sparse_jac_rev: pattern.nc() not equal domain dimension for f" + ); + // + // convert pattern to an internal version + local::pod_vector internal_index(m); + for(size_t i = 0; i < m; i++) + internal_index[i] = i; + bool transpose = false; + bool zero_empty = false; + bool input_empty = true; + local::sparse::list_setvec internal_pattern; + internal_pattern.resize(m, n); + local::sparse::set_internal_pattern(zero_empty, input_empty, + transpose, internal_index, internal_pattern, pattern + ); + // + // execute coloring algorithm + color.resize(m); + if( coloring == "cppad" ) + local::color_general_cppad(internal_pattern, row, col, color); + else if( coloring == "colpack" ) + { +# if CPPAD_HAS_COLPACK + local::color_general_colpack(internal_pattern, row, col, color); +# else + CPPAD_ASSERT_KNOWN( + false, + "sparse_jac_rev: coloring = colpack " + "and colpack_prefix missing from cmake command line." + ); +# endif + } + else CPPAD_ASSERT_KNOWN( + false, + "sparse_jac_rev: coloring is not valid." + ); + // + // put sorting indices in color order + SizeVector key(K); + order.resize(K); + for(size_t k = 0; k < K; k++) + key[k] = color[ row[k] ]; + index_sort(key, order); + } + // Base versions of zero and one + Base one(1.0); + Base zero(0.0); + // + size_t n_color = 1; + for(size_t i = 0; i < m; i++) if( color[i] < m ) + n_color = std::max(n_color, color[i] + 1); + // + // initialize the return Jacobian values as zero + for(size_t k = 0; k < K; k++) + subset.set(k, zero); + // + // weighting vector and return values for calls to Reverse + BaseVector w(m), dw(n); + // + // loop over colors + size_t k = 0; + for(size_t ell = 0; ell < n_color; ell++) + if( k == K ) + { // kludge because colpack returns colors that are not used + // (it does not know about the subset corresponding to row, col) + CPPAD_ASSERT_UNKNOWN( coloring == "colpack" ); + } + else if( color[ row[ order[k] ] ] != ell ) + { // kludge because colpack returns colors that are not used + // (it does not know about the subset corresponding to row, col) + CPPAD_ASSERT_UNKNOWN( coloring == "colpack" ); + } + else + { CPPAD_ASSERT_UNKNOWN( color[ row[ order[k] ] ] == ell ); + // + // combine all rows with this color + for(size_t i = 0; i < m; i++) + { w[i] = zero; + if( color[i] == ell ) + w[i] = one; + } + // call reverse mode for all these rows at once + dw = Reverse(1, w); + // + // set the corresponding components of the result + while( k < K && color[ row[order[k]] ] == ell ) + { subset.set(order[k], dw[col[order[k]]] ); + k++; + } + } + return n_color; +} + +} // END_CPPAD_NAMESPACE +# endif diff --git a/build-config/cppad/include/cppad/core/sparse_jacobian.hpp b/build-config/cppad/include/cppad/core/sparse_jacobian.hpp new file mode 100644 index 00000000..dfd849eb --- /dev/null +++ b/build-config/cppad/include/cppad/core/sparse_jacobian.hpp @@ -0,0 +1,1086 @@ +# ifndef CPPAD_CORE_SPARSE_JACOBIAN_HPP +# define CPPAD_CORE_SPARSE_JACOBIAN_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +// maximum number of sparse directions to compute at the same time + +// # define CPPAD_SPARSE_JACOBIAN_MAX_MULTIPLE_DIRECTION 1 +# define CPPAD_SPARSE_JACOBIAN_MAX_MULTIPLE_DIRECTION 64 + +/* +$begin sparse_jacobian$$ +$spell + cppad + colpack + cmake + recomputed + valarray + std + CppAD + Bool + jac + Jacobian + Jacobians + const + Taylor +$$ + +$section Sparse Jacobian$$ + +$head Syntax$$ +$icode%jac% = %f%.SparseJacobian(%x%) +%jac% = %f%.SparseJacobian(%x%, %p%) +%n_sweep% = %f%.SparseJacobianForward(%x%, %p%, %row%, %col%, %jac%, %work%) +%n_sweep% = %f%.SparseJacobianReverse(%x%, %p%, %row%, %col%, %jac%, %work%) +%$$ + +$head Purpose$$ +We use $latex n$$ for the $cref/domain/seq_property/Domain/$$ size, +and $latex m$$ for the $cref/range/seq_property/Range/$$ size of $icode f$$. +We use $latex F : \B{R}^n \rightarrow \B{R}^m$$ do denote the +$cref/AD function/glossary/AD Function/$$ +corresponding to $icode f$$. +The syntax above sets $icode jac$$ to the Jacobian +$latex \[ + jac = F^{(1)} (x) +\] $$ +This routine takes advantage of the sparsity of the Jacobian +in order to reduce the amount of computation necessary. +If $icode row$$ and $icode col$$ are present, it also takes +advantage of the reduced set of elements of the Jacobian that +need to be computed. +One can use speed tests (e.g. $cref speed_test$$) +to verify that results are computed faster +than when using the routine $cref Jacobian$$. + +$head f$$ +The object $icode f$$ has prototype +$codei% + ADFun<%Base%> %f% +%$$ +Note that the $cref ADFun$$ object $icode f$$ is not $code const$$ +(see $cref/Uses Forward/sparse_jacobian/Uses Forward/$$ below). + +$head x$$ +The argument $icode x$$ has prototype +$codei% + const %BaseVector%& %x% +%$$ +(see $cref/BaseVector/sparse_jacobian/BaseVector/$$ below) +and its size +must be equal to $icode n$$, the dimension of the +$cref/domain/seq_property/Domain/$$ space for $icode f$$. +It specifies +that point at which to evaluate the Jacobian. + +$head p$$ +The argument $icode p$$ is optional and has prototype +$codei% + const %SetVector%& %p% +%$$ +(see $cref/SetVector/sparse_jacobian/SetVector/$$ below). +If it has elements of type $code bool$$, +its size is $latex m * n$$. +If it has elements of type $code std::set$$, +its size is $latex m$$ and all its set elements are between +zero and $latex n - 1$$. +It specifies a +$cref/sparsity pattern/glossary/Sparsity Pattern/$$ +for the Jacobian $latex F^{(1)} (x)$$. +$pre + +$$ +If this sparsity pattern does not change between calls to +$codei SparseJacobian$$, it should be faster to calculate $icode p$$ once +(using $cref ForSparseJac$$ or $cref RevSparseJac$$) +and then pass $icode p$$ to $codei SparseJacobian$$. +Furthermore, if you specify $icode work$$ in the calling sequence, +it is not necessary to keep the sparsity pattern; see the heading +$cref/p/sparse_jacobian/work/p/$$ under the $icode work$$ description. +$pre + +$$ +In addition, +if you specify $icode p$$, CppAD will use the same +type of sparsity representation +(vectors of $code bool$$ or vectors of $code std::set$$) +for its internal calculations. +Otherwise, the representation +for the internal calculations is unspecified. + +$head row, col$$ +The arguments $icode row$$ and $icode col$$ are optional and have prototype +$codei% + const %SizeVector%& %row% + const %SizeVector%& %col% +%$$ +(see $cref/SizeVector/sparse_jacobian/SizeVector/$$ below). +They specify which rows and columns of $latex F^{(1)} (x)$$ are +computes and in what order. +Not all the non-zero entries in $latex F^{(1)} (x)$$ need be computed, +but all the entries specified by $icode row$$ and $icode col$$ +must be possibly non-zero in the sparsity pattern. +We use $latex K$$ to denote the value $icode%jac%.size()%$$ +which must also equal the size of $icode row$$ and $icode col$$. +Furthermore, +for $latex k = 0 , \ldots , K-1$$, it must hold that +$latex row[k] < m$$ and $latex col[k] < n$$. + +$head jac$$ +The result $icode jac$$ has prototype +$codei% + %BaseVector%& %jac% +%$$ +In the case where the arguments $icode row$$ and $icode col$$ are not present, +the size of $icode jac$$ is $latex m * n$$ and +for $latex i = 0 , \ldots , m-1$$, +$latex j = 0 , \ldots , n-1$$, +$latex \[ + jac [ i * n + j ] = \D{ F_i }{ x_j } (x) +\] $$ +$pre + +$$ +In the case where the arguments $icode row$$ and $icode col$$ are present, +we use $latex K$$ to denote the size of $icode jac$$. +The input value of its elements does not matter. +Upon return, for $latex k = 0 , \ldots , K - 1$$, +$latex \[ + jac [ k ] = \D{ F_i }{ x_j } (x) + \; , \; + \; {\rm where} \; + i = row[k] + \; {\rm and } \; + j = col[k] +\] $$ + +$head work$$ +If this argument is present, it has prototype +$codei% + sparse_jacobian_work& %work% +%$$ +This object can only be used with the routines +$code SparseJacobianForward$$ and $code SparseJacobianReverse$$. +During its the first use, information is stored in $icode work$$. +This is used to reduce the work done by future calls to the same mode +(forward or reverse), +the same $icode f$$, $icode p$$, $icode row$$, and $icode col$$. +If a future call is for a different mode, +or any of these values have changed, +you must first call $icode%work%.clear()%$$ +to inform CppAD that this information needs to be recomputed. + +$subhead color_method$$ +The coloring algorithm determines which columns (forward mode) +or rows (reverse mode) can be computed during the same sweep. +This field has prototype +$codei% + std::string %work%.color_method +%$$ +and its default value (after a constructor or $code clear()$$) +is $code "cppad"$$. +If $cref colpack_prefix$$ is specified on the +$cref/cmake command/cmake/CMake Command/$$ line, +you can set this method to $code "colpack"$$. +This value only matters on the first call to $code sparse_jacobian$$ +that follows the $icode work$$ constructor or a call to +$icode%work%.clear()%$$. + +$subhead p$$ +If $icode work$$ is present, and it is not the first call after +its construction or a clear, +the sparsity pattern $icode p$$ is not used. +This enables one to free the sparsity pattern +and still compute corresponding sparse Jacobians. + +$head n_sweep$$ +The return value $icode n_sweep$$ has prototype +$codei% + size_t %n_sweep% +%$$ +If $code SparseJacobianForward$$ ($code SparseJacobianReverse$$) is used, +$icode n_sweep$$ is the number of first order forward (reverse) sweeps +used to compute the requested Jacobian values. +(This is also the number of colors determined by the coloring method +mentioned above). +This is proportional to the total work that $code SparseJacobian$$ does, +not counting the zero order forward sweep, +or the work to combine multiple columns (rows) into a single sweep. + +$head BaseVector$$ +The type $icode BaseVector$$ must be a $cref SimpleVector$$ class with +$cref/elements of type/SimpleVector/Elements of Specified Type/$$ +$icode Base$$. +The routine $cref CheckSimpleVector$$ will generate an error message +if this is not the case. + +$head SetVector$$ +The type $icode SetVector$$ must be a $cref SimpleVector$$ class with +$cref/elements of type/SimpleVector/Elements of Specified Type/$$ +$code bool$$ or $code std::set$$; +see $cref/sparsity pattern/glossary/Sparsity Pattern/$$ for a discussion +of the difference. +The routine $cref CheckSimpleVector$$ will generate an error message +if this is not the case. + +$subhead Restrictions$$ +If $icode SetVector$$ has elements of $code std::set$$, +then $icode%p%[%i%]%$$ must return a reference (not a copy) to the +corresponding set. +According to section 26.3.2.3 of the 1998 C++ standard, +$code std::valarray< std::set >$$ does not satisfy +this condition. + +$head SizeVector$$ +The type $icode SizeVector$$ must be a $cref SimpleVector$$ class with +$cref/elements of type/SimpleVector/Elements of Specified Type/$$ +$code size_t$$. +The routine $cref CheckSimpleVector$$ will generate an error message +if this is not the case. + +$head Uses Forward$$ +After each call to $cref Forward$$, +the object $icode f$$ contains the corresponding +$cref/Taylor coefficients/glossary/Taylor Coefficient/$$. +After a call to any of the sparse Jacobian routines, +the zero order Taylor coefficients correspond to +$icode%f%.Forward(0, %x%)%$$ +and the other coefficients are unspecified. + +After $code SparseJacobian$$, +the previous calls to $cref Forward$$ are undefined. + +$head Example$$ +$children% + example/sparse/sparse_jacobian.cpp +%$$ +The routine +$cref sparse_jacobian.cpp$$ +is examples and tests of $code sparse_jacobian$$. +It return $code true$$, if it succeeds and $code false$$ otherwise. + +$end +============================================================================== +*/ +# include +# include + +namespace CppAD { // BEGIN_CPPAD_NAMESPACE +/*! +\file sparse_jacobian.hpp +Sparse Jacobian driver routine and helper functions. +*/ +// =========================================================================== +/*! +class used by SparseJacobian to hold information so it does not need to be +recomputed. +*/ +class sparse_jacobian_work { + public: + /// Coloring method: "cppad", or "colpack" + /// (this field is set by user) + std::string color_method; + /// indices that sort the user row and col arrays by color + CppAD::vector order; + /// results of the coloring algorithm + CppAD::vector color; + + /// constructor + sparse_jacobian_work(void) : color_method("cppad") + { } + /// reset coloring method to its default and + /// inform CppAD that color and order need to be recomputed + void clear(void) + { color_method = "cppad"; + order.clear(); + color.clear(); + } +}; +// =========================================================================== +/*! +Private helper function forward mode cases + +\tparam Base +is the base type for the recording that is stored in this +ADFun object. + +\tparam BaseVector +is a simple vector class with elements of type Base. + +\tparam SetVector +is either sparse_pack or sparse_list. + +\tparam SizeVector +is a simple vector class with elements of type size_t. + +\param x [in] +is a vector specifing the point at which to compute the Jacobian. + +\param p_transpose [in] +If work.color.size() != 0, +then p_transpose is not used. +Otherwise, it is a +sparsity pattern for the transpose of the Jacobian of this ADFun object. +Note that we do not change the values in p_transpose, +but is not const because we use its iterator facility. + +\param row [in] +is the vector of row indices for the returned Jacobian values. + +\param col [in] +is the vector of columns indices for the returned Jacobian values. +It must have the same size as row. + +\param jac [out] +is the vector of Jacobian values. We use K to denote the size of jac. +The return value jac[k] is the partial of the +row[k] range component of the function with respect +the the col[k] domain component of its argument. + +\param work +work.color_method is an input. The rest of +this structure contains information that is computed by SparseJacobainFor. +If the sparsity pattern, row vector, or col vectors +are not the same between calls to SparseJacobianFor, + work.clear() must be called to reinitialize work. + +\return +Is the number of first order forward sweeps used to compute the +requested Jacobian values. The total work, not counting the zero order +forward sweep, or the time to combine computations, is proportional to this +return value. +*/ +template +template +size_t ADFun::SparseJacobianFor( + const BaseVector& x , + SetVector& p_transpose , + const SizeVector& row , + const SizeVector& col , + BaseVector& jac , + sparse_jacobian_work& work ) +{ + size_t j, k, ell; + + CppAD::vector& order(work.order); + CppAD::vector& color(work.color); + + size_t m = Range(); + size_t n = Domain(); + + // some values + const Base zero(0); + const Base one(1); + + // check BaseVector is Simple Vector class with Base type elements + CheckSimpleVector(); + + CPPAD_ASSERT_UNKNOWN( size_t(x.size()) == n ); + CPPAD_ASSERT_UNKNOWN( color.size() == 0 || color.size() == n ); + + // number of components of Jacobian that are required + size_t K = size_t(jac.size()); + CPPAD_ASSERT_UNKNOWN( size_t( row.size() ) == K ); + CPPAD_ASSERT_UNKNOWN( size_t( col.size() ) == K ); + + // Point at which we are evaluating the Jacobian + Forward(0, x); + + // check for case where nothing (except Forward above) to do + if( K == 0 ) + return 0; + + if( color.size() == 0 ) + { + CPPAD_ASSERT_UNKNOWN( p_transpose.n_set() == n ); + CPPAD_ASSERT_UNKNOWN( p_transpose.end() == m ); + + // execute coloring algorithm + color.resize(n); + if( work.color_method == "cppad" ) + local::color_general_cppad(p_transpose, col, row, color); + else if( work.color_method == "colpack" ) + { +# if CPPAD_HAS_COLPACK + local::color_general_colpack(p_transpose, col, row, color); +# else + CPPAD_ASSERT_KNOWN( + false, + "SparseJacobianForward: work.color_method = colpack " + "and colpack_prefix missing from cmake command line." + ); +# endif + } + else CPPAD_ASSERT_KNOWN( + false, + "SparseJacobianForward: work.color_method is not valid." + ); + + // put sorting indices in color order + SizeVector key(K); + order.resize(K); + for(k = 0; k < K; k++) + key[k] = color[ col[k] ]; + index_sort(key, order); + } + size_t n_color = 1; + for(j = 0; j < n; j++) if( color[j] < n ) + n_color = std::max(n_color, color[j] + 1); + + // initialize the return value + for(k = 0; k < K; k++) + jac[k] = zero; + +# if CPPAD_SPARSE_JACOBIAN_MAX_MULTIPLE_DIRECTION == 1 + // direction vector and return values for calls to forward + BaseVector dx(n), dy(m); + + // loop over colors + k = 0; + for(ell = 0; ell < n_color; ell++) + { CPPAD_ASSERT_UNKNOWN( color[ col[ order[k] ] ] == ell ); + + // combine all columns with this color + for(j = 0; j < n; j++) + { dx[j] = zero; + if( color[j] == ell ) + dx[j] = one; + } + // call forward mode for all these columns at once + dy = Forward(1, dx); + + // set the corresponding components of the result + while( k < K && color[ col[order[k]] ] == ell ) + { jac[ order[k] ] = dy[row[order[k]]]; + k++; + } + } +# else + // abbreviation for this value + size_t max_r = CPPAD_SPARSE_JACOBIAN_MAX_MULTIPLE_DIRECTION; + CPPAD_ASSERT_UNKNOWN( max_r > 1 ); + + // count the number of colors done so far + size_t count_color = 0; + // count the sparse matrix entries done so far + k = 0; + while( count_color < n_color ) + { // number of colors we will do this time + size_t r = std::min(max_r , n_color - count_color); + BaseVector dx(n * r), dy(m * r); + + // loop over colors we will do this tme + for(ell = 0; ell < r; ell++) + { // combine all columns with this color + for(j = 0; j < n; j++) + { dx[j * r + ell] = zero; + if( color[j] == ell + count_color ) + dx[j * r + ell] = one; + } + } + size_t q = 1; + dy = Forward(q, r, dx); + + // store results + for(ell = 0; ell < r; ell++) + { // set the components of the result for this color + while( k < K && color[ col[order[k]] ] == ell + count_color ) + { jac[ order[k] ] = dy[ row[order[k]] * r + ell ]; + k++; + } + } + count_color += r; + } +# endif + return n_color; +} +/*! +Private helper function for reverse mode cases. + +\tparam Base +is the base type for the recording that is stored in this +ADFun object. + +\tparam BaseVector +is a simple vector class with elements of type Base. + +\tparam SetVector +is either sparse_pack or sparse_list. + +\tparam SizeVector +is a simple vector class with elements of type size_t. + +\param x [in] +is a vector specifing the point at which to compute the Jacobian. + +\param p [in] +If work.color.size() != 0, then p is not used. +Otherwise, it is a +sparsity pattern for the Jacobian of this ADFun object. +Note that we do not change the values in p, +but is not const because we use its iterator facility. + +\param row [in] +is the vector of row indices for the returned Jacobian values. + +\param col [in] +is the vector of columns indices for the returned Jacobian values. +It must have the same size as row. + +\param jac [out] +is the vector of Jacobian values. +It must have the same size as row. +The return value jac[k] is the partial of the +row[k] range component of the function with respect +the the col[k] domain component of its argument. + +\param work +work.color_method is an input. The rest of +This structure contains information that is computed by SparseJacobainRev. +If the sparsity pattern, row vector, or col vectors +are not the same between calls to SparseJacobianRev, + work.clear() must be called to reinitialize work. + +\return +Is the number of first order reverse sweeps used to compute the +reverse Jacobian values. The total work, not counting the zero order +forward sweep, or the time to combine computations, is proportional to this +return value. +*/ +template +template +size_t ADFun::SparseJacobianRev( + const BaseVector& x , + SetVector& p , + const SizeVector& row , + const SizeVector& col , + BaseVector& jac , + sparse_jacobian_work& work ) +{ + size_t i, k, ell; + + CppAD::vector& order(work.order); + CppAD::vector& color(work.color); + + size_t m = Range(); + size_t n = Domain(); + + // some values + const Base zero(0); + const Base one(1); + + // check BaseVector is Simple Vector class with Base type elements + CheckSimpleVector(); + + CPPAD_ASSERT_UNKNOWN( size_t(x.size()) == n ); + CPPAD_ASSERT_UNKNOWN (color.size() == m || color.size() == 0 ); + + // number of components of Jacobian that are required + size_t K = size_t(jac.size()); + CPPAD_ASSERT_UNKNOWN( size_t( size_t( row.size() ) ) == K ); + CPPAD_ASSERT_UNKNOWN( size_t( size_t( col.size() ) ) == K ); + + // Point at which we are evaluating the Jacobian + Forward(0, x); + + // check for case where nothing (except Forward above) to do + if( K == 0 ) + return 0; + + if( color.size() == 0 ) + { + CPPAD_ASSERT_UNKNOWN( p.n_set() == m ); + CPPAD_ASSERT_UNKNOWN( p.end() == n ); + + // execute the coloring algorithm + color.resize(m); + if( work.color_method == "cppad" ) + local::color_general_cppad(p, row, col, color); + else if( work.color_method == "colpack" ) + { +# if CPPAD_HAS_COLPACK + local::color_general_colpack(p, row, col, color); +# else + CPPAD_ASSERT_KNOWN( + false, + "SparseJacobianReverse: work.color_method = colpack " + "and colpack_prefix missing from cmake command line." + ); +# endif + } + else CPPAD_ASSERT_KNOWN( + false, + "SparseJacobianReverse: work.color_method is not valid." + ); + + // put sorting indices in color order + SizeVector key(K); + order.resize(K); + for(k = 0; k < K; k++) + key[k] = color[ row[k] ]; + index_sort(key, order); + } + size_t n_color = 1; + for(i = 0; i < m; i++) if( color[i] < m ) + n_color = std::max(n_color, color[i] + 1); + + // weighting vector for calls to reverse + BaseVector w(m); + + // location for return values from Reverse + BaseVector dw(n); + + // initialize the return value + for(k = 0; k < K; k++) + jac[k] = zero; + + // loop over colors + k = 0; + for(ell = 0; ell < n_color; ell++) + { CPPAD_ASSERT_UNKNOWN( color[ row[ order[k] ] ] == ell ); + + // combine all the rows with this color + for(i = 0; i < m; i++) + { w[i] = zero; + if( color[i] == ell ) + w[i] = one; + } + // call reverse mode for all these rows at once + dw = Reverse(1, w); + + // set the corresponding components of the result + while( k < K && color[ row[order[k]] ] == ell ) + { jac[ order[k] ] = dw[col[order[k]]]; + k++; + } + } + return n_color; +} +// ========================================================================== +// Public Member functions +// ========================================================================== +/*! +Compute user specified subset of a sparse Jacobian using forward mode. + +The C++ source code corresponding to this operation is +\verbatim + SparceJacobianForward(x, p, row, col, jac, work) +\endverbatim + +\tparam Base +is the base type for the recording that is stored in this +ADFun object. + +\tparam BaseVector +is a simple vector class with elements of type Base. + +\tparam SetVector +is a simple vector class with elements of type + bool or std::set. + +\tparam SizeVector +is a simple vector class with elements of type size_t. + +\param x [in] +is a vector specifing the point at which to compute the Jacobian. + +\param p [in] +is the sparsity pattern for the Jacobian that we are calculating. + +\param row [in] +is the vector of row indices for the returned Jacobian values. + +\param col [in] +is the vector of columns indices for the returned Jacobian values. +It must have the same size as row. + +\param jac [out] +is the vector of Jacobian values. +It must have the same size as row. +The return value jac[k] is the partial of the +row[k] range component of the function with respect +the the col[k] domain component of its argument. + +\param work [in,out] +this structure contains information that depends on the function object, +sparsity pattern, row vector, and col vector. +If they are not the same between calls to SparseJacobianForward, + work.clear() must be called to reinitialize them. + +\return +Is the number of first order forward sweeps used to compute the +requested Jacobian values. The total work, not counting the zero order +forward sweep, or the time to combine computations, is proportional to this +return value. +*/ +template +template +size_t ADFun::SparseJacobianForward( + const BaseVector& x , + const SetVector& p , + const SizeVector& row , + const SizeVector& col , + BaseVector& jac , + sparse_jacobian_work& work ) +{ + size_t n = Domain(); + size_t m = Range(); + size_t K = jac.size(); +# ifndef NDEBUG + size_t k; + CPPAD_ASSERT_KNOWN( + size_t(x.size()) == n , + "SparseJacobianForward: size of x not equal domain dimension for f." + ); + CPPAD_ASSERT_KNOWN( + size_t(row.size()) == K && size_t(col.size()) == K , + "SparseJacobianForward: either r or c does not have " + "the same size as jac." + ); + CPPAD_ASSERT_KNOWN( + work.color.size() == 0 || work.color.size() == n, + "SparseJacobianForward: invalid value in work." + ); + for(k = 0; k < K; k++) + { CPPAD_ASSERT_KNOWN( + row[k] < m, + "SparseJacobianForward: invalid value in r." + ); + CPPAD_ASSERT_KNOWN( + col[k] < n, + "SparseJacobianForward: invalid value in c." + ); + } + if( work.color.size() != 0 ) + for(size_t j = 0; j < n; j++) CPPAD_ASSERT_KNOWN( + work.color[j] <= n, + "SparseJacobianForward: invalid value in work." + ); +# endif + // check for case where there is nothing to compute + size_t n_sweep = 0; + if( K == 0 ) + return n_sweep; + + typedef typename SetVector::value_type Set_type; + typedef typename local::sparse::internal_pattern::pattern_type Pattern_type; + Pattern_type s_transpose; + if( work.color.size() == 0 ) + { bool transpose = true; + const char* error_msg = "SparseJacobianForward: transposed sparsity" + " pattern does not have proper row or column dimension"; + sparsity_user2internal(s_transpose, p, n, m, transpose, error_msg); + } + n_sweep = SparseJacobianFor(x, s_transpose, row, col, jac, work); + return n_sweep; +} +/*! +Compute user specified subset of a sparse Jacobian using forward mode. + +The C++ source code corresponding to this operation is +\verbatim + SparceJacobianReverse(x, p, row, col, jac, work) +\endverbatim + +\tparam Base +is the base type for the recording that is stored in this +ADFun object. + +\tparam BaseVector +is a simple vector class with elements of type Base. + +\tparam SetVector +is a simple vector class with elements of type + bool or std::set. + +\tparam SizeVector +is a simple vector class with elements of type size_t. + +\param x [in] +is a vector specifing the point at which to compute the Jacobian. + +\param p [in] +is the sparsity pattern for the Jacobian that we are calculating. + +\param row [in] +is the vector of row indices for the returned Jacobian values. + +\param col [in] +is the vector of columns indices for the returned Jacobian values. +It must have the same size as row. + +\param jac [out] +is the vector of Jacobian values. +It must have the same size as row. +The return value jac[k] is the partial of the +row[k] range component of the function with respect +the the col[k] domain component of its argument. + +\param work [in,out] +this structure contains information that depends on the function object, +sparsity pattern, row vector, and col vector. +If they are not the same between calls to SparseJacobianReverse, + work.clear() must be called to reinitialize them. + +\return +Is the number of first order reverse sweeps used to compute the +reverse Jacobian values. The total work, not counting the zero order +forward sweep, or the time to combine computations, is proportional to this +return value. +*/ +template +template +size_t ADFun::SparseJacobianReverse( + const BaseVector& x , + const SetVector& p , + const SizeVector& row , + const SizeVector& col , + BaseVector& jac , + sparse_jacobian_work& work ) +{ + size_t m = Range(); + size_t n = Domain(); + size_t K = jac.size(); +# ifndef NDEBUG + size_t k; + CPPAD_ASSERT_KNOWN( + size_t(x.size()) == n , + "SparseJacobianReverse: size of x not equal domain dimension for f." + ); + CPPAD_ASSERT_KNOWN( + size_t(row.size()) == K && size_t(col.size()) == K , + "SparseJacobianReverse: either r or c does not have " + "the same size as jac." + ); + CPPAD_ASSERT_KNOWN( + work.color.size() == 0 || work.color.size() == m, + "SparseJacobianReverse: invalid value in work." + ); + for(k = 0; k < K; k++) + { CPPAD_ASSERT_KNOWN( + row[k] < m, + "SparseJacobianReverse: invalid value in r." + ); + CPPAD_ASSERT_KNOWN( + col[k] < n, + "SparseJacobianReverse: invalid value in c." + ); + } + if( work.color.size() != 0 ) + for(size_t i = 0; i < m; i++) CPPAD_ASSERT_KNOWN( + work.color[i] <= m, + "SparseJacobianReverse: invalid value in work." + ); +# endif + // check for case where there is nothing to compute + size_t n_sweep = 0; + if( K == 0 ) + return n_sweep; + + typedef typename SetVector::value_type Set_type; + typedef typename local::sparse::internal_pattern::pattern_type Pattern_type; + Pattern_type s; + if( work.color.size() == 0 ) + { bool transpose = false; + const char* error_msg = "SparseJacobianReverse: sparsity" + " pattern does not have proper row or column dimension"; + sparsity_user2internal(s, p, m, n, transpose, error_msg); + } + n_sweep = SparseJacobianRev(x, s, row, col, jac, work); + return n_sweep; +} +/*! +Compute a sparse Jacobian. + +The C++ source code corresponding to this operation is +\verbatim + jac = SparseJacobian(x, p) +\endverbatim + +\tparam Base +is the base type for the recording that is stored in this +ADFun object. + +\tparam BaseVector +is a simple vector class with elements of type Base. + +\tparam SetVector +is a simple vector class with elements of type + bool or std::set. + +\param x [in] +is a vector specifing the point at which to compute the Jacobian. + +\param p [in] +is the sparsity pattern for the Jacobian that we are calculating. + +\return +Will be a vector if size m * n containing the Jacobian at the +specified point (in row major order). +*/ +template +template +BaseVector ADFun::SparseJacobian( + const BaseVector& x, const SetVector& p +) +{ size_t i, j, k; + + size_t m = Range(); + size_t n = Domain(); + BaseVector jac(m * n); + + CPPAD_ASSERT_KNOWN( + size_t(x.size()) == n, + "SparseJacobian: size of x not equal domain size for f." + ); + CheckSimpleVector(); + + typedef typename SetVector::value_type Set_type; + typedef typename local::sparse::internal_pattern::pattern_type Pattern_type; + + // initialize the return value as zero + Base zero(0); + for(i = 0; i < m; i++) + for(j = 0; j < n; j++) + jac[i * n + j] = zero; + + sparse_jacobian_work work; + CppAD::vector row; + CppAD::vector col; + if( n <= m ) + { + // need an internal copy of sparsity pattern + Pattern_type s_transpose; + bool transpose = true; + const char* error_msg = "SparseJacobian: transposed sparsity" + " pattern does not have proper row or column dimension"; + sparsity_user2internal(s_transpose, p, n, m, transpose, error_msg); + + k = 0; + for(j = 0; j < n; j++) + { typename Pattern_type::const_iterator itr(s_transpose, j); + i = *itr; + while( i != s_transpose.end() ) + { row.push_back(i); + col.push_back(j); + k++; + i = *(++itr); + } + } + size_t K = k; + BaseVector J(K); + + // now we have folded this into the following case + SparseJacobianFor(x, s_transpose, row, col, J, work); + + // now set the non-zero return values + for(k = 0; k < K; k++) + jac[ row[k] * n + col[k] ] = J[k]; + } + else + { + // need an internal copy of sparsity pattern + Pattern_type s; + bool transpose = false; + const char* error_msg = "SparseJacobian: sparsity" + " pattern does not have proper row or column dimension"; + sparsity_user2internal(s, p, m, n, transpose, error_msg); + + k = 0; + for(i = 0; i < m; i++) + { typename Pattern_type::const_iterator itr(s, i); + j = *itr; + while( j != s.end() ) + { row.push_back(i); + col.push_back(j); + k++; + j = *(++itr); + } + } + size_t K = k; + BaseVector J(K); + + // now we have folded this into the following case + SparseJacobianRev(x, s, row, col, J, work); + + // now set the non-zero return values + for(k = 0; k < K; k++) + jac[ row[k] * n + col[k] ] = J[k]; + } + + return jac; +} + +/*! +Compute a sparse Jacobian. + +The C++ source code corresponding to this operation is +\verbatim + jac = SparseJacobian(x) +\endverbatim + +\tparam Base +is the base type for the recording that is stored in this +ADFun object. + +\tparam BaseVector +is a simple vector class with elements of the Base. + +\param x [in] +is a vector specifing the point at which to compute the Jacobian. + +\return +Will be a vector of size m * n containing the Jacobian at the +specified point (in row major order). +*/ +template +template +BaseVector ADFun::SparseJacobian( const BaseVector& x ) +{ typedef CppAD::vectorBool BoolVector; + + size_t m = Range(); + size_t n = Domain(); + + // sparsity pattern for Jacobian + BoolVector p(m * n); + + if( n <= m ) + { size_t j, k; + + // use forward mode + BoolVector r(n * n); + for(j = 0; j < n; j++) + { for(k = 0; k < n; k++) + r[j * n + k] = false; + r[j * n + j] = true; + } + p = ForSparseJac(n, r); + } + else + { size_t i, k; + + // use reverse mode + BoolVector s(m * m); + for(i = 0; i < m; i++) + { for(k = 0; k < m; k++) + s[i * m + k] = false; + s[i * m + i] = true; + } + p = RevSparseJac(m, s); + } + return SparseJacobian(x, p); +} + +} // END_CPPAD_NAMESPACE +# undef CPPAD_SPARSE_JACOBIAN_MAX_MULTIPLE_DIRECTION +# endif diff --git a/build-config/cppad/include/cppad/core/standard_math.hpp b/build-config/cppad/include/cppad/core/standard_math.hpp new file mode 100644 index 00000000..8144d473 --- /dev/null +++ b/build-config/cppad/include/cppad/core/standard_math.hpp @@ -0,0 +1,118 @@ +# ifndef CPPAD_CORE_STANDARD_MATH_HPP +# define CPPAD_CORE_STANDARD_MATH_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +/* +$begin unary_standard_math$$ +$spell + const + VecAD + fabs +$$ + +$section The Unary Standard Math Functions$$ + +$head Syntax$$ +$icode%y% = %fun%(%x%)%$$ + +$head Purpose$$ +Evaluates the standard math function $icode fun$$. + +$head Possible Types$$ + +$subhead Base$$ +If $icode Base$$ satisfies the +$cref/base type requirements/base_require/$$ +and argument $icode x$$ has prototype +$codei% + const %Base%& %x% +%$$ +then the result $icode y$$ has prototype +$codei% + %Base% %y% +%$$ + +$subhead AD$$ +If the argument $icode x$$ has prototype +$codei% + const AD<%Base%>& %x% +%$$ +then the result $icode y$$ has prototype +$codei% + AD<%Base%> %y% +%$$ + +$subhead VecAD$$ +If the argument $icode x$$ has prototype +$codei% + const VecAD<%Base%>::reference& %x% +%$$ +then the result $icode y$$ has prototype +$codei% + AD<%Base%> %y% +%$$ + +$children%include/cppad/core/std_math_11.hpp + %include/cppad/core/abs.hpp + %include/cppad/core/sign.hpp +%$$ + +$head fun$$ +The possible values for $icode fun$$ are +$table +$icode fun$$ $pre $$ $cnext Description $rnext +$cref abs$$ $cnext $title abs$$ $rnext +$cref acos$$ $cnext $title acos$$ $rnext +$cref acosh$$ $cnext $title acosh$$ $rnext +$cref asin$$ $cnext $title asin$$ $rnext +$cref asinh$$ $cnext $title asinh$$ $rnext +$cref atan$$ $cnext $title atan$$ $rnext +$cref atanh$$ $cnext $title atanh$$ $rnext +$cref cos$$ $cnext $title cos$$ $rnext +$cref cosh$$ $cnext $title cosh$$ $rnext +$cref erf$$ $cnext $title erf$$ $rnext +$cref exp$$ $cnext $title exp$$ $rnext +$cref expm1$$ $cnext $title expm1$$ $rnext +$cref/fabs/abs/$$ $cnext $title abs$$ $rnext +$cref log10$$ $cnext $title log10$$ $rnext +$cref log1p$$ $cnext $title log1p$$ $rnext +$cref log$$ $cnext $title log$$ $rnext +$cref sign$$ $cnext $title sign$$ $rnext +$cref sin$$ $cnext $title sin$$ $rnext +$cref sinh$$ $cnext $title sinh$$ $rnext +$cref sqrt$$ $cnext $title sqrt$$ $rnext +$cref tan$$ $cnext $title tan$$ $rnext +$cref tanh$$ $cnext $title tanh$$ +$tend + +$end +*/ +# include +# include + +/* +$begin binary_math$$ + +$section The Binary Math Functions$$ + +$childtable%include/cppad/core/atan2.hpp + %include/cppad/core/pow.hpp + %include/cppad/core/azmul.hpp +%$$ + +$end +*/ +# include +# include + +# endif diff --git a/build-config/cppad/include/cppad/core/std_math_11.hpp b/build-config/cppad/include/cppad/core/std_math_11.hpp new file mode 100644 index 00000000..8cc88122 --- /dev/null +++ b/build-config/cppad/include/cppad/core/std_math_11.hpp @@ -0,0 +1,884 @@ +# ifndef CPPAD_CORE_STD_MATH_11_HPP +# define CPPAD_CORE_STD_MATH_11_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ +/* +------------------------------------------------------------------------------- +$begin acos$$ +$spell + acos +$$ + +$section Inverse Cosine Function: acos$$ + +$head Syntax$$ +$icode%y% = acos(%x%)%$$ + +$head x, y$$ +See the $cref/possible types/unary_standard_math/Possible Types/$$ +for a unary standard math function. + +$head Atomic$$ +This is an $cref/atomic operation/glossary/Operation/Atomic/$$. + +$head Derivative$$ +$latex \[ +\begin{array}{lcr} + \R{acos}^{(1)} (x) & = & - (1 - x * x)^{-1/2} +\end{array} +\] $$ + +$head Example$$ +$children% + example/general/acos.cpp +%$$ +The file +$cref acos.cpp$$ +contains an example and test of this function. + +$end +------------------------------------------------------------------------------- +$begin acosh$$ +$spell + acosh + const + Vec + std + cmath + CppAD +$$ +$section The Inverse Hyperbolic Cosine Function: acosh$$ + +$head Syntax$$ +$icode%y% = acosh(%x%)%$$ + +$head Description$$ +The inverse hyperbolic cosine function is defined by +$icode%x% == cosh(%y%)%$$. + +$head x, y$$ +See the $cref/possible types/unary_standard_math/Possible Types/$$ +for a unary standard math function. + +$head Atomic$$ +This is an $cref/atomic operation/glossary/Operation/Atomic/$$. + +$head Example$$ +$children% + example/general/acosh.cpp +%$$ +The file +$cref acosh.cpp$$ +contains an example and test of this function. + +$end +------------------------------------------------------------------------------- +$begin asin$$ +$spell + asin +$$ + +$section Inverse Sine Function: asin$$ + +$head Syntax$$ +$icode%y% = asin(%x%)%$$ + +$head x, y$$ +See the $cref/possible types/unary_standard_math/Possible Types/$$ +for a unary standard math function. + +$head Atomic$$ +This is an $cref/atomic operation/glossary/Operation/Atomic/$$. + +$head Derivative$$ +$latex \[ +\begin{array}{lcr} + \R{asin}^{(1)} (x) & = & (1 - x * x)^{-1/2} +\end{array} +\] $$ + +$head Example$$ +$children% + example/general/asin.cpp +%$$ +The file +$cref asin.cpp$$ +contains an example and test of this function. + +$end +------------------------------------------------------------------------------- +$begin asinh$$ +$spell + asinh + const + Vec + std + cmath + CppAD +$$ +$section The Inverse Hyperbolic Sine Function: asinh$$ + +$head Syntax$$ +$icode%y% = asinh(%x%)%$$ + +$head Description$$ +The inverse hyperbolic sine function is defined by +$icode%x% == sinh(%y%)%$$. + +$head x, y$$ +See the $cref/possible types/unary_standard_math/Possible Types/$$ +for a unary standard math function. + +$head Atomic$$ +This is an $cref/atomic operation/glossary/Operation/Atomic/$$. + +$head Example$$ +$children% + example/general/asinh.cpp +%$$ +The file +$cref asinh.cpp$$ +contains an example and test of this function. + +$end +------------------------------------------------------------------------------- +$begin atan$$ +$spell + atan +$$ + +$section Inverse Tangent Function: atan$$ + +$head Syntax$$ +$icode%y% = atan(%x%)%$$ + +$head x, y$$ +See the $cref/possible types/unary_standard_math/Possible Types/$$ +for a unary standard math function. + +$head Atomic$$ +This is an $cref/atomic operation/glossary/Operation/Atomic/$$. + +$head Derivative$$ +$latex \[ +\begin{array}{lcr} + \R{atan}^{(1)} (x) & = & \frac{1}{1 + x^2} +\end{array} +\] $$ + +$head Example$$ +$children% + example/general/atan.cpp +%$$ +The file +$cref atan.cpp$$ +contains an example and test of this function. + +$end +------------------------------------------------------------------------------- +$begin atanh$$ +$spell + atanh + const + Vec + std + cmath + CppAD + tanh +$$ +$section The Inverse Hyperbolic Tangent Function: atanh$$ + +$head Syntax$$ +$icode%y% = atanh(%x%)%$$ + +$head Description$$ +The inverse hyperbolic tangent function is defined by +$icode%x% == tanh(%y%)%$$. + +$head x, y$$ +See the $cref/possible types/unary_standard_math/Possible Types/$$ +for a unary standard math function. + +$head Atomic$$ +This is an $cref/atomic operation/glossary/Operation/Atomic/$$. + +$head Example$$ +$children% + example/general/atanh.cpp +%$$ +The file +$cref atanh.cpp$$ +contains an example and test of this function. + +$end +------------------------------------------------------------------------------- +$begin cos$$ +$spell + cos +$$ + +$section The Cosine Function: cos$$ + +$head Syntax$$ +$icode%y% = cos(%x%)%$$ + +$head x, y$$ +See the $cref/possible types/unary_standard_math/Possible Types/$$ +for a unary standard math function. + +$head Atomic$$ +This is an $cref/atomic operation/glossary/Operation/Atomic/$$. + +$head Derivative$$ +$latex \[ +\begin{array}{lcr} + \R{cos}^{(1)} (x) & = & - \sin(x) +\end{array} +\] $$ + +$head Example$$ +$children% + example/general/cos.cpp +%$$ +The file +$cref cos.cpp$$ +contains an example and test of this function. + +$end +------------------------------------------------------------------------------- +$begin cosh$$ +$spell + cosh +$$ + +$section The Hyperbolic Cosine Function: cosh$$ + +$head Syntax$$ +$icode%y% = cosh(%x%)%$$ + +$head x, y$$ +See the $cref/possible types/unary_standard_math/Possible Types/$$ +for a unary standard math function. + +$head Atomic$$ +This is an $cref/atomic operation/glossary/Operation/Atomic/$$. + +$head Derivative$$ +$latex \[ +\begin{array}{lcr} + \R{cosh}^{(1)} (x) & = & \sinh(x) +\end{array} +\] $$ + +$head Example$$ +$children% + example/general/cosh.cpp +%$$ +The file +$cref cosh.cpp$$ +contains an example and test of this function. + +$end +------------------------------------------------------------------------------- +$begin erf$$ +$spell + erf + const + Vec + std + cmath + CppAD + Vedder +$$ +$section The Error Function$$ + +$head Syntax$$ +$icode%y% = erf(%x%)%$$ + +$head Description$$ +Returns the value of the error function which is defined by +$latex \[ +{\rm erf} (x) = \frac{2}{ \sqrt{\pi} } \int_0^x \exp( - t * t ) \; {\bf d} t +\] $$ + +$head x, y$$ +See the $cref/possible types/unary_standard_math/Possible Types/$$ +for a unary standard math function. + +$head Atomic$$ +This is an $cref/atomic operation/glossary/Operation/Atomic/$$. + +$head Example$$ +$children% + example/general/erf.cpp +%$$ +The file +$cref erf.cpp$$ +contains an example and test of this function. + +$end +------------------------------------------------------------------------------- +$begin erfc$$ +$spell + erf + erfc + Vec + CppAD +$$ +$section The Complementary Error Function: erfc$$ + +$head Syntax$$ +$icode%y% = erfc(%x%)%$$ + +$head Description$$ +Returns the value of the complementary error function which is defined by +$icode%y% == 1 - erf(%x%)%$$. + +$head x, y$$ +See the $cref/possible types/unary_standard_math/Possible Types/$$ +for a unary standard math function. + +$head Atomic$$ +This is an $cref/atomic operation/glossary/Operation/Atomic/$$. + +$head Example$$ +$children% + example/general/erfc.cpp +%$$ +The file +$cref erfc.cpp$$ +contains an example and test of this function. + +$end +------------------------------------------------------------------------------- +$begin exp$$ +$spell + exp +$$ + +$section The Exponential Function: exp$$ + +$head Syntax$$ +$icode%y% = exp(%x%)%$$ + +$head x, y$$ +See the $cref/possible types/unary_standard_math/Possible Types/$$ +for a unary standard math function. + +$head Atomic$$ +This is an $cref/atomic operation/glossary/Operation/Atomic/$$. + +$head Derivative$$ +$latex \[ +\begin{array}{lcr} + \R{exp}^{(1)} (x) & = & \exp(x) +\end{array} +\] $$ + +$head Example$$ +$children% + example/general/exp.cpp +%$$ +The file +$cref exp.cpp$$ +contains an example and test of this function. + +$end +------------------------------------------------------------------------------- +$begin expm1$$ +$spell + exp + expm1 + CppAD +$$ +$section The Exponential Function Minus One: expm1$$ + +$head Syntax$$ +$icode%y% = expm1(%x%)%$$ + +$head Description$$ +Returns the value of the exponential function minus one which is defined +by $icode%y% == exp(%x%) - 1%$$. + +$head x, y$$ +See the $cref/possible types/unary_standard_math/Possible Types/$$ +for a unary standard math function. + +$head Atomic$$ +This is an $cref/atomic operation/glossary/Operation/Atomic/$$. + +$head Example$$ +$children% + example/general/expm1.cpp +%$$ +The file +$cref expm1.cpp$$ +contains an example and test of this function. + +$end +------------------------------------------------------------------------------- +$begin log$$ +$spell +$$ + +$section The Exponential Function: log$$ + +$head Syntax$$ +$icode%y% = log(%x%)%$$ + +$head x, y$$ +See the $cref/possible types/unary_standard_math/Possible Types/$$ +for a unary standard math function. + +$head Atomic$$ +This is an $cref/atomic operation/glossary/Operation/Atomic/$$. + +$head Derivative$$ +$latex \[ +\begin{array}{lcr} + \R{log}^{(1)} (x) & = & \frac{1}{x} +\end{array} +\] $$ + +$head Example$$ +$children% + example/general/log.cpp +%$$ +The file +$cref log.cpp$$ +contains an example and test of this function. + +$end +------------------------------------------------------------------------------- +$begin log1p$$ +$spell + CppAD +$$ + +$section The Logarithm of One Plus Argument: log1p$$ + +$head Syntax$$ +$icode%y% = log1p(%x%)%$$ + +$head Description$$ +Returns the value of the logarithm of one plus argument which is defined +by $icode%y% == log(1 + %x%)%$$. + +$head x, y$$ +See the $cref/possible types/unary_standard_math/Possible Types/$$ +for a unary standard math function. + +$head Atomic$$ +This is an $cref/atomic operation/glossary/Operation/Atomic/$$. + +$head Example$$ +$children% + example/general/log1p.cpp +%$$ +The file +$cref log1p.cpp$$ +contains an example and test of this function. + +$end +------------------------------------------------------------------------------- +$begin log10$$ +$spell + CppAD +$$ + +$section The Base 10 Logarithm Function: log10$$ + +$head Syntax$$ +$icode%y% = log10(%x%)%$$ + +$head x, y$$ +See the $cref/possible types/unary_standard_math/Possible Types/$$ +for a unary standard math function. + +$head Method$$ +CppAD uses the representation +$latex \[ +\begin{array}{lcr} + {\rm log10} (x) & = & \log(x) / \log(10) +\end{array} +\] $$ + +$head Example$$ +$children% + example/general/log10.cpp +%$$ +The file +$cref log10.cpp$$ +contains an example and test of this function. + +$end +------------------------------------------------------------------------------- +$begin sin$$ +$spell + sin +$$ + +$section The Sine Function: sin$$ + +$head Syntax$$ +$icode%y% = sin(%x%)%$$ + +$head x, y$$ +See the $cref/possible types/unary_standard_math/Possible Types/$$ +for a unary standard math function. + +$head Atomic$$ +This is an $cref/atomic operation/glossary/Operation/Atomic/$$. + +$head Derivative$$ +$latex \[ +\begin{array}{lcr} + \R{sin}^{(1)} (x) & = & \cos(x) +\end{array} +\] $$ + +$head Example$$ +$children% + example/general/sin.cpp +%$$ +The file +$cref sin.cpp$$ +contains an example and test of this function. + +$end +------------------------------------------------------------------------------- +$begin sinh$$ +$spell + sinh +$$ + +$section The Hyperbolic Sine Function: sinh$$ + +$head Syntax$$ +$icode%y% = sinh(%x%)%$$ + +$head x, y$$ +See the $cref/possible types/unary_standard_math/Possible Types/$$ +for a unary standard math function. + +$head Atomic$$ +This is an $cref/atomic operation/glossary/Operation/Atomic/$$. + +$head Derivative$$ +$latex \[ +\begin{array}{lcr} + \R{sinh}^{(1)} (x) & = & \cosh(x) +\end{array} +\] $$ + +$head Example$$ +$children% + example/general/sinh.cpp +%$$ +The file +$cref sinh.cpp$$ +contains an example and test of this function. + +$end +------------------------------------------------------------------------------- +$begin sqrt$$ +$spell + sqrt +$$ + +$section The Square Root Function: sqrt$$ + +$head Syntax$$ +$icode%y% = sqrt(%x%)%$$ + +$head x, y$$ +See the $cref/possible types/unary_standard_math/Possible Types/$$ +for a unary standard math function. + +$head Atomic$$ +This is an $cref/atomic operation/glossary/Operation/Atomic/$$. + +$head Derivative$$ +$latex \[ +\begin{array}{lcr} + \R{sqrt}^{(1)} (x) & = & \frac{1}{2 \R{sqrt} (x) } +\end{array} +\] $$ + +$head Example$$ +$children% + example/general/sqrt.cpp +%$$ +The file +$cref sqrt.cpp$$ +contains an example and test of this function. + +$end +------------------------------------------------------------------------------- +$begin tan$$ +$spell + tan +$$ + +$section The Tangent Function: tan$$ + +$head Syntax$$ +$icode%y% = tan(%x%)%$$ + +$head x, y$$ +See the $cref/possible types/unary_standard_math/Possible Types/$$ +for a unary standard math function. + +$head Atomic$$ +This is an $cref/atomic operation/glossary/Operation/Atomic/$$. + +$head Derivative$$ +$latex \[ +\begin{array}{lcr} + \R{tan}^{(1)} (x) & = & 1 + \tan (x)^2 +\end{array} +\] $$ + +$head Example$$ +$children% + example/general/tan.cpp +%$$ +The file +$cref tan.cpp$$ +contains an example and test of this function. + +$end +------------------------------------------------------------------------------- +$begin tanh$$ +$spell + tanh +$$ + +$section The Hyperbolic Tangent Function: tanh$$ + +$head Syntax$$ +$icode%y% = tanh(%x%)%$$ + +$head x, y$$ +See the $cref/possible types/unary_standard_math/Possible Types/$$ +for a unary standard math function. + +$head Atomic$$ +This is an $cref/atomic operation/glossary/Operation/Atomic/$$. + +$head Derivative$$ +$latex \[ +\begin{array}{lcr} + \R{tanh}^{(1)} (x) & = & 1 - \tanh (x)^2 +\end{array} +\] $$ + +$head Example$$ +$children% + example/general/tanh.cpp +%$$ +The file +$cref tanh.cpp$$ +contains an example and test of this function. + +$end +------------------------------------------------------------------------------- +*/ + +/*! +\file std_math_11.hpp +Define AD standard math functions (using their Base versions) +*/ + +/*! +\def CPPAD_STANDARD_MATH_UNARY_AD(Name, Op) +Defines function Name with argument type AD and tape operation Op + +The macro defines the function x.Name() where x has type AD. +It then uses this funciton to define Name(x) where x has type +AD or VecAD_reference. + +If x is a variable, the tape unary operator Op is used +to record the operation and the result is identified as correspoding +to this operation; i.e., Name(x).taddr_ idendifies the operation and +Name(x).tape_id_ identifies the tape. + +This macro is used to define AD versions of +acos, asin, atan, cos, cosh, exp, fabs, log, sin, sinh, sqrt, tan, tanh. +*/ + +# define CPPAD_STANDARD_MATH_UNARY_AD(Name, Op) \ + template \ + inline AD Name(const AD &x) \ + { return x.Name##_me(); \ + } \ + template \ + inline AD AD::Name##_me (void) const \ + { \ + AD result; \ + result.value_ = CppAD::Name(value_); \ + CPPAD_ASSERT_UNKNOWN( Parameter(result) ); \ + \ + local::ADTape* tape = AD::tape_ptr(); \ + if( tape == nullptr ) \ + return result; \ + \ + if( tape_id_ != tape->id_ ) \ + return result; \ + \ + if(ad_type_ == dynamic_enum) \ + { result.taddr_ = tape->Rec_.put_dyn_par( \ + result.value_, local::Name##_dyn, taddr_ \ + ); \ + result.tape_id_ = tape_id_; \ + result.ad_type_ = dynamic_enum; \ + } \ + else \ + { CPPAD_ASSERT_UNKNOWN( NumArg(Op) == 1 ); \ + tape->Rec_.PutArg(taddr_); \ + result.taddr_ = tape->Rec_.PutOp(Op); \ + result.tape_id_ = tape->id_; \ + result.ad_type_ = variable_enum; \ + } \ + return result; \ + } \ + template \ + inline AD Name(const VecAD_reference &x) \ + { return x.ADBase().Name##_me(); } + +// BEGIN CppAD namespace +namespace CppAD { + + CPPAD_STANDARD_MATH_UNARY_AD(acos, local::AcosOp) + CPPAD_STANDARD_MATH_UNARY_AD(acosh, local::AcoshOp) + CPPAD_STANDARD_MATH_UNARY_AD(asin, local::AsinOp) + CPPAD_STANDARD_MATH_UNARY_AD(asinh, local::AsinhOp) + CPPAD_STANDARD_MATH_UNARY_AD(atan, local::AtanOp) + CPPAD_STANDARD_MATH_UNARY_AD(atanh, local::AtanhOp) + CPPAD_STANDARD_MATH_UNARY_AD(cos, local::CosOp) + CPPAD_STANDARD_MATH_UNARY_AD(cosh, local::CoshOp) + CPPAD_STANDARD_MATH_UNARY_AD(exp, local::ExpOp) + CPPAD_STANDARD_MATH_UNARY_AD(expm1, local::Expm1Op) + CPPAD_STANDARD_MATH_UNARY_AD(fabs, local::AbsOp) + CPPAD_STANDARD_MATH_UNARY_AD(log, local::LogOp) + CPPAD_STANDARD_MATH_UNARY_AD(log1p, local::Log1pOp) + CPPAD_STANDARD_MATH_UNARY_AD(sin, local::SinOp) + CPPAD_STANDARD_MATH_UNARY_AD(sinh, local::SinhOp) + CPPAD_STANDARD_MATH_UNARY_AD(sqrt, local::SqrtOp) + CPPAD_STANDARD_MATH_UNARY_AD(tan, local::TanOp) + CPPAD_STANDARD_MATH_UNARY_AD(tanh, local::TanhOp) + + + // Error function is a special case + template + inline AD erf(const AD &x) + { bool complement = false; + return x.erf_me(complement); + } + template + inline AD erfc(const AD &x) + { bool complement = true; + return x.erf_me(complement); + } + template + inline AD AD::erf_me (bool complement) const + { + AD result; + if( complement ) + result.value_ = CppAD::erfc(value_); + else + result.value_ = CppAD::erf(value_); + CPPAD_ASSERT_UNKNOWN( Parameter(result) ); + + // check if there is a recording in progress + local::ADTape* tape = AD::tape_ptr(); + if( tape == nullptr ) + return result; + + // check if operand is a constant parameter + if( tape_id_ != tape->id_ ) + return result; + + if(ad_type_ == dynamic_enum) + { local::op_code_dyn op = local::erf_dyn; + if( complement ) + op = local::erfc_dyn; + + // dynamic paramter argument + result.taddr_ = tape->Rec_.put_dyn_par( + result.value_, op, taddr_ + ); + result.tape_id_ = tape_id_; + result.ad_type_ = dynamic_enum; + } + else + { local::OpCode op = local::ErfOp; + if( complement ) + op = local::ErfcOp; + + // variable argument + CPPAD_ASSERT_UNKNOWN( local::NumArg(op) == 3 ); + + // arg[0] = argument to erf function + tape->Rec_.PutArg(taddr_); + + // arg[1] = zero + addr_t p = tape->Rec_.put_con_par( Base(0.0) ); + tape->Rec_.PutArg(p); + + // arg[2] = 2 / sqrt(pi) + p = tape->Rec_.put_con_par(Base( + 1.0 / std::sqrt( std::atan(1.0) ) + )); + tape->Rec_.PutArg(p); + // + result.taddr_ = tape->Rec_.PutOp(op); + result.tape_id_ = tape->id_; + result.ad_type_ = variable_enum; + } + return result; + } + template + inline AD erf(const VecAD_reference &x) + { bool complement = false; + return x.ADBase().erf_me(complement); + } + template + inline AD erfc(const VecAD_reference &x) + { bool complement = true; + return x.ADBase().erf_me(complement); + } + + /*! + Compute the log of base 10 of x where has type AD + + \tparam Base + is the base type (different from base for log) + for this AD type, see base_require. + + \param x + is the argument for the log10 function. + + \result + if the result is y, then \f$ x = 10^y \f$. + */ + template + inline AD log10(const AD &x) + { return CppAD::log(x) / CppAD::log( Base(10) ); } + template + inline AD log10(const VecAD_reference &x) + { return CppAD::log(x.ADBase()) / CppAD::log( Base(10) ); } +} + +# undef CPPAD_STANDARD_MATH_UNARY_AD + +# endif diff --git a/build-config/cppad/include/cppad/core/sub.hpp b/build-config/cppad/include/cppad/core/sub.hpp new file mode 100644 index 00000000..0f743eec --- /dev/null +++ b/build-config/cppad/include/cppad/core/sub.hpp @@ -0,0 +1,125 @@ +# ifndef CPPAD_CORE_SUB_HPP +# define CPPAD_CORE_SUB_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +// BEGIN CppAD namespace +namespace CppAD { + +template +AD operator - (const AD &left , const AD &right) +{ + // compute the Base part + AD result; + result.value_ = left.value_ - right.value_; + CPPAD_ASSERT_UNKNOWN( Parameter(result) ); + + // check if there is a recording in progress + local::ADTape* tape = AD::tape_ptr(); + if( tape == nullptr ) + return result; + tape_id_t tape_id = tape->id_; + // tape_id cannot match the default value for tape_id_; i.e., 0 + CPPAD_ASSERT_UNKNOWN( tape_id > 0 ); + + // check if left and right tapes match + bool match_left = left.tape_id_ == tape_id; + bool match_right = right.tape_id_ == tape_id; + + // check if left and right are dynamic parameters + bool dyn_left = match_left & (left.ad_type_ == dynamic_enum); + bool dyn_right = match_right & (right.ad_type_ == dynamic_enum); + + // check if left and right are variables + bool var_left = match_left & (left.ad_type_ != dynamic_enum); + bool var_right = match_right & (right.ad_type_ != dynamic_enum); + + + CPPAD_ASSERT_KNOWN( + left.tape_id_ == right.tape_id_ || ! match_left || ! match_right , + "Subtract: AD variables or dynamic parameters on different threads." + ); + if( var_left ) + { if( var_right ) + { // result = variable - variable + CPPAD_ASSERT_UNKNOWN( local::NumRes(local::SubvvOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( local::NumArg(local::SubvvOp) == 2 ); + + // put operand addresses in tape + tape->Rec_.PutArg(left.taddr_, right.taddr_); + // put operator in the tape + result.taddr_ = tape->Rec_.PutOp(local::SubvvOp); + // make result a variable + result.tape_id_ = tape_id; + result.ad_type_ = variable_enum; + } + else if( (! dyn_right) & IdenticalZero(right.value_) ) + { // result = variable - 0 + result.make_variable(left.tape_id_, left.taddr_); + } + else + { // result = variable - parameter + CPPAD_ASSERT_UNKNOWN( local::NumRes(local::SubvpOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( local::NumArg(local::SubvpOp) == 2 ); + + // put operand addresses in tape + addr_t p = right.taddr_; + if( ! dyn_right ) + p = tape->Rec_.put_con_par(right.value_); + tape->Rec_.PutArg(left.taddr_, p); + // put operator in the tape + result.taddr_ = tape->Rec_.PutOp(local::SubvpOp); + // make result a variable + result.tape_id_ = tape_id; + result.ad_type_ = variable_enum; + } + } + else if( var_right ) + { // result = parameter - variable + CPPAD_ASSERT_UNKNOWN( local::NumRes(local::SubpvOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( local::NumArg(local::SubpvOp) == 2 ); + + // put operand addresses in tape + addr_t p = left.taddr_; + if( ! dyn_left ) + p = tape->Rec_.put_con_par(left.value_); + tape->Rec_.PutArg(p, right.taddr_); + // put operator in the tape + result.taddr_ = tape->Rec_.PutOp(local::SubpvOp); + // make result a variable + result.tape_id_ = tape_id; + result.ad_type_ = variable_enum; + } + else if( dyn_left | dyn_right ) + { addr_t arg0 = left.taddr_; + addr_t arg1 = right.taddr_; + if( ! dyn_left ) + arg0 = tape->Rec_.put_con_par(left.value_); + if( ! dyn_right ) + arg1 = tape->Rec_.put_con_par(right.value_); + // + // parameters with a dynamic parameter result + result.taddr_ = tape->Rec_.put_dyn_par( + result.value_, local::sub_dyn, arg0, arg1 + ); + result.tape_id_ = tape_id; + result.ad_type_ = dynamic_enum; + } + return result; +} + +// convert other cases into the case above +CPPAD_FOLD_AD_VALUED_BINARY_OPERATOR(-) + +} // END CppAD namespace + +# endif diff --git a/build-config/cppad/include/cppad/core/sub_eq.hpp b/build-config/cppad/include/cppad/core/sub_eq.hpp new file mode 100644 index 00000000..7344321a --- /dev/null +++ b/build-config/cppad/include/cppad/core/sub_eq.hpp @@ -0,0 +1,124 @@ +# ifndef CPPAD_CORE_SUB_EQ_HPP +# define CPPAD_CORE_SUB_EQ_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +// BEGIN CppAD namespace +namespace CppAD { + +template +AD& AD::operator -= (const AD &right) +{ + // compute the Base part + Base left; + left = value_; + value_ -= right.value_; + + // check if there is a recording in progress + local::ADTape* tape = AD::tape_ptr(); + if( tape == nullptr ) + return *this; + tape_id_t tape_id = tape->id_; + // tape_id cannot match the default value for tape_id_; i.e., 0 + CPPAD_ASSERT_UNKNOWN( tape_id > 0 ); + + // check if left and right tapes match + bool match_left = tape_id_ == tape_id; + bool match_right = right.tape_id_ == tape_id; + + // check if left and right are dynamic parameters + bool dyn_left = match_left & (ad_type_ == dynamic_enum); + bool dyn_right = match_right & (right.ad_type_ == dynamic_enum); + + // check if left and right are variables + bool var_left = match_left & (ad_type_ != dynamic_enum); + bool var_right = match_right & (right.ad_type_ != dynamic_enum); + + CPPAD_ASSERT_KNOWN( + tape_id_ == right.tape_id_ || ! match_left || ! match_right , + "-= : AD variables or dynamic parameters on different threads." + ); + if( var_left ) + { if( var_right ) + { // this = variable - variable + CPPAD_ASSERT_UNKNOWN( local::NumRes(local::SubvvOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( local::NumArg(local::SubvvOp) == 2 ); + + // put operand addresses in tape + tape->Rec_.PutArg(taddr_, right.taddr_); + // put operator in the tape + taddr_ = tape->Rec_.PutOp(local::SubvvOp); + // check that this is a variable + CPPAD_ASSERT_UNKNOWN( tape_id_ == tape_id ); + CPPAD_ASSERT_UNKNOWN( ad_type_ == variable_enum); + } + else if( (! dyn_right) & IdenticalZero(right.value_) ) + { // this = variable - 0 + } + else + { // this = variable - parameter + CPPAD_ASSERT_UNKNOWN( local::NumRes(local::SubvpOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( local::NumArg(local::SubvpOp) == 2 ); + + // put operand addresses in tape + addr_t p = right.taddr_; + if( ! dyn_right ) + p = tape->Rec_.put_con_par(right.value_); + tape->Rec_.PutArg(taddr_, p); + // put operator in the tape + taddr_ = tape->Rec_.PutOp(local::SubvpOp); + // check that this is a variable + CPPAD_ASSERT_UNKNOWN( tape_id_ == tape_id ); + CPPAD_ASSERT_UNKNOWN( ad_type_ == variable_enum); + } + } + else if( var_right ) + { // this = parameter - variable + CPPAD_ASSERT_UNKNOWN( local::NumRes(local::SubpvOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( local::NumArg(local::SubpvOp) == 2 ); + + // put operand addresses in tape + addr_t p = taddr_; + if( ! dyn_left ) + p = tape->Rec_.put_con_par(left); + tape->Rec_.PutArg(p, right.taddr_); + + // put operator in the tape + taddr_ = tape->Rec_.PutOp(local::SubpvOp); + + // make this a variable + tape_id_ = tape_id; + ad_type_ = variable_enum; + } + else if( dyn_left | dyn_right ) + { addr_t arg0 = taddr_; + addr_t arg1 = right.taddr_; + if( ! dyn_left ) + arg0 = tape->Rec_.put_con_par(left); + if( ! dyn_right ) + arg1 = tape->Rec_.put_con_par(right.value_); + // + // parameters with a dynamic parameter results + taddr_ = tape->Rec_.put_dyn_par( + value_, local::sub_dyn, arg0, arg1 + ); + tape_id_ = tape_id; + ad_type_ = dynamic_enum; + } + return *this; +} + +CPPAD_FOLD_ASSIGNMENT_OPERATOR(-=) + +} // END CppAD namespace + +# endif diff --git a/build-config/cppad/include/cppad/core/subgraph_jac_rev.hpp b/build-config/cppad/include/cppad/core/subgraph_jac_rev.hpp new file mode 100644 index 00000000..a58b2256 --- /dev/null +++ b/build-config/cppad/include/cppad/core/subgraph_jac_rev.hpp @@ -0,0 +1,351 @@ +# ifndef CPPAD_CORE_SUBGRAPH_JAC_REV_HPP +# define CPPAD_CORE_SUBGRAPH_JAC_REV_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-18 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ +/* +$begin subgraph_jac_rev$$ +$spell + Jacobians + Jacobian + Subgraphs + subgraph + jac + rcv + Taylor + rev + nr + nc + const + Bool + nnz +$$ + +$section Compute Sparse Jacobians Using Subgraphs$$ + +$head Syntax$$ +$icode%f%.subgraph_jac_rev(%x%, %subset%) +%$$ +$icode%f%.subgraph_jac_rev( + %select_domain%, %select_range%, %x%, %matrix_out% +)%$$ + +$head See Also$$ +$cref/clear_subgraph/subgraph_reverse/clear_subgraph/$$. + +$head Purpose$$ +We use $latex F : \B{R}^n \rightarrow \B{R}^m$$ to denote the +function corresponding to $icode f$$. +Here $icode n$$ is the $cref/domain/seq_property/Domain/$$ size, +and $icode m$$ is the $cref/range/seq_property/Range/$$ size, or $icode f$$. +The syntax above takes advantage of sparsity when computing the Jacobian +$latex \[ + J(x) = F^{(1)} (x) +\] $$ +The first syntax requires one to know what which elements of the Jacobian +they want to compute. +The second syntax computes the sparsity pattern and the value +of the Jacobian at the same time. +If one only wants the sparsity pattern, +it should be faster to use $cref subgraph_sparsity$$. + +$head Method$$ +This routine uses a subgraph technique. To be specific, +for each dependent variable, +it creates a subgraph of the operation sequence +containing the variables that affect the dependent variable. +This avoids the overhead of performing set operations +that is inherent in other methods for computing sparsity patterns. + +$head BaseVector$$ +The type $icode BaseVector$$ is a $cref SimpleVector$$ class with +$cref/elements of type/SimpleVector/Elements of Specified Type/$$ +$icode Base$$. + +$head SizeVector$$ +The type $icode SizeVector$$ is a $cref SimpleVector$$ class with +$cref/elements of type/SimpleVector/Elements of Specified Type/$$ +$code size_t$$. + +$head BoolVector$$ +The type $icode BoolVector$$ is a $cref SimpleVector$$ class with +$cref/elements of type/SimpleVector/Elements of Specified Type/$$ +$code bool$$. + +$head f$$ +This object has prototype +$codei% + ADFun<%Base%> %f% +%$$ +Note that the Taylor coefficients stored in $icode f$$ are affected +by this operation; see +$cref/uses forward/sparse_jac/Uses Forward/$$ below. + +$head x$$ +This argument has prototype +$codei% + const %BaseVector%& %x% +%$$ +It is the value of $icode x$$ at which we are computing the Jacobian. + +$head Uses Forward$$ +After each call to $cref Forward$$, +the object $icode f$$ contains the corresponding +$cref/Taylor coefficients/glossary/Taylor Coefficient/$$. +After a call to $code sparse_jac_forward$$ or $code sparse_jac_rev$$, +the zero order coefficients correspond to +$codei% + %f%.Forward(0, %x%) +%$$ +All the other forward mode coefficients are unspecified. + +$head subset$$ +This argument has prototype +$codei% + sparse_rcv<%SizeVector%, %BaseVector%>& %subset% +%$$ +Its row size is $icode%subset%.nr() == %m%$$, +and its column size is $icode%subset%.nc() == %n%$$. +It specifies which elements of the Jacobian are computed. +The input elements in its value vector +$icode%subset%.val()%$$ do not matter. +Upon return it contains the value of the corresponding elements +of the Jacobian. + +$head select_domain$$ +The argument $icode select_domain$$ has prototype +$codei% + const %BoolVector%& %select_domain% +%$$ +It has size $latex n$$ and specifies which independent variables +to include. + +$head select_range$$ +The argument $icode select_range$$ has prototype +$codei% + const %BoolVector%& %select_range% +%$$ +It has size $latex m$$ and specifies which components of the range +to include in the calculation. +A subgraph is built for each dependent variable and the selected set +of independent variables. + +$head matrix_out$$ +This argument has prototype +$codei% + sparse_rcv<%SizeVector%, %BaseVector%>& %matrix_out% +%$$ +This input value of $icode matrix_out$$ does not matter. +Upon return $icode matrix_out$$ is +$cref/sparse matrix/sparse_rcv/$$ representation of $latex F^{(1)} (x)$$. +The matrix has $latex m$$ rows, $latex n$$ columns. +If $icode%select_domain%[%j%]%$$ is true, +$icode%select_range%[%i%]%$$ is true, and +$latex F_i (x)$$ depends on $latex x_j$$, +then the pair $latex (i, j)$$ is in $icode matrix_out$$. +For each $icode%k% = 0 , %...%, %matrix_out%.nnz()%$$, let +$codei% + %i% = %matrix_out%.row()[%k%] + %j% = %matrix_out%.col()[%k%] + %v% = %matrix_out%.val()[%k%] +%$$ +It follows that the partial of $latex F_i (x)$$ with respect to +$latex x_j$$ is equal to $latex v$$. + + +$head Example$$ +$children% + example/sparse/subgraph_jac_rev.cpp% + example/sparse/subgraph_hes2jac.cpp +%$$ +The files $cref subgraph_jac_rev.cpp$$ and $cref subgraph_hes2jac.cpp$$ +are examples and tests using $code subgraph_jac_rev$$. +They returns $code true$$ for success and $code false$$ for failure. + +$end +----------------------------------------------------------------------------- +*/ +# include +# include + +namespace CppAD { // BEGIN_CPPAD_NAMESPACE + +/*! +Subgraph sparsity patterns. + +\tparam Base +is the base type for this recording. + +\tparam SizeVector +is the simple vector with elements of type size_t that is used for +row, column index sparsity patterns. + +\tparam BaseVector +a simple vector class with elements of type Base. + +\param x +a vector of length n, the number of independent variables in f +(this ADFun object). + +\param subset +specifices the subset of the sparsity pattern where the Jacobian is evaluated. +subset.nr() == m, +subset.nc() == n. +*/ +template +template +void ADFun::subgraph_jac_rev( + const BaseVector& x , + sparse_rcv& subset ) +{ size_t m = Range(); + size_t n = Domain(); + // + CPPAD_ASSERT_KNOWN( + subset.nr() == m, + "subgraph_jac_rev: subset.nr() not equal range dimension for f" + ); + CPPAD_ASSERT_KNOWN( + subset.nc() == n, + "subgraph_jac_rev: subset.nc() not equal domain dimension for f" + ); + // + // point at which we are evaluating Jacobian + Forward(0, x); + // + // nnz and row, column, and row_major vectors for subset + size_t nnz = subset.nnz(); + const SizeVector& row( subset.row() ); + const SizeVector& col( subset.col() ); + SizeVector row_major = subset.row_major(); + // + // determine set of independent variabels + local::pod_vector select_domain(n); + for(size_t j = 0; j < n; j++) + select_domain[j] = false; + for(size_t k = 0; k < nnz; k++) + select_domain[ col[k] ] = true; + // + // initialize reverse mode computation on subgraphs + subgraph_reverse(select_domain); + // + // memory used to hold subgraph_reverse results + BaseVector dw; + SizeVector dw_col; + // + // initialize index in row_major + size_t k = 0; + Base zero(0); + while(k < nnz ) + { size_t q = 1; + size_t i_dep = row[ row_major[k] ]; + size_t i_ind = col[ row_major[k] ]; + size_t ell = i_dep; + subgraph_reverse(q, ell, dw_col, dw); + // + size_t c = 0; + while( i_dep == ell ) + { // row numbers match + // + // advance c to possible match with column i_ind + while( c < size_t( dw_col.size() ) && dw_col[c] < i_ind ) + ++c; + // + // check for match with i_ind + if( i_ind == dw_col[c] ) + subset.set( row_major[k], dw[i_ind] ); + else + subset.set( row_major[k], zero); + // + // advance to next (i_dep, i_ind) + ++k; + if( k == nnz ) + { i_dep = m; + i_ind = n; + } + else + { i_dep = row[ row_major[k] ]; + i_ind = col[ row_major[k] ]; + } + } + } + return; +} +template +template +void ADFun::subgraph_jac_rev( + const BoolVector& select_domain , + const BoolVector& select_range , + const BaseVector& x , + sparse_rcv& matrix_out ) +{ size_t m = Range(); + size_t n = Domain(); + // + // point at which we are evaluating Jacobian + Forward(0, x); + // + // nnz and row, column, and row_major vectors for subset + local::pod_vector row_out; + local::pod_vector col_out; + local::pod_vector_maybe val_out; + // + // initialize reverse mode computation on subgraphs + subgraph_reverse(select_domain); + // + // memory used to hold subgraph_reverse results + BaseVector dw; + SizeVector col; + // + // loop through selected independent variables + for(size_t i = 0; i < m; ++i) if( select_range[i] ) + { // compute Jacobian and sparsity for this dependent variable + size_t q = 1; + subgraph_reverse(q, i, col, dw); + CPPAD_ASSERT_UNKNOWN( size_t( dw.size() ) == n ); + // + // offset for this dependent variable + size_t index = row_out.size(); + CPPAD_ASSERT_UNKNOWN( col_out.size() == index ); + CPPAD_ASSERT_UNKNOWN( val_out.size() == index ); + // + // extend vectors to hold results for this dependent variable + size_t col_size = size_t( col.size() ); + row_out.extend( col_size ); + col_out.extend( col_size ); + val_out.extend( col_size ); + // + // store results for this dependent variable + for(size_t c = 0; c < col_size; ++c) + { row_out[index + c] = i; + col_out[index + c] = col[c]; + val_out[index + c] = dw[ col[c] ]; + } + } + // + // create sparsity pattern corresponding to row_out, col_out + size_t nr = m; + size_t nc = n; + size_t nnz = row_out.size(); + sparse_rc pattern(nr, nc, nnz); + for(size_t k = 0; k < nnz; ++k) + pattern.set(k, row_out[k], col_out[k]); + // + // create sparse matrix + sparse_rcv matrix(pattern); + for(size_t k = 0; k < nnz; ++k) + matrix.set(k, val_out[k]); + // + // return matrix + matrix_out = matrix; + // + return; +} +} // END_CPPAD_NAMESPACE +# endif diff --git a/build-config/cppad/include/cppad/core/subgraph_reverse.hpp b/build-config/cppad/include/cppad/core/subgraph_reverse.hpp new file mode 100644 index 00000000..7286745a --- /dev/null +++ b/build-config/cppad/include/cppad/core/subgraph_reverse.hpp @@ -0,0 +1,494 @@ +# ifndef CPPAD_CORE_SUBGRAPH_REVERSE_HPP +# define CPPAD_CORE_SUBGRAPH_REVERSE_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ +/* +$begin subgraph_reverse$$ +$spell + resize + subgraph + Subgraphs + dw + Taylor + Bool + const +$$ + +$section Reverse Mode Using Subgraphs$$ + +$head Syntax$$ +$icode%f%.subgraph_reverse(%select_domain%) +%$$ +$icode%f%.subgraph_reverse(%q%, %ell%, %col%, %dw%) +%$$ +$icode%f%.clear_subgraph() +%$$ + +$head Purpose$$ +We use $latex F : \B{R}^n \rightarrow \B{R}^m$$ to denote the +$cref/AD function/glossary/AD Function/$$ corresponding to $icode f$$. +Reverse mode computes the derivative of the $cref Forward$$ mode +$cref/Taylor coefficients/glossary/Taylor Coefficient/$$ +with respect to the domain variable $latex x$$. + +$head Notation$$ +We use the reverse mode +$cref/notation/reverse_any/Notation/$$ with the following change: +the vector +$cref/w^(k)/reverse_any/Notation/w^(k)/$$ is defined +$latex \[ +w_i^{(k)} = \left\{ \begin{array}{ll} + 1 & {\rm if} \; k = q-1 \; \R{and} \; i = \ell + \\ + 0 & {\rm otherwise} +\end{array} \right. +\] $$ + +$head BaseVector$$ +The type $icode BaseVector$$ must be a $cref SimpleVector$$ class with +$cref/elements of type/SimpleVector/Elements of Specified Type/$$ +$icode Base$$. +The routine $cref CheckSimpleVector$$ will generate an error message +if this is not the case. + +$head BoolVector$$ +The type $icode BoolVector$$ is a $cref SimpleVector$$ class with +$cref/elements of type/SimpleVector/Elements of Specified Type/$$ +$code bool$$. + +$head SizeVector$$ +The type $icode SizeVector$$ is a $cref SimpleVector$$ class with +$cref/elements of type/SimpleVector/Elements of Specified Type/$$ +$code size_t$$. + +$head select_domain$$ +The argument $icode select_domain$$ has prototype +$codei% + const %BoolVector%& %select_domain% +%$$ +It has size $latex n$$ and specifies which independent variables +to include in future $code subgraph_reverse$$ calculations. +If $icode%select_domain%[%j%]%$$ is false, +it is assumed that $latex u^{(k)}_j = 0$$ for $latex k > 0$$; i.e., +the $th j$$ component of the Taylor coefficient for $latex x$$, +with order greater that zero, are zero; see +$cref/u^(k)/reverse_any/Notation/u^(k)/$$. + +$head q$$ +The argument $icode q$$ has prototype +$codei% + size_t %q% +%$$ +and specifies the number of Taylor coefficient orders to be differentiated. + +$head ell$$ +The argument $icode ell$$ has prototype +$codei% + size_t %ell% +%$$ +and specifies the dependent variable index that we are computing +the derivatives for; i.e. $latex \ell$$. +This index can only be used once per, and after, a call that selects +the independent variables using $icode select_domain$$. + +$head col$$ +This argument $icode col$$ has prototype +$codei% + %SizeVector% %col% +%$$ +The input size and value of its elements do not matter. +The $icode%col%.resize%$$ member function is used to change its size +to the number the number of possible non-zero derivative components. +For each $icode c$$, +$codei% + %select_domain%[ %col%[%c%] ] == true + %col%[%c%+1] >= %col%[%c%] +%$$ +and the derivative with respect to the $th j$$ independent +variable is possibly non-zero where +$icode%j% = %col%[%c%]%$$. + +$head dw$$ +The argument $icode dw$$ has prototype +$codei% + %Vector% %dw% +%$$ +Its input size and value does not matter. +Upon return, +it is a vector with size $latex n \times q$$. +For $latex c = 0 , \ldots , %col%.size()-1$$, +and $latex k = 0, \ldots , q-1$$, +$latex \[ + dw[ j * q + k ] = W^{(1)} ( x )_{j,k} +\] $$ +is the derivative of the specified Taylor coefficients w.r.t the $th j$$ +independent variable where $icode%j% = %col%[%c%]%$$. +Note that this corresponds to the $cref reverse_any$$ convention when +$cref/w/reverse_any/w/$$ has size $icode%m% * %q%$$. + +$head clear_subgraph$$ +Calling this routine will free memory that holds +information between calls to subgraph calculations so that +it does not need to be recalculated. +(This memory is automatically freed when $icode f$$ is deleted.) +You cannot free this memory between calls that select the domain +and corresponding calls that compute reverse mode derivatives. +Some of this information is also used by $cref subgraph_sparsity$$. + +$head Example$$ +$children% + example/sparse/subgraph_reverse.cpp +%$$ +The file +$cref subgraph_reverse.cpp$$ +contains an example and test of this operation. + +$end +*/ +namespace CppAD { // BEGIN_CPPAD_NAMESPACE +/*! +\file subgraph_reverse.hpp +Compute derivatvies using reverse mode and subgraphs. +*/ + +/// clear all subgraph information +template +void ADFun::clear_subgraph(void) +{ play_.clear_random(); + subgraph_info_.clear(); + subgraph_partial_.clear(); +} + +/*! +Initialize reverse mode derivative computation on subgraphs. + +\param select_domain +is a vector with size equal to the dimension of the domain for this function. +Only derivatives w.r.t. the components that are true will be computed. + +\par subgraph_info_.map_user_op() +If the input size of this vector is zero, +its value for this player (play_) is computed. + +\par subgraph_info.in_subgraph_ +This vector is initialized for a reverse mode computation on subgraphs. + +\par subgraph_info.select_domain() +This vector is set equal to the select_domain argument. + +\par subgraph_info.process_range() +This vector is initialized to have size Range() and its elements are false. +*/ + +template +template +void ADFun::subgraph_reverse( const BoolVector& select_domain ) +{ using local::pod_vector; + // + CPPAD_ASSERT_UNKNOWN( + dep_taddr_.size() == subgraph_info_.n_dep() + ); + CPPAD_ASSERT_UNKNOWN( + size_t( select_domain.size() ) == subgraph_info_.n_ind() + ); + + // map_user_op + if( subgraph_info_.map_user_op().size() == 0 ) + subgraph_info_.set_map_user_op(&play_); + else + { CPPAD_ASSERT_UNKNOWN( subgraph_info_.check_map_user_op(&play_) ); + } + CPPAD_ASSERT_UNKNOWN( + subgraph_info_.map_user_op().size() == play_.num_op_rec() + ); + + // initialize for reverse mode subgraph computations + switch( play_.address_type() ) + { + case local::play::unsigned_short_enum: + subgraph_info_.init_rev(&play_, select_domain); + break; + + case local::play::unsigned_int_enum: + subgraph_info_.init_rev(&play_, select_domain); + break; + + case local::play::size_t_enum: + subgraph_info_.init_rev(&play_, select_domain); + break; + + default: + CPPAD_ASSERT_UNKNOWN(false); + } + CPPAD_ASSERT_UNKNOWN( + subgraph_info_.in_subgraph().size() == play_.num_op_rec() + ); + + return; +} + + +/*! +Use reverse mode to compute derivative of Taylor coefficients on a subgraph. + +The function +\f$ X : {\bf R} \times {\bf R}^{n \times q} \rightarrow {\bf R} \f$ +is defined by +\f[ +X(t , u) = \sum_{k=0}^{q-1} u^{(k)} t^k +\f] +The function +\f$ Y : {\bf R} \times {\bf R}^{n \times q} \rightarrow {\bf R} \f$ +is defined by +\f[ +Y(t , u) = F[ X(t, u) ] +\f] +The function +\f$ W : {\bf R}^{n \times q} \rightarrow {\bf R} \f$ is defined by +\f[ +W(u) = \sum_{k=0}^{q-1} ( w^{(k)} )^{\rm T} +\frac{1}{k !} \frac{ \partial^k } { t^k } Y(0, u) +\f] + +\param q +is the number of Taylor coefficient we are differentiating. + +\param ell +is the component of the range that is selected for differentiation. + +\param col +is the set of indices j = col[c] where the return value is defined. +If an index j is not in col, then either its derivative is zero, +or it is not in select_domain. + +\param dw +Is a vector \f$ dw \f$ such that +for j = col[c], +\f$ k = 0 , \ldots , q-1 \f$ +\f[ + dw[ j * q + k ] = W^{(1)} ( x )_{j,k} +\f] +where the matrix \f$ x \f$ is the value for \f$ u \f$ +that corresponding to the forward mode Taylor coefficients +for the independent variables as specified by previous calls to Forward. + +\par subgraph_info.process_range() +The element process_range[ell] is set to true by this operation. + +\par subgraph_info.in_subgraph_ +some of the elements of this vector are set to have value ell +(so it can not longer be used to determine the subgraph corresponding to +the ell-th dependent variable). +*/ +template +template +void ADFun::subgraph_reverse_helper( + size_t q , + size_t ell , + SizeVector& col , + BaseVector& dw ) +{ using local::pod_vector; + // used to identify the RecBase type in calls to sweeps + RecBase not_used_rec_base(0.0); + // + // get a random iterator for this player + play_.template setup_random(); + typename local::play::const_random_iterator random_itr = + play_.template get_random(); + + // check BaseVector is Simple Vector class with Base type elements + CheckSimpleVector(); + CPPAD_ASSERT_KNOWN( + q > 0, + "The second argument to Reverse must be greater than zero." + ); + CPPAD_ASSERT_KNOWN( + num_order_taylor_ >= q, + "Less than q Taylor coefficients are currently stored" + " in this ADFun object." + ); + 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." + ); + CPPAD_ASSERT_KNOWN( + ell < dep_taddr_.size(), + "dependent variable index in to large for this function" + ); + CPPAD_ASSERT_KNOWN( + subgraph_info_.process_range()[ell] == false, + "This dependent variable index has already been processed\n" + "after the previous subgraph_reverse(select_domain)." + ); + + // subgraph of operators connected to dependent variable ell + pod_vector subgraph; + subgraph_info_.get_rev( + random_itr, dep_taddr_, addr_t(ell), subgraph + ); + + // Add all the atomic function call operators + // for calls that have first operator in the subgraph + local::subgraph::entire_call(random_itr, subgraph); + + // First add the BeginOp and EndOp to the subgraph and then sort it + // sort the subgraph + addr_t i_op_begin_op = 0; + addr_t i_op_end_op = addr_t( play_.num_op_rec() - 1); + subgraph.push_back(i_op_begin_op); + subgraph.push_back(i_op_end_op); + std::sort( subgraph.data(), subgraph.data() + subgraph.size() ); + CPPAD_ASSERT_UNKNOWN( subgraph[0] == i_op_begin_op ); + CPPAD_ASSERT_UNKNOWN( subgraph[subgraph.size()-1] == i_op_end_op ); + /* + // Use this printout for debugging + std::cout << "{ "; + for(size_t k = 0; k < subgraph.size(); k++) + { if( k > 0 ) + std::cout << ", "; + std::cout << subgraph[k]; + } + std::cout << "}\n"; + */ + + // initialize subgraph_partial_ matrix to zero on subgraph + Base zero(0); + subgraph_partial_.resize(num_var_tape_ * q); + for(size_t k = 0; k < subgraph.size(); ++k) + { + size_t i_op = size_t( subgraph[k] ); + local::OpCode op; + const addr_t* arg; + size_t i_var; + random_itr.op_info(i_op, op, arg, i_var); + if( NumRes(op) == 0 ) + { CPPAD_ASSERT_UNKNOWN( + op == local::AFunOp || + op == local::FunapOp || + op == local::FunavOp || + op == local::FunrpOp || + op == local::EndOp + ); + } + else if( op != local::BeginOp ) + { CPPAD_ASSERT_UNKNOWN( i_var >= NumRes(op) ); + size_t j_var = i_var + 1 - NumRes(op); + for(size_t i = j_var; i <= i_var; ++i) + { for(size_t j = 0; j < q; ++j) + subgraph_partial_[i * q + j] = zero; + } + } + } + + // set partial to one for component we are differentiating + subgraph_partial_[ dep_taddr_[ell] * q + q - 1] = Base(1); + + // evaluate the derivatives + CPPAD_ASSERT_UNKNOWN( cskip_op_.size() == play_.num_op_rec() ); + CPPAD_ASSERT_UNKNOWN( load_op2var_.size() == play_.num_var_load_rec() ); + size_t n = Domain(); + // + local::play::const_subgraph_iterator subgraph_itr = + play_.end_subgraph(random_itr, &subgraph); + // + local::sweep::reverse( + q - 1, + n, + num_var_tape_, + &play_, + cap_order_taylor_, + taylor_.data(), + q, + subgraph_partial_.data(), + cskip_op_.data(), + load_op2var_, + subgraph_itr, + not_used_rec_base + ); + + // number of non-zero in return value + size_t col_size = 0; + size_t subgraph_index = 0; + CPPAD_ASSERT_UNKNOWN( subgraph[subgraph_index] == 0 ); + // Skip BeginOp + ++subgraph_index; + while( subgraph_index < subgraph.size() ) + { // check for InvOp + if( subgraph[subgraph_index] > addr_t(n) ) + subgraph_index = subgraph.size(); + else + { ++col_size; + ++subgraph_index; + } + } + col.resize(col_size); + + // return the derivative values + dw.resize(n * q); + for(size_t c = 0; c < col_size; ++c) + { size_t i_op = size_t( subgraph[c + 1] ); + CPPAD_ASSERT_UNKNOWN( play_.GetOp(i_op) == local::InvOp ); + // + size_t j = i_op - 1; + CPPAD_ASSERT_UNKNOWN( i_op == random_itr.var2op( ind_taddr_[j] ) ); + // + // return paritial for this independent variable + col[c] = j; + for(size_t k = 0; k < q; k++) + dw[j * q + k ] = subgraph_partial_[ind_taddr_[j] * q + k]; + } + // + CPPAD_ASSERT_KNOWN( ! ( hasnan(dw) && check_for_nan_ ) , + "f.subgraph_reverse(dw, q, ell): dw has a nan,\n" + "but none of f's Taylor coefficents are nan." + ); + // + return; +} +/*! +\copydoc subgraph_reverse_helper + +*/ +template +template +void ADFun::subgraph_reverse( + size_t q , + size_t ell , + SizeVector& col , + BaseVector& dw ) +{ using local::pod_vector; + // + // call proper version of helper function + switch( play_.address_type() ) + { + case local::play::unsigned_short_enum: + subgraph_reverse_helper(q, ell, col, dw); + break; + + case local::play::unsigned_int_enum: + subgraph_reverse_helper(q, ell, col, dw); + break; + + case local::play::size_t_enum: + subgraph_reverse_helper(q, ell, col, dw); + break; + + default: + CPPAD_ASSERT_UNKNOWN(false); + } + // + return; +} + +} // END_CPPAD_NAMESPACE +# endif diff --git a/build-config/cppad/include/cppad/core/subgraph_sparsity.hpp b/build-config/cppad/include/cppad/core/subgraph_sparsity.hpp new file mode 100644 index 00000000..40f7f038 --- /dev/null +++ b/build-config/cppad/include/cppad/core/subgraph_sparsity.hpp @@ -0,0 +1,242 @@ +# ifndef CPPAD_CORE_SUBGRAPH_SPARSITY_HPP +# define CPPAD_CORE_SUBGRAPH_SPARSITY_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-18 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ +/* +$begin subgraph_sparsity$$ +$spell + const + subgraph + subgraphs + rc + Jacobian + bool +$$ + +$section Subgraph Dependency Sparsity Patterns$$ + +$head Syntax$$ +$icode%f%.subgraph_sparsity( + %select_domain%, %select_range%, %transpose%, %pattern_out% +)%$$ + +$head See Also$$ +$cref/clear_subgraph/subgraph_reverse/clear_subgraph/$$. + +$head Notation$$ +We use $latex F : \B{R}^n \rightarrow \B{R}^m$$ to denote the +$cref/AD function/glossary/AD Function/$$ corresponding to +the operation sequence stored in $icode f$$. + + +$head Method$$ +This routine uses a subgraph technique. To be specific, +for each dependent variable, +it creates a subgraph of the operation sequence +containing the variables that affect the dependent variable. +This avoids the overhead of performing set operations +that is inherent in other methods for computing sparsity patterns. + +$head Atomic Function$$ +The sparsity calculation for +$cref/atomic functions/atomic_two_afun/$$ in the $icode f$$ operation sequence +are not efficient. To be specific, each atomic function is treated as if +all of its outputs depend on all of its inputs. +This may be improved upon in the future; see the +$cref/subgraph sparsity/wish_list/Subgraph/Sparsity/$$ +wish list item. + +$head BoolVector$$ +The type $icode BoolVector$$ is a $cref SimpleVector$$ class with +$cref/elements of type/SimpleVector/Elements of Specified Type/$$ +$code bool$$. + +$head SizeVector$$ +The type $icode SizeVector$$ is a $cref SimpleVector$$ class with +$cref/elements of type/SimpleVector/Elements of Specified Type/$$ +$code size_t$$. + +$head f$$ +The object $icode f$$ has prototype +$codei% + ADFun<%Base%> %f% +%$$ + +$head select_domain$$ +The argument $icode select_domain$$ has prototype +$codei% + const %BoolVector%& %select_domain% +%$$ +It has size $latex n$$ and specifies which independent variables +to include in the calculation. +If not all the independent variables are included in the calculation, +a forward pass on the operation sequence is used to determine which +nodes may be in the subgraphs. + +$head select_range$$ +The argument $icode select_range$$ has prototype +$codei% + const %BoolVector%& %select_range% +%$$ +It has size $latex m$$ and specifies which components of the range +to include in the calculation. +A subgraph is built for each dependent variable +and the selected set of independent variables. + +$head transpose$$ +This argument has prototype +$codei% + bool %transpose% +%$$ +If $icode transpose$$ it is false (true), +upon return $icode pattern_out$$ is a sparsity pattern for +$latex J(x)$$ ($latex J(x)^\R{T}$$) defined below. + +$head pattern_out$$ +This argument has prototype +$codei% + sparse_rc<%SizeVector%>& %pattern_out% +%$$ +This input value of $icode pattern_out$$ does not matter. +Upon return $icode pattern_out$$ is a +$cref/dependency pattern/dependency.cpp/Dependency Pattern/$$ +for $latex F(x)$$. +The pattern has $latex m$$ rows, $latex n$$ columns. +If $icode%select_domain%[%j%]%$$ is true, +$icode%select_range%[%i%]%$$ is true, and +$latex F_i (x)$$ depends on $latex x_j$$, +then the pair $latex (i, j)$$ is in $icode pattern_out$$. +Not that this is also a sparsity pattern for the Jacobian +$latex \[ + J(x) = R F^{(1)} (x) D +\] $$ +where $latex D$$ ($latex R$$) is the diagonal matrix corresponding +to $icode select_domain$$ ($icode select_range$$). + +$head Example$$ +$children% + example/sparse/subgraph_sparsity.cpp +%$$ +The file +$cref subgraph_sparsity.cpp$$ +contains an example and test of this operation. + +$end +----------------------------------------------------------------------------- +*/ +# include +# include + +namespace CppAD { // BEGIN_CPPAD_NAMESPACE + +/*! +Subgraph sparsity patterns. + +\tparam Base +is the base type for this recording. + +\tparam SizeVector +is the simple vector with elements of type size_t that is used for +row, column index sparsity patterns. + +\param select_domain +sparsity pattern for the diagonal of the square matrix D. + +\param select_range +sparsity pattern for the diagnoal of the square matrix R + +\param transpose +If true, the return is a dependency sparsity pattern for +\f$ D F^{(1)} (x)^T R \f$ + +\param pattern_out +The input value does not matter. +The return value is a dependency sparsity pattern for \f$ R F^{(1)} (x) D \f$ +where F is the function corresponding to the operation sequence +and x is any argument value. +is the sparsity pattern transposed. +*/ +template +template +void ADFun::subgraph_sparsity( + const BoolVector& select_domain , + const BoolVector& select_range , + bool transpose , + sparse_rc& pattern_out ) +{ + // compute the sparsity pattern in row, col + local::pod_vector row; + local::pod_vector col; + + // create the optimized recording + switch( play_.address_type() ) + { + case local::play::unsigned_short_enum: + local::subgraph::subgraph_sparsity( + &play_, + subgraph_info_, + dep_taddr_, + select_domain, + select_range, + row, + col + ); + break; + + case local::play::unsigned_int_enum: + local::subgraph::subgraph_sparsity( + &play_, + subgraph_info_, + dep_taddr_, + select_domain, + select_range, + row, + col + ); + break; + + case local::play::size_t_enum: + local::subgraph::subgraph_sparsity( + &play_, + subgraph_info_, + dep_taddr_, + select_domain, + select_range, + row, + col + ); + break; + + default: + CPPAD_ASSERT_UNKNOWN(false); + } + + CPPAD_ASSERT_UNKNOWN( row.size() == col.size() ); + + // return the sparsity pattern + size_t nr = dep_taddr_.size(); + size_t nc = ind_taddr_.size(); + size_t nnz = row.size(); + if( transpose ) + { pattern_out.resize(nc, nr, nnz); + for(size_t k = 0; k < nnz; k++) + pattern_out.set(k, col[k], row[k]); + } + else + { pattern_out.resize(nr, nc, nnz); + for(size_t k = 0; k < nnz; k++) + pattern_out.set(k, row[k], col[k]); + } + return; +} +} // END_CPPAD_NAMESPACE +# endif diff --git a/build-config/cppad/include/cppad/core/tape_link.hpp b/build-config/cppad/include/cppad/core/tape_link.hpp new file mode 100644 index 00000000..cbe865d6 --- /dev/null +++ b/build-config/cppad/include/cppad/core/tape_link.hpp @@ -0,0 +1,265 @@ +# ifndef CPPAD_CORE_TAPE_LINK_HPP +# define CPPAD_CORE_TAPE_LINK_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +# include +# include +# include + +// needed before one can use CPPAD_ASSERT_FIRST_CALL_NOT_PARALLEL +# include + +namespace CppAD { // BEGIN_CPPAD_NAMESPACE +/*! +\file tape_link.hpp +Routines that Link AD and local::ADTape Objects. + +The routines that connect the AD class to the corresponding tapes +(one for each thread). +*/ + +/*! +Pointer to the tape identifier for this AD class and the specific thread. + +\tparam Base +is the base type for this AD class. + +\param thread +is the thread number. The following condition must hold +\code +(! thread_alloc::in_parallel()) || thread == thread_alloc::thread_num() +\endcode + +\return +is a pointer to the tape identifier for this thread and AD class. +*/ +template +tape_id_t* AD::tape_id_ptr(size_t thread) +{ CPPAD_ASSERT_FIRST_CALL_NOT_PARALLEL; + static tape_id_t tape_id_table[CPPAD_MAX_NUM_THREADS]; + CPPAD_ASSERT_UNKNOWN( + (! thread_alloc::in_parallel()) || thread == thread_alloc::thread_num() + ); + return tape_id_table + thread; +} + +/*! +Handle for the tape for this AD class and the specific thread. + +\tparam Base +is the base type for this AD class. + + +\param thread +is the thread number; i.e., +\code +(! thread_alloc::in_parallel()) || thread == thread_alloc::thread_num() +\endcode + +\return +is a handle for the tape for this AD class and the specified thread. +*/ +template +local::ADTape** AD::tape_handle(size_t thread) +{ CPPAD_ASSERT_FIRST_CALL_NOT_PARALLEL; + static local::ADTape* tape_table[CPPAD_MAX_NUM_THREADS]; + CPPAD_ASSERT_UNKNOWN( + (! thread_alloc::in_parallel()) || thread == thread_alloc::thread_num() + ); + return tape_table + thread; +} + +/*! +Pointer for the tape for this AD class and the current thread. + +\code +thread == thread_alloc::thread_num() +\endcode + +\tparam Base +is the base type corresponding to AD operations. + +\return +is a pointer to the tape that is currently recording AD operations +for the current thread. +If this value is nullptr, there is no tape currently +recording AD operations for this thread. +*/ +template +local::ADTape* AD::tape_ptr(void) +{ size_t thread = thread_alloc::thread_num(); + return *tape_handle(thread); +} + +/*! +Pointer for the tape for this AD class and the specified tape +identifier. + +\tparam Base +is the base type corresponding to AD operations. + +\param tape_id +is the identifier for the tape that is currently recording +AD operations for the current thread. +It must hold that the current thread is +\code + thread = size_t( tape_id % CPPAD_MAX_NUM_THREADS ) +\endcode +and that there is a tape recording AD operations +for this thread. +If this is not the currently executing thread, +a variable from a different thread is being recorded on the +tape for this thread which is a user error. + +\return +is a pointer to the tape that is currently recording AD operations +for the current thread (and it is not nullptr). + +\par Restrictions +This routine should only be called if there is a tape recording operaitons +for the specified thread. +*/ +template +local::ADTape* AD::tape_ptr(tape_id_t tape_id) +{ size_t thread = size_t( tape_id % CPPAD_MAX_NUM_THREADS ); + CPPAD_ASSERT_KNOWN( + thread == thread_alloc::thread_num(), + "Attempt to use an AD variable with two different threads." + ); + CPPAD_ASSERT_UNKNOWN( tape_id == *tape_id_ptr(thread) ); + CPPAD_ASSERT_UNKNOWN( *tape_handle(thread) != nullptr ); + return *tape_handle(thread); +} + +/*! +Create and delete tapes that record AD operations for current thread. + +\par thread +the current thread is given by +\code +thread = thread_alloc::thread_num() +\endcode + +\tparam Base +is the base type corresponding to AD operations. + +\param job +This argument determines if we are creating a new tape, or deleting an +old one. + +- new_tape_manage : +Creates and a new tape. +It is assumed that there is no tape recording AD operations +for this thread when tape_manage is called. + +- delete_tape_manage : +It is assumed that there is a tape recording AD operations +for this thread when tape_manage is called. +The value of *tape_id_ptr(thread) will be advanced by + CPPAD_MAX_NUM_THREADS. + + +\return +- job == new_tape_manage: a pointer to the new tape is returned. +- job == delete_tape_manage: the value nullptr is returned. +*/ +template +local::ADTape* AD::tape_manage(tape_manage_enum job) +{ + CPPAD_ASSERT_UNKNOWN( + job == new_tape_manage || job == delete_tape_manage + ); + // thread, tape_id, and tape for this call + size_t thread = thread_alloc::thread_num(); + tape_id_t* tape_id_p = tape_id_ptr(thread); + local::ADTape** tape_h = tape_handle(thread); + + + // ----------------------------------------------------------------------- + // new_tape_manage + if( job == new_tape_manage ) + { + // tape for this thread must be null at the start + CPPAD_ASSERT_UNKNOWN( *tape_h == nullptr ); + + // allocate separate memroy to avoid false sharing + *tape_h = new local::ADTape(); + + // if tape id is zero, initialize it so that + // thread == tape id % CPPAD_MAX_NUM_THREADS + if( *tape_id_p == 0 ) + { size_t new_tape_id = thread + CPPAD_MAX_NUM_THREADS; + CPPAD_ASSERT_KNOWN( + size_t( std::numeric_limits::max() ) >= new_tape_id, + "cppad_tape_id_type maximum value has been exceeded" + ); + *tape_id_p = static_cast( new_tape_id ); + } + // make sure tape_id value is valid for this thread + CPPAD_ASSERT_UNKNOWN( + size_t( *tape_id_p % CPPAD_MAX_NUM_THREADS ) == thread + ); + // set the tape_id for this tape + (*tape_h)->id_ = *tape_id_p; + } + // ----------------------------------------------------------------------- + // delete_tape_manage + if( job == delete_tape_manage ) + { // delete this tape + CPPAD_ASSERT_UNKNOWN( *tape_h != nullptr ); + delete *tape_h; + *tape_h = nullptr; + // + // advance tape_id so that all AD variables become parameters + CPPAD_ASSERT_KNOWN( + std::numeric_limits::max() + - CPPAD_MAX_NUM_THREADS > *tape_id_p, + "To many different tapes given the type used for " + "CPPAD_TAPE_ID_TYPE" + ); + *tape_id_p += CPPAD_MAX_NUM_THREADS; + } + // ----------------------------------------------------------------------- + return *tape_h; +} + +/*! +Get a pointer to tape that records AD operations for the current thread. + +\tparam Base +is the base type corresponding to AD operations. + +\par thread +The current thread must be given by +\code + thread = this->tape_id_ % CPPAD_MAX_NUM_THREADS +\endcode + +\return +is a pointer to the tape that is currently recording AD operations +for the current thread. +This value must not be nullptr; i.e., there must be a tape currently +recording AD operations for this thread. +*/ + +template +local::ADTape *AD::tape_this(void) const +{ + size_t thread = size_t( tape_id_ % CPPAD_MAX_NUM_THREADS ); + CPPAD_ASSERT_UNKNOWN( tape_id_ == *tape_id_ptr(thread) ); + CPPAD_ASSERT_UNKNOWN( *tape_handle(thread) != nullptr ); + return *tape_handle(thread); +} + +} // END_CPPAD_NAMESPACE +# endif diff --git a/build-config/cppad/include/cppad/core/test_vector.hpp b/build-config/cppad/include/cppad/core/test_vector.hpp new file mode 100644 index 00000000..34182adc --- /dev/null +++ b/build-config/cppad/include/cppad/core/test_vector.hpp @@ -0,0 +1,135 @@ +# ifndef CPPAD_CORE_TEST_VECTOR_HPP +# define CPPAD_CORE_TEST_VECTOR_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-17 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +/* +$begin test_vector$$ +$spell + autotools + ifdef + undef + Microsofts + CppADvector + hpp + std + endif + ublas + Dir + valarray + stdvector +$$ + + +$section Choosing The Vector Testing Template Class$$ + +$head Deprecated 2012-07-03$$ +The $code CPPAD_TEST_VECTOR$$ macro has been deprecated, +use $cref/CPPAD_TESTVECTOR/testvector/$$ instead. + +$head Syntax$$ +$codei%CPPAD_TEST_VECTOR<%Scalar%> +%$$ + +$head Introduction$$ +Many of the CppAD $cref/examples/example/$$ and tests use +the $code CPPAD_TEST_VECTOR$$ template class to pass information. +The default definition for this template class is +$cref/CppAD::vector/CppAD_vector/$$. + +$head MS Windows$$ +The include path for boost is not defined in the Windows project files. +If we are using Microsofts compiler, the following code overrides the setting +of $code CPPAD_BOOSTVECTOR$$: +$srccode%cpp% */ +// The next 7 lines are C++ source code. +# ifdef _MSC_VER +# if CPPAD_BOOSTVECTOR +# undef CPPAD_BOOSTVECTOR +# define CPPAD_BOOSTVECTOR 0 +# undef CPPAD_CPPADVECTOR +# define CPPAD_CPPADVECTOR 1 +# endif +# endif +/* %$$ + +$head CppAD::vector$$ +By default $code CPPAD_CPPADVECTOR$$ is true +and $code CPPAD_TEST_VECTOR$$ is defined by the following source code +$srccode%cpp% */ +// The next 3 line are C++ source code. +# if CPPAD_CPPADVECTOR +# define CPPAD_TEST_VECTOR CppAD::vector +# endif +/* %$$ +If you specify $code --with-eigenvector$$ on the +$cref/configure/autotools/Configure/$$ command line, +$code CPPAD_EIGENVECTOR$$ is true. +This vector type cannot be supported by $code CPPAD_TEST_VECTOR$$ +(use $cref/CPPAD_TESTVECTOR/testvector/$$ for this support) +so $code CppAD::vector$$ is used in this case +$srccode%cpp% */ +// The next 3 line are C++ source code. +# if CPPAD_EIGENVECTOR +# define CPPAD_TEST_VECTOR CppAD::vector +# endif +/* %$$ + + +$head std::vector$$ +If you specify $code --with-stdvector$$ on the +$cref/configure/autotools/Configure/$$ +command line during CppAD installation, +$code CPPAD_STDVECTOR$$ is true +and $code CPPAD_TEST_VECTOR$$ is defined by the following source code +$srccode%cpp% */ +// The next 4 lines are C++ source code. +# if CPPAD_STDVECTOR +# include +# define CPPAD_TEST_VECTOR std::vector +# endif +/* %$$ +In this case CppAD will use $code std::vector$$ for its examples and tests. +Use of $code CppAD::vector$$, $code std::vector$$, +and $code std::valarray$$ with CppAD is always tested to some degree. +Specifying $code --with-stdvector$$ will increase the amount of +$code std::vector$$ testing. + +$head boost::numeric::ublas::vector$$ +If you specify a value for $icode boost_dir$$ on the configure +command line during CppAD installation, +$code CPPAD_BOOSTVECTOR$$ is true +and $code CPPAD_TEST_VECTOR$$ is defined by the following source code +$srccode%cpp% */ +// The next 4 lines are C++ source code. +# if CPPAD_BOOSTVECTOR +# include +# define CPPAD_TEST_VECTOR boost::numeric::ublas::vector +# endif +/* %$$ +In this case CppAD will use Ublas vectors for its examples and tests. +Use of $code CppAD::vector$$, $code std::vector$$, +and $code std::valarray$$ with CppAD is always tested to some degree. +Specifying $icode boost_dir$$ will increase the amount of +Ublas vector testing. + +$head CppADvector Deprecated 2007-07-28$$ +The preprocessor symbol $code CppADvector$$ is defined to +have the same value as $code CPPAD_TEST_VECTOR$$ but its use is deprecated: +$srccode%cpp% */ +# define CppADvector CPPAD_TEST_VECTOR +/* %$$ +$end +------------------------------------------------------------------------ +*/ + +# endif diff --git a/build-config/cppad/include/cppad/core/testvector.hpp b/build-config/cppad/include/cppad/core/testvector.hpp new file mode 100644 index 00000000..ec8bd00c --- /dev/null +++ b/build-config/cppad/include/cppad/core/testvector.hpp @@ -0,0 +1,116 @@ +# ifndef CPPAD_CORE_TESTVECTOR_HPP +# define CPPAD_CORE_TESTVECTOR_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-18 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +/* +$begin testvector$$ +$spell + CppAD + cmake + testvector + cppad + Eigen + ifdef + hpp + std + endif + ublas +$$ + + +$section Using The CppAD Test Vector Template Class$$ + +$head Syntax$$ +$codei%CPPAD_TESTVECTOR(%Scalar%) +%$$ + +$head Choice$$ +The user can choose, during the install procedure, +which template class to use in the examples and tests; see below. +This shows that any +$cref/simple vector/SimpleVector/$$ class can be used in place of +$codei% + CPPAD_TESTVECTOR(%Type%) +%$$ +When writing their own code, +users can choose a specific simple vector they prefer; for example, +$codei% + CppAD::vector<%Type%> +%$$ + + +$head CppAD::vector$$ +If in the $cref/cmake command/cmake/CMake Command/$$ +you specify $cref cppad_testvector$$ to be $code cppad$$, +$code CPPAD_CPPADVECTOR$$ will be true. +In this case, +$code CPPAD_TESTVECTOR$$ is defined by the following source code: +$srccode%cpp% */ +# if CPPAD_CPPADVECTOR +# define CPPAD_TESTVECTOR(Scalar) CppAD::vector< Scalar > +# endif +/* %$$ +In this case CppAD will use its own vector for +many of its examples and tests. + +$head std::vector$$ +If in the cmake command +you specify $icode cppad_testvector$$ to be $code std$$, +$code CPPAD_STDVECTOR$$ will be true. +In this case, +$code CPPAD_TESTVECTOR$$ is defined by the following source code: +$srccode%cpp% */ +# if CPPAD_STDVECTOR +# include +# define CPPAD_TESTVECTOR(Scalar) std::vector< Scalar > +# endif +/* %$$ +In this case CppAD will use standard vector for +many of its examples and tests. + +$head boost::numeric::ublas::vector$$ +If in the cmake command +you specify $icode cppad_testvector$$ to be $code boost$$, +$code CPPAD_BOOSTVECTOR$$ will be true. +In this case, +$code CPPAD_TESTVECTOR$$ is defined by the following source code: +$srccode%cpp% */ +# if CPPAD_BOOSTVECTOR +# include +# define CPPAD_TESTVECTOR(Scalar) boost::numeric::ublas::vector< Scalar > +# endif +/* %$$ +In this case CppAD will use this boost vector for +many of its examples and tests. + +$head CppAD::eigen_vector$$ +If in the cmake command +you specify $icode cppad_testvector$$ to be $code eigen$$, +$code CPPAD_EIGENVECTOR$$ will be true. +In this case, +$code CPPAD_TESTVECTOR$$ is defined by the following source code: +$srccode%cpp% */ +# if CPPAD_EIGENVECTOR +# include +# define CPPAD_TESTVECTOR(Scalar) CppAD::eigen_vector< Scalar > +# endif +/* %$$ +see $cref/eigen_vector/cppad_eigen.hpp/eigen_vector/$$. +In this case CppAD will use the Eigen vector +for many of its examples and tests. + +$end +------------------------------------------------------------------------ +*/ + +# endif diff --git a/build-config/cppad/include/cppad/core/unary_minus.hpp b/build-config/cppad/include/cppad/core/unary_minus.hpp new file mode 100644 index 00000000..5fa689d0 --- /dev/null +++ b/build-config/cppad/include/cppad/core/unary_minus.hpp @@ -0,0 +1,100 @@ +# ifndef CPPAD_CORE_UNARY_MINUS_HPP +# define CPPAD_CORE_UNARY_MINUS_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-18 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +/* +$begin UnaryMinus$$ +$spell + Vec + const + inline +$$ + + +$section AD Unary Minus Operator$$ + +$head Syntax$$ + +$icode%y% = - %x%$$ + + +$head Purpose$$ +Computes the negative of $icode x$$. + +$head Base$$ +The operation in the syntax above must be supported for the case where +the operand is a $code const$$ $icode Base$$ object. + +$head x$$ +The operand $icode x$$ has one of the following prototypes +$codei% + const AD<%Base%> &%x% + const VecAD<%Base%>::reference &%x% +%$$ + +$head y$$ +The result $icode y$$ has type +$codei% + AD<%Base%> %y% +%$$ +It is equal to the negative of the operand $icode x$$. + +$head Operation Sequence$$ +This is an AD of $icode Base$$ +$cref/atomic operation/glossary/Operation/Atomic/$$ +and hence is part of the current +AD of $icode Base$$ +$cref/operation sequence/glossary/Operation/Sequence/$$. + +$head Derivative$$ +If $latex f$$ is a +$cref/Base function/glossary/Base Function/$$, +$latex \[ + \D{[ - f(x) ]}{x} = - \D{f(x)}{x} +\] $$ + +$head Example$$ +$children% + example/general/unary_minus.cpp +%$$ +The file +$cref unary_minus.cpp$$ +contains an example and test of this operation. + +$end +------------------------------------------------------------------------------- +*/ + +// BEGIN CppAD namespace +namespace CppAD { + +// Broken g++ compiler inhibits declaring unary minus a member or friend +template +AD AD::operator - (void) const +{ // 2DO: make a more efficient by adding unary minus to op_code.h (some day) + // + AD result(0); + result -= *this; + return result; +} + + +template +AD operator - (const VecAD_reference &right) +{ return - right.ADBase(); } + +} +// END CppAD namespace + + +# endif diff --git a/build-config/cppad/include/cppad/core/unary_plus.hpp b/build-config/cppad/include/cppad/core/unary_plus.hpp new file mode 100644 index 00000000..2dfb47cd --- /dev/null +++ b/build-config/cppad/include/cppad/core/unary_plus.hpp @@ -0,0 +1,97 @@ +# ifndef CPPAD_CORE_UNARY_PLUS_HPP +# define CPPAD_CORE_UNARY_PLUS_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-17 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +/* +$begin UnaryPlus$$ +$spell + Vec + const + inline +$$ + + +$section AD Unary Plus Operator$$ + +$head Syntax$$ + +$icode%y% = + %x%$$ + + +$head Purpose$$ +Performs the unary plus operation +(the result $icode y$$ is equal to the operand $icode x$$). + + +$head x$$ +The operand $icode x$$ has one of the following prototypes +$codei% + const AD<%Base%> &%x% + const VecAD<%Base%>::reference &%x% +%$$ + +$head y$$ +The result $icode y$$ has type +$codei% + AD<%Base%> %y% +%$$ +It is equal to the operand $icode x$$. + +$head Operation Sequence$$ +This is an AD of $icode Base$$ +$cref/atomic operation/glossary/Operation/Atomic/$$ +and hence is part of the current +AD of $icode Base$$ +$cref/operation sequence/glossary/Operation/Sequence/$$. + +$head Derivative$$ +If $latex f$$ is a +$cref/Base function/glossary/Base Function/$$, +$latex \[ + \D{[ + f(x) ]}{x} = \D{f(x)}{x} +\] $$ + + + +$head Example$$ +$children% + example/general/unary_plus.cpp +%$$ +The file +$cref unary_plus.cpp$$ +contains an example and test of this operation. + +$end +------------------------------------------------------------------------------- +*/ + +// BEGIN CppAD namespace +namespace CppAD { + +template +AD AD::operator + (void) const +{ AD result(*this); + + return result; +} + + +template +AD operator + (const VecAD_reference &right) +{ return right.ADBase(); } + +} +// END CppAD namespace + + +# endif diff --git a/build-config/cppad/include/cppad/core/undef.hpp b/build-config/cppad/include/cppad/core/undef.hpp new file mode 100644 index 00000000..f7f8f276 --- /dev/null +++ b/build-config/cppad/include/cppad/core/undef.hpp @@ -0,0 +1,100 @@ +# ifndef CPPAD_CORE_UNDEF_HPP +# define CPPAD_CORE_UNDEF_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +/* +---------------------------------------------------------------------------- +Preprecessor definitions that presist after cppad/cppad.hpp is included. +These are part of the user API with some exceptions that are used +by the CppAD examples and tests. + +# undef CPPAD_ASSERT_FIRST_CALL_NOT_PARALLEL used by CPPAD_USER_ATOMIC +# undef CPPAD_ASSERT_KNOWN used by cppad_ipopt +# undef CPPAD_ASSERT_UNKNOWN used by cppad_ipopt +# undef CPPAD_HASH_TABLE_SIZE used by test_more/optimize.cpp +# undef EIGEN_MATRIXBASE_PLUGIN example use of Eigen with CppAD +# undef CPPAD_HAS_COLPACK used by speed/cppad/sparse_*.cpp + +# undef CPPAD_BOOL_BINARY in user api +# undef CPPAD_BOOL_UNARY in user api +# undef CPPAD_DEBUG_AND_RELEASE in user api +# undef CPPAD_DISCRETE_FUNCTION in user api +# undef CPPAD_EIGENVECTOR in user api +# undef CPPAD_MAX_NUM_THREADS in user api +# undef CPPAD_NUMERIC_LIMITS in user api +# undef CPPAD_NULL in user api +# undef CPPAD_PACKAGE_STRING in user api +# undef CPPAD_STANDARD_MATH_UNARY in user api +# undef CPPAD_TAPE_ADDR_TYPE in user api +# undef CPPAD_TAPE_ID_TYPE in user api +# undef CPPAD_TESTVECTOR in user api +# undef CPPAD_TO_STRING in user api +# undef CPPAD_USE_CPLUSPLUS_2011 in user api + +# undef CPPAD_TRACK_COUNT in deprecated api +# undef CPPAD_TRACK_DEL_VEC in deprecated api +# undef CPPAD_TRACK_EXTEND in deprecated api +# undef CPPAD_TRACK_NEW_VEC in deprecated api +# undef CPPAD_USER_ATOMIC in deprecated api + +# undef CPPAD_TEST_VECTOR deprecated verssion of CPPAD_TESTVECTOR +# undef CppADCreateBinaryBool deprecated version of CPPAD_BOOL_BINARY +# undef CppADCreateDiscrete deprecated version of CPPAD_DISCRETE_FUNCTION +# undef CppADCreateUnaryBool deprecated version of CPPAD_BOOL_UNARY +# undef CppADTrackCount deprecated version of CPPAD_TRACK_COUNT +# undef CppADTrackDelVec deprecated version of CPPAD_TRACK_DEL_VEC +# undef CppADTrackExtend deprecated version of CPPAD_TRACK_EXTEND +# undef CppADTrackNewVec deprecated version of CPPAD_TRACK_NEW_VEC +# undef CppADvector deprecated version of CPPAD_TEST_VECTOR + +// for conditional testing when implicit conversion is not present +# undef CPPAD_DEPRECATED +----------------------------------------------------------------------------- +*/ +// Preprecessor definitions that do not presist. None of these are in the +// user API. +# undef CPPAD_ASSERT_NARG_NRES +# undef CPPAD_AZMUL +# undef CPPAD_BOOSTVECTOR +# undef CPPAD_COMPILER_HAS_CONVERSION_WARN +# undef CPPAD_COND_EXP +# undef CPPAD_COND_EXP_BASE_REL +# undef CPPAD_COND_EXP_REL +# undef CPPAD_CPPADVECTOR +# undef CPPAD_FOLD_AD_VALUED_BINARY_OPERATOR +# undef CPPAD_FOLD_ASSIGNMENT_OPERATOR +# undef CPPAD_FOLD_BOOL_VALUED_BINARY_OPERATOR +# undef CPPAD_HAS_ADOLC +# undef CPPAD_HAS_EIGEN +# undef CPPAD_HAS_GETTIMEOFDAY +# undef CPPAD_HAS_IPOPT +# undef CPPAD_HAS_MKSTEMP +# undef CPPAD_HAS_TMPNAM_S +# undef CPPAD_INLINE_FRIEND_TEMPLATE_FUNCTION +# undef CPPAD_LIB_EXPORT +# undef CPPAD_MAX_NUM_CAPACITY +# undef CPPAD_MIN_DOUBLE_CAPACITY +# undef CPPAD_NDEBUG_NOEXCEPT +# undef CPPAD_NOEXCEPT +# undef CPPAD_STANDARD_MATH_UNARY_AD +# undef CPPAD_STDVECTOR +# undef CPPAD_TRACE_CAPACITY +# undef CPPAD_TRACE_THREAD +# undef CPPAD_TRACK_DEBUG +# undef CPPAD_USER_MACRO +# undef CPPAD_USER_MACRO_ONE +# undef CPPAD_USER_MACRO_TWO +# undef CPPAD_VEC_AD_COMP_ASSIGN +# undef CPPAD_VEC_ENUM_TYPE + +# endif diff --git a/build-config/cppad/include/cppad/core/user_ad.hpp b/build-config/cppad/include/cppad/core/user_ad.hpp new file mode 100644 index 00000000..da41b5c2 --- /dev/null +++ b/build-config/cppad/include/cppad/core/user_ad.hpp @@ -0,0 +1,71 @@ +# ifndef CPPAD_CORE_USER_AD_HPP +# define CPPAD_CORE_USER_AD_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ +/* +--------------------------------------------------------------------------- + +$begin AD$$ +$spell + std + bool + cos + Cpp +$$ + +$section AD Objects$$ + + +$head Purpose$$ +The sections listed below describe the operations +that are available to $cref/AD of Base/glossary/AD of Base/$$ objects. +These objects are used to $cref/tape/glossary/Tape/$$ +an AD of $icode Base$$ +$cref/operation sequence/glossary/Operation/Sequence/$$. +This operation sequence can +be transferred to an $cref ADFun$$ object where it +can be used to evaluate the corresponding +function and derivative values. + +$head Base Type Requirements$$ +The $icode Base$$ requirements are provided by the CppAD package +for the following base types: +$code float$$, +$code double$$, +$code std::complex$$, +$code std::complex$$. +Otherwise, see $cref base_require$$. + + +$childtable% + include/cppad/core/ad_ctor.hpp% + include/cppad/core/ad_assign.hpp% + include/cppad/core/convert.hpp% + include/cppad/core/ad_valued.hpp% + include/cppad/core/bool_valued.hpp% + include/cppad/core/vec_ad/user.omh% + include/cppad/base_require.hpp +%$$ + +$end +--------------------------------------------------------------------------- +*/ + +# include +# include +# include +# include +# include +# include +# include + +# endif diff --git a/build-config/cppad/include/cppad/core/value.hpp b/build-config/cppad/include/cppad/core/value.hpp new file mode 100644 index 00000000..6da7d258 --- /dev/null +++ b/build-config/cppad/include/cppad/core/value.hpp @@ -0,0 +1,95 @@ +# ifndef CPPAD_CORE_VALUE_HPP +# define CPPAD_CORE_VALUE_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-18 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +/* +$begin Value$$ +$spell + const +$$ + + + +$section Convert From an AD Type to its Base Type$$ + +$head Syntax$$ +$icode%b% = Value(%x%)%$$ + +$head See Also$$ +$cref var2par$$ + + +$head Purpose$$ +Converts from an AD type to the corresponding +$cref/base type/glossary/Base Type/$$. + +$head x$$ +The argument $icode x$$ has prototype +$codei% + const AD<%Base%> &%x% +%$$ + +$head b$$ +The return value $icode b$$ has prototype +$codei% + %Base% %b% +%$$ + +$head Operation Sequence$$ +The result of this operation is not an +$cref/AD of Base/glossary/AD of Base/$$ object. +Thus it will not be recorded as part of an +AD of $icode Base$$ +$cref/operation sequence/glossary/Operation/Sequence/$$. + +$head Restriction$$ +The argument $icode x$$ must not be a +$cref/variable/glossary/Variable/$$ or +$cref/dynamic/glossary/Parameter/Dynamic/$$ parameter +because its dependency information +would not be included in the $code Value$$ result $icode b$$. + +$head Example$$ +$children% + example/general/value.cpp +%$$ +The file +$cref value.cpp$$ +contains an example and test of this operation. + +$end +------------------------------------------------------------------------------- +*/ + +// BEGIN CppAD namespace +namespace CppAD { + +template +CPPAD_INLINE_FRIEND_TEMPLATE_FUNCTION +Base Value(const AD &x) +{ Base result; + // + CPPAD_ASSERT_KNOWN( + ! ( Variable(x) | Dynamic(x) ) , + "Value: argument is a variable or dynamic parameter" + ); + // + result = x.value_; + return result; +} + +} +// END CppAD namespace + + +# endif diff --git a/build-config/cppad/include/cppad/core/var2par.hpp b/build-config/cppad/include/cppad/core/var2par.hpp new file mode 100644 index 00000000..83074f2c --- /dev/null +++ b/build-config/cppad/include/cppad/core/var2par.hpp @@ -0,0 +1,88 @@ +# ifndef CPPAD_CORE_VAR2PAR_HPP +# define CPPAD_CORE_VAR2PAR_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-18 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +/* +------------------------------------------------------------------------------ + +$begin Var2Par$$ +$spell + var + const +$$ + + +$section Convert an AD Variable to a Parameter$$ + +$head Syntax$$ +$icode%y% = Var2Par(%x%)%$$ + +$head See Also$$ +$cref value$$ + +$head Purpose$$ +Returns a +$cref/parameter/glossary/Parameter/$$ $icode y$$ +with the same value as the +$cref/variable/glossary/Variable/$$ $icode x$$. + +$head x$$ +The argument $icode x$$ has prototype +$codei% + const AD<%Base%> &x +%$$ +The argument $icode x$$ may be a variable, parameter, or dynamic parameter. + + +$head y$$ +The result $icode y$$ has prototype +$codei% + AD<%Base%> &y +%$$ +The return value $icode y$$ will be a parameter. + + +$head Example$$ +$children% + example/general/var2par.cpp +%$$ +The file +$cref var2par.cpp$$ +contains an example and test of this operation. + +$end +------------------------------------------------------------------------------ +*/ + +// BEGIN CppAD namespace +namespace CppAD { + +template +CPPAD_INLINE_FRIEND_TEMPLATE_FUNCTION +AD Var2Par(const AD &x) +{ AD y(x.value_); + return y; +} + + +template +CPPAD_INLINE_FRIEND_TEMPLATE_FUNCTION +AD Var2Par(const VecAD_reference &x) +{ AD y(x.ADBase()); + y.id_ = 0; +} + + +} // END CppAD namespace + +# endif diff --git a/build-config/cppad/include/cppad/core/vec_ad/user.omh b/build-config/cppad/include/cppad/core/vec_ad/user.omh new file mode 100644 index 00000000..796f15dc --- /dev/null +++ b/build-config/cppad/include/cppad/core/vec_ad/user.omh @@ -0,0 +1,306 @@ +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ +/* +$begin VecAD$$ +$spell + cppad.hpp + CondExpGt + grep + Ld + vp + Lu + wc + op + Ldp + Ldv + Taylor + VecAD + const + Cpp + ind +$$ + + +$section AD Vectors that Record Index Operations$$ + + +$head Syntax$$ +$codei%VecAD<%Base%> %vec%(%n%)%$$ +$pre +$$ +$icode%vec%.size()%$$ +$pre +$$ +$icode%base% = %vec%[%i%]%$$ +$pre +$$ +$icode%abase% = %vec%[%ind%] +%$$ +$icode%vec%[%ind%] = %right% +%$$ +$icode%left% = %vec%[%ind%] +%$$ + +$head Purpose$$ +If either $icode vec$$ or $icode ind$$ is a +$cref/variable/glossary/Variable/$$ or +$cref/dynamic parameter/glossary/Parameter/Dynamic/$$, +the indexing operation +$codei% + %vec%[%ind%] +%$$ +is recorded in the corresponding $codei%AD<%Base%>%$$ +$cref/operation sequence/glossary/Operation/Sequence/$$ and +included in the corresponding $cref ADFun$$ object $icode f$$. +Such an index can change each time +zero order $cref/f.Forward/Forward/$$ is used; i.e., +each time $icode f$$ is evaluated with new value for the +$cref/independent variables/glossary/Tape/Independent Variable/$$. +Note that the value of $icode%vec%[%ind%]%$$ +depends on the value of $icode ind$$ +in a discrete fashion and CppAD computes its partial derivative with +respect to $icode ind$$ as zero. + +$head Alternatives$$ +If only the values in $icode vec$$, +and not the indices $icode ind$$, +depend on the independent variables, +a $cref SimpleVector$$ with elements of type $codei%AD<%Base%>%$$ +would be more efficient than using $codei%VecAD<%Base%>%$$. +If only the indices, and not the values in the vector, +depend on the independent variables, +a $cref Discrete$$ functions would be a much more efficient. + +$head Efficiency$$ +If one uses $code VecAD$$ vector where one could use a simple vector, +the $cref sparsity_pattern$$ will be less efficient +because the dependence on different elements cannot be separated. +In addition, $code VecAD$$ objects that only depend on dynamic parameters +are treated as if they were variables making sparsity patterns +even less efficient (have more possibly non-zero values than necessary); +see $cref/VecAD vectors/wish_list/Dynamic Parameters/VecAD Vectors/$$ +under dynamic parameters in the wish list. + +$head VecAD::reference$$ +The expression $icode%vec%[%ind%]%$$ has prototype +$codei% + VecAD<%Base%>::reference %vec%[%ind%] +%$$ +which is like the $codei%AD<%Base%>%$$ type +with some notable exceptions: + +$subhead Exceptions$$ + +$list number$$ +This object cannot be used with the +$cref Value$$ function to compute the corresponding $icode Base$$ value. +In some cases, the syntax +$codei% + %vec%[%i%] +%$$ +can be used to obtain the corresponding $icode Base$$ value; see below. + +$lnext +This object cannot be used as the left hand side in a +with a $cref/compound assignment/compound_assign/$$; i.e., +$code +=$$, +$code -=$$, +$code *=$$, or +$code /=$$. +For example, the following syntax is not valid: +$codei% + %vec%[%ind%] += %z%; +%$$ +no matter what the types of $icode z$$. + +$lnext +Assignment to $codei%vec%[%ind%]%$$ returns a $code void$$. +For example, the following syntax is not valid: +$codei% + %z% = %vec%[%ind%] = %u%; +%$$ +no matter what the types of $icode z$$, and $icode u$$. + +$lnext +A $icode%vec%[%ind%]%$$ object cannot appear in a $cref CondExp$$; +For example, the following syntax is not valid: +$codei% + CondExpGt(%vec%[%ind%], %u%, %v%, %w%) +%$$ +no matter what the types of $icode u$$, $icode v$$, and $icode w$$. + +$lnext +A $icode%vec%[%ind%]%$$ object should not be used with the +$code Constant$$, $code Dynamic$$, $code Parameter$$, and $code Variable$$ +functions (see $cref con_dyn_var$$). +The entire vector $icode vec$$ should be used instead. + +$lnext +A $code VecAD$$ vector +cannot be passed to $code Independent$$ function. + +$lend + +$head Constructor$$ + +$subhead vec$$ +The syntax +$codei% + VecAD<%Base%> %vec%(%n%) +%$$ +creates an $code VecAD$$ object $icode vec$$ with +$icode n$$ elements. +The initial value of the elements of $icode vec$$ is unspecified. + +$subhead n$$ +The argument $icode n$$ has prototype +$codei% + size_t %n% +%$$ + +$head size$$ +The syntax +$codei% + %vec%.size() +%$$ +returns the number of elements in the vector $icode vec$$; +i.e., the value of $icode n$$ when it was constructed. + +$head Base Indexing$$ +We refer to the syntax +$codei% + %base% = %vec%[%i%] +%$$ +as base indexing of a $code VecAD$$ object. +This indexing is only valid if the vector $icode vec$$ is a +$cref/constant/con_dyn_var/Constant/$$; i.e., +it does not depend on the independent variables. + +$subhead i$$ +The operand $icode i$$ has prototype +$codei% + size_t %i% +%$$ +and must be less than $icode n$$; i.e., less than +the number of elements in $icode vec$$. + +$subhead base$$ +The result $icode base$$ has prototype +$codei% + %Base%& %base% +%$$ +i.e., it is a reference to the $th i$$ element in the vector $icode vec$$. +It can be used to change the element value; +for example, +$codei% + %vec%[%i%] = %b% +%$$ +is valid where $icode b$$ is a $icode Base$$ object. +The reference $icode base$$ is no longer valid once the +$icode vec$$ changes in any way; i.e., has another assignment. + +$head AD Indexing$$ +We refer to the syntax +$codei% + %vec%[%ind%] +%$$ +as AD indexing of a $code VecAD$$ object. + +$subhead ind$$ +The argument $icode ind$$ has prototype +$codei% + const AD<%Base%>& %ind% +%$$ +The value of $icode ind$$ must be greater than or equal zero +and less than $icode n$$; i.e., less than +the number of elements in $icode vec$$. + +$subhead result$$ +The resulting expression has prototype +$codei% + VecAD<%Base%>::reference %vec%[%ind%] +%$$ +This objects operations are recorded as part of the $codei%AD<%Base%>%$$ +$cref/operation sequence/glossary/Operation/Sequence/$$. +It acts like a reference to the +element with index $codei%floor(%ind%)%$$ in the vector $icode vec$$; +($codei%floor(%ind%)%$$ is +the greatest integer less than or equal $icode ind$$). + +$subhead right$$ +Is the right hand side of the assignment statement +and specifies the new value for the corresponding element of $icode vec$$. +It has one of the following prototypes: +$codei% + int %% %right% + const %Base%& %right% + const AD<%Base%>& %right% + const VecAD_reverence<%Base%>& %right% +%$$ + +$subhead left$$ +Is the left hand side of the assignment statement +is the current value for the corresponding element of $icode vec$$. +It has the following prototype: +$codei% + const AD<%Base%>& %left% +%$$ + +$head Example$$ +$children% + example/general/vec_ad.cpp +%$$ +The file +$cref vec_ad.cpp$$ +contains an example and test using $code VecAD$$ vectors. + + +$head Speed and Memory$$ +The $cref VecAD$$ vector type is inefficient because every +time an element of a vector is accessed, a new CppAD +$cref/variable/glossary/Variable/$$ is created on the tape +using either the $code Ldp$$ or $code Ldv$$ operation +(unless all of the elements of the vector are +$cref/parameters/glossary/Parameter/$$). +The effect of this can be seen by executing the following steps: + +$list number$$ +In the file $code cppad/local/forward1sweep.h$$, +change the definition of $code CPPAD_FORWARD1SWEEP_TRACE$$ to +$codep + # define CPPAD_FORWARD1SWEEP_TRACE 1 +$$ +$lnext +In the $code Example$$ directory, execute the command +$codep + ./test_one.sh lu_vec_ad_ok.cpp lu_vec_ad.cpp -DNDEBUG > lu_vec_ad_ok.log +$$ +This will write a trace of all the forward tape operations, +for the test case $cref lu_vec_ad_ok.cpp$$, +to the file $code lu_vec_ad_ok.log$$. +$lnext +In the $code Example$$ directory execute the commands +$codep + grep "op=" lu_vec_ad_ok.log | wc -l + grep "op=Ld[vp]" lu_vec_ad_ok.log | wc -l + grep "op=St[vp][vp]" lu_vec_ad_ok.log | wc -l +$$ +The first command counts the number of operators in the tracing, +the second counts the number of VecAD load operations, +and the third counts the number of VecAD store operations. +(For CppAD version 05-11-20 these counts were 956, 348, and 118 +respectively.) +$lend + +$end +------------------------------------------------------------------------ +*/ diff --git a/build-config/cppad/include/cppad/core/vec_ad/vec_ad.hpp b/build-config/cppad/include/cppad/core/vec_ad/vec_ad.hpp new file mode 100644 index 00000000..29f1a065 --- /dev/null +++ b/build-config/cppad/include/cppad/core/vec_ad/vec_ad.hpp @@ -0,0 +1,642 @@ +# ifndef CPPAD_CORE_VEC_AD_VEC_AD_HPP +# define CPPAD_CORE_VEC_AD_VEC_AD_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ +# include +namespace CppAD { // BEGIN_CPPAD_NAMESPACE +/* + ------------------------------------------------------------------------------ +$begin vec_ad_comp_assign$$ +$spell + Vec + op +$$ +$section VecAD: Prints Error Message If A Compound Assignment Is Used$$ + +$head Syntax$$ +$codei%CPPAD_VEC_AD_COMP_ASSIGN(%cop%) +%$$ +$icode%ref cop right +%$$ + +$head CPPAD_VEC_AD_COMP_ASSIGN$$ +This macro defines the compound assignment operator $icode cop$$ +for a VecAD reference element to be an error with an error message. + +$head cop$$ +Is one of the following computed assignment operators: ++= , -= , *= , /=. + +$head ref$$ +is the VecAD reference. + +$head right$$ +is the right hand side for the compound assignment. + +$head Source$$ +$srccode%hpp% */ +# define CPPAD_VEC_AD_COMP_ASSIGN(cop) \ +VecAD_reference& operator cop (const VecAD_reference &right) \ +{ CPPAD_ASSERT_KNOWN(false, \ + "Can't use VecAD::reference on left side of " #cop \ + ); \ + return *this; \ +} \ +VecAD_reference& operator cop (const AD &right) \ +{ CPPAD_ASSERT_KNOWN(false, \ + "Can't use VecAD::reference on left side of " #cop \ + ); \ + return *this; \ +} \ +VecAD_reference& operator cop (const Base &right) \ +{ CPPAD_ASSERT_KNOWN(false, \ + "Can't use VecAD::reference on left side of " #cop \ + ); \ + return *this; \ +} \ +VecAD_reference& operator cop (int right) \ +{ CPPAD_ASSERT_KNOWN(false, \ + "Can't use VecAD::reference on left side of " #cop \ + ); \ + return *this; \ +} +/* %$$ +$end +------------------------------------------------------------------------------ +$begin vec_ad_reference$$ +$spell + Vec + ind + const +$$ +$section VecAD Element Reference Class$$ + +$head Syntax$$ +$codei%VecAD_reverence %ref%(%vec%, %ind%) +%$$ +$icode%ref% = %right% +%$$ +$icode ref cop right +%$$ +$icode%element% = %ref%.ADBase() +%$$ + +$head vec_$$ +This private data is a reference to $icode vec$$ in the constructor. + +$head ind_$$ +This private data is a copy of $icode ind$$ in the constructor. + +$head Base$$ +Elements of this reference class act like an +$codei%AD<%Base%>%$$ object (in a restricted sense), +in addition they track (on the tape) the index $icode ind$$ they correspond to. + +$head vec$$ +is the vector containing the element being referenced and has prototype +$codei% + VecAD<%Base%> %vec% +%$$ + +$head ind$$ +is the index of the element being referenced and has prototype +$codei% + const AD<%Base%>& ind +%$$ +If $icode%ind%.tape_id_%$$ matches a current recording, +so does $icode%vec%.tape_id_%$$ and +the $cref/AD type/atomic_three/ad_type/$$ corresponding to $icode vec$$ +includes this indexing operation; i.e., it is greater than or equal +the AD type corresponding to $icode ind$$. + +$head right$$ +Is the right hand side of the assignment statement and has one +of the following prototypes: +$codei% + int %% %right% + const %Base%& %right% + const AD<%Base%>& %right% + const VecAD_reverence<%Base%>& %right% +%$$ + +$head cop$$ +Is one of the following computed assignment operators: ++= , -= , *= , /=. +All of these operations report an error. + +$head element$$ +Is a copy of the element corresponding to the reference $icode ref$$ +and has prototype: +$codei% + AD<%Base%> %element% +%$$ + +$end +*/ +template +class VecAD_reference { + friend bool Constant (const VecAD &vec); + friend bool Parameter (const VecAD &vec); + friend bool Dynamic (const VecAD &vec); + friend bool Variable (const VecAD &vec); + friend class VecAD; + friend class local::ADTape; + +private: + VecAD& vec_; // reverence to vector + AD ind_; // index for this element +public: + VecAD_reference(VecAD& vec, const AD& ind) + : vec_( vec ) , ind_(ind) + { } + + // assignment operators + void operator = (const VecAD_reference &right); + void operator = (const AD &right); + void operator = (const Base &right); + void operator = (int right); + + // compound assignments + CPPAD_VEC_AD_COMP_ASSIGN( += ) + CPPAD_VEC_AD_COMP_ASSIGN( -= ) + CPPAD_VEC_AD_COMP_ASSIGN( *= ) + CPPAD_VEC_AD_COMP_ASSIGN( /= ) + + + /// Conversion from VecAD_reference to AD. + /// puts the correspond vecad load instruction in the tape. + AD ADBase(void) const + { // start with default construtor (hence dynamic_ is false). + AD result; + + size_t i = static_cast( Integer(ind_) ); + CPPAD_ASSERT_UNKNOWN( i < vec_.length_ ); + + // AD value corresponding to this element + result.value_ = vec_.data_[i]; + CPPAD_ASSERT_UNKNOWN( Constant(result) ); + + // check if there is a recording in progress + local::ADTape* tape = AD::tape_ptr(); + if( tape == nullptr ) + return result; + + // tape_id cannot match the default value zero + CPPAD_ASSERT_UNKNOWN( tape->id_ > 0 ); + + // check if vector, index match tape_id + bool match_vec = vec_.tape_id_ == tape->id_; + bool match_ind = ind_.tape_id_ == tape->id_; + + // check if vector, index are dynamic parmaerters + CPPAD_ASSERT_UNKNOWN( vec_.ad_type_ != dynamic_enum); + bool dyn_ind = match_ind & (ind_.ad_type_ == dynamic_enum); + + // check if vector, index are variables + bool var_vec = match_vec & (vec_.ad_type_ == variable_enum); + bool var_ind = match_ind & (ind_.ad_type_ == variable_enum); + + // check if vector, index are constants + bool con_vec = ! var_vec; + bool con_ind = ! ( dyn_ind | var_ind); + if( con_vec & con_ind ) + return result; +# ifndef NDEBUG + if( match_vec & match_ind ) CPPAD_ASSERT_KNOWN( + vec_.tape_id_ == ind_.tape_id_ , + "VecAD: vector and index are dynamic parameters or variables " + "on different treads." + ); +# endif + // parameter or variable index corresponding to ind_ + addr_t ind_taddr = ind_.taddr_; + if( con_ind ) + ind_taddr = tape->Rec_.put_con_par(ind_.value_); + + // index corresponding to this element + CPPAD_ASSERT_UNKNOWN( var_vec ); + { CPPAD_ASSERT_UNKNOWN( vec_.offset_ > 0 ); + size_t load_op_index = tape->Rec_.num_var_load_rec(); + // + if( var_ind ) + { CPPAD_ASSERT_UNKNOWN( local::NumRes(local::LdvOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( local::NumArg(local::LdvOp) == 3 ); + + // put operand addresses in tape, ind_ is a variable + result.taddr_ = tape->Rec_.PutLoadOp(local::LdvOp); + tape->Rec_.PutArg( + (addr_t) vec_.offset_, ind_taddr, (addr_t) load_op_index + ); + + // change result to variable for this load + result.tape_id_ = tape->id_; + result.ad_type_ = variable_enum; + } + else + { CPPAD_ASSERT_UNKNOWN( local::NumRes(local::LdpOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( local::NumArg(local::LdpOp) == 3 ); + CPPAD_ASSERT_UNKNOWN( con_ind | dyn_ind ); + + + // put operand addresses in tape + tape->Rec_.PutArg( + (addr_t) vec_.offset_, ind_taddr, (addr_t) load_op_index + ); + // put operator in the tape, ind_ is a parameter + result.taddr_ = tape->Rec_.PutLoadOp(local::LdpOp); + + // change result to variable for this load + result.tape_id_ = tape->id_; + result.ad_type_ = variable_enum; + } + } + return result; + } +}; +// --------------------------------------------------------------------------- +/*! +$begin vec_ad_class$$ +$spell + Vec + ind + enum + taddr +$$ +$section VecAD Class Objects$$ + +$head Syntax$$ +$codei%VecAD %empty%, %vec%(%length%) +%$$ +$icode%length% = %vec%.size() +%$$ +$icode%b% = %vec%[%i%] +%$$ +$icode%ref% = %vec%[%ind%] +%$$ + +$head length$$ +is the size of the vector and has prototype +$codei% + size_t %length% +%$$ + +$head Private Members$$ +$srcthisfile% + 0%// BEGIN_VECAD_PRIVATE_DATA%// END_VECAD_PRIVATE_DATA%1 +%$$ + +$subhead length_$$ +is a copy of $icode length$$. + +$subhead data_$$ +This vector has size $icode length$$ and +contains the value of the elements of the vector. + +$subhead taddr_$$ +This vector has size $icode length$$. +If $code tape_id_$$ matches the current recording +and $code ad_type_$$ is $code dynamic_enum$$, +$codei%taddr[%i%]%$$ is the parameter index for the corresponding element. + +$subhead offset_$$ +If $icode tape_id_$$ is the current tape, +$icode offset_$$ is the index of the first element of this vector +in the combined vector that contains all the VecAD elements for this recording. +$icode%offset_%-1%$$ is the index of the size of this vector +in the combined vector. + +$subhead tape_id_$$ +is the tape currently associated with this vector. + +$subhead ad_type_$$ +is the $cref/ad_type/atomic_three/ad_type/$$ corresponding to this +vector. + +$head i$$ +is a $code size_t$$ value less than $icode length$$. +This form of indexing can only be used when $icode vec$$ is a +constant parameter; i.e., its operations are not being recorded. + +$head b$$ +is a reference to the $icode Base$$ value +for the $th i$$ element of the vector. + +$head ind$$ +is a $codei%AD<%Base%>%$$ value less than $icode length$$. +This form of indexing gets recorded and the value of the index +can change. + +$head ref$$ +is a reference to the $codei%AD<%Base%>%$$ value +for the $th x$$ element of the vector. +If the vector is a parameter and the index is a variable, +the vector is changed to be a variable. + +$end +*/ +template +class VecAD { + friend bool Constant (const VecAD &vec); + friend bool Parameter (const VecAD &vec); + friend bool Dynamic (const VecAD &vec); + friend bool Variable (const VecAD &vec); + friend class local::ADTape; + friend class VecAD_reference; + + friend std::ostream& operator << + (std::ostream &os, const VecAD &vec_); +private: +// BEGIN_VECAD_PRIVATE_DATA + const size_t length_; + local::pod_vector_maybe data_; + local::pod_vector taddr_; + tape_id_t tape_id_; + addr_t offset_; + ad_type_enum ad_type_; +// END_VECAD_PRIVATE_DATA +public: + // declare the user's view of this type here + typedef VecAD_reference reference; + + // default constructor + // initialize tape_id_ same as for default constructor; see default.hpp + VecAD(void) + : length_(0), tape_id_(0), offset_(0), ad_type_(constant_enum) + { CPPAD_ASSERT_UNKNOWN( Constant(*this) ); } + + // sizing constructor + // initialize tape_id_ same as for constants; see ad_copy.hpp + VecAD(size_t length) + : length_(length), tape_id_(0), offset_(0), ad_type_(constant_enum) + { if( length_ > 0 ) + { size_t i; + Base zero(0); + data_.extend(length_); + taddr_.extend(length_); + + // Initialize data to zero so all have same value. + // This uses less memory and avoids a valgrind error + // during TapeRec::PutPar + for(i = 0; i < length_; i++) + { data_[i] = zero; + taddr_[i] = 0; + } + } + CPPAD_ASSERT_UNKNOWN( Constant(*this) ); + } + + // destructor + ~VecAD(void) + { } + + // number of elements in the vector + size_t size(void) + { return length_; } + + // element access (not taped) + Base& operator[](size_t i) + { + CPPAD_ASSERT_KNOWN( + Constant(*this), + "VecAD: cannot use size_t indexing because this" + " VecAD vector is not a constant paraameter." + ); + CPPAD_ASSERT_KNOWN( + i < length_, + "VecAD: element index is >= vector length" + ); + + return data_[i]; + } + + // element access (taped) + VecAD_reference operator[](const AD &ind) + { + CPPAD_ASSERT_KNOWN( + 0 <= Integer(ind), + "VecAD: element index is less than zero" + ); + CPPAD_ASSERT_KNOWN( + static_cast( Integer(ind) ) < length_, + "VecAD: element index is >= vector length" + ); + + // check if there is a recording in progress + local::ADTape* tape = AD::tape_ptr(); + if( tape == nullptr ) + return VecAD_reference(*this, ind); + + // tape_id cannot match the defautl value zero + CPPAD_ASSERT_UNKNOWN( tape->id_ > 0 ); + + // check if vector, index match tape_id + bool match_vec = tape_id_ == tape->id_; + bool match_ind = ind.tape_id_ == tape->id_; + + // check if vector, index are dynamic parmaerters + CPPAD_ASSERT_UNKNOWN( ad_type_ != dynamic_enum ); + bool dyn_ind = match_ind & (ind.ad_type_ == dynamic_enum); + + // check if vector, index are variables + bool var_vec = match_vec & (ad_type_ == variable_enum); + bool var_ind = match_ind & (ind.ad_type_ == variable_enum); + + // check if vector, index are constants + bool con_vec = ! var_vec; + bool con_ind = ! ( dyn_ind | var_ind); + if( con_vec & con_ind ) + return VecAD_reference(*this, ind); +# ifndef NDEBUG + if( match_vec & match_ind ) CPPAD_ASSERT_KNOWN( + tape_id_ == ind.tape_id_ , + "VecAD: vector and index are dynamic parameters or variables " + "on different treads." + ); +# endif + if( con_vec ) + { // place a copy of vector in tape + for(size_t i = 0; i < length_; ++i) + taddr_[i] = tape->Rec_.put_con_par( data_[i] ); + offset_ = tape->Rec_.put_var_vecad(length_, taddr_); + + // Advance pointer by one so starts at first component of this + // vector; i.e., skip length at begining (so is always > 0) + offset_++; + + // tape_id corresponding to this vector + tape_id_ = ind.tape_id_; + + // VecAD objects go striaght from constants to variables; i.e., + // they never are dynamic parameters. + ad_type_ = variable_enum; + } + CPPAD_ASSERT_UNKNOWN( Variable(*this) ); + return VecAD_reference(*this, ind); + } + +}; +// --------------------------------------------------------------------------- +// ref = right +template +void VecAD_reference::operator=(const AD &right) +{ + // index in vector for this element + size_t index = static_cast( Integer(ind_) ); + CPPAD_ASSERT_UNKNOWN( index < vec_.length_ ); + + // Base part of assignment for this element + vec_.data_[index] = right.value_; + + // check if there is a recording in progress + local::ADTape* tape = AD::tape_ptr(); + if( tape == nullptr ) + return; + + // tape_id cannot match the defautl value zero + tape_id_t tape_id = tape->id_; + CPPAD_ASSERT_UNKNOWN( tape_id > 0 ); + + // check if vector, index, right match tape_id + bool match_vec = vec_.tape_id_ == tape_id; + bool match_ind = ind_.tape_id_ == tape_id; + bool match_right = right.tape_id_ == tape_id; + CPPAD_ASSERT_UNKNOWN( match_vec || ! match_ind ); + + // check if vector, index, right are dynamic parmaerters + CPPAD_ASSERT_UNKNOWN(vec_.ad_type_ != dynamic_enum); + bool dyn_ind = match_ind & (ind_.ad_type_ == dynamic_enum); + bool dyn_right = match_right & (right.ad_type_ == dynamic_enum); + + // check if vector, index, right are variables + bool var_vec = match_vec & (vec_.ad_type_ == variable_enum); + bool var_ind = match_ind & (ind_.ad_type_ == variable_enum); + bool var_right = match_right & (right.ad_type_ == variable_enum); + + // check if vector, index, right are constants + bool con_vec = ! var_vec; + bool con_ind = ! ( dyn_ind | var_ind); + bool con_right = ! ( dyn_right | var_right); + if( con_vec & con_right ) + return; + +# ifndef NDEBUG + if( match_ind ) + { CPPAD_ASSERT_UNKNOWN( ind_.tape_id_ == vec_.tape_id_ ); + CPPAD_ASSERT_UNKNOWN( ind_.ad_type_ <= vec_.ad_type_ ); + } + if( match_vec & match_right ) CPPAD_ASSERT_KNOWN( + vec_.tape_id_ == right.tape_id_ , + "VecAD: vector and element are dynamic parameters or variables " + "on different treads." + ); +# endif + + if( con_vec ) + { CPPAD_ASSERT_UNKNOWN( con_ind ); + + // place a copy of vector in tape + for(size_t i = 0; i < vec_.length_; ++i) + vec_.taddr_[i] = tape->Rec_.put_con_par( vec_.data_[i] ); + vec_.offset_ = tape->Rec_.put_var_vecad(vec_.length_, vec_.taddr_); + + // advance offset from size of vector to first element in vector + (vec_.offset_)++; + + // tape_id corresponding to this vector + vec_.tape_id_ = right.tape_id_; + + // VecAD objects go striaght from constants to variables; i.e., + // they never are dynamic parameters. + vec_.ad_type_ = variable_enum; + } + CPPAD_ASSERT_UNKNOWN( Variable(vec_) ); + CPPAD_ASSERT_UNKNOWN( vec_.offset_ > 0 ); + + // parameter or variable index for ind_ + addr_t ind_taddr = ind_.taddr_; + if( con_ind ) + ind_taddr = tape->Rec_.put_con_par(ind_.value_); + CPPAD_ASSERT_UNKNOWN( ind_taddr > 0 ); + + // parameter or variable index for right + addr_t right_taddr = right.taddr_; + if( con_right ) + right_taddr = tape->Rec_.put_con_par(right.value_); + CPPAD_ASSERT_UNKNOWN( right_taddr > 0 ); + + // record the setting of this array element + if( var_right ) + { // resulting vector is a variable + vec_.ad_type_ = variable_enum; + + // put operator arguments in tape + tape->Rec_.PutArg(vec_.offset_, ind_taddr, right_taddr); + + if( con_ind | dyn_ind) + { CPPAD_ASSERT_UNKNOWN( local::NumArg(local::StpvOp) == 3 ); + CPPAD_ASSERT_UNKNOWN( local::NumRes(local::StpvOp) == 0 ); + + // put operator in the tape, ind_ is parameter, right is variable + tape->Rec_.PutOp(local::StpvOp); + + } + else + { CPPAD_ASSERT_UNKNOWN( var_ind ); + CPPAD_ASSERT_UNKNOWN( local::NumArg(local::StvvOp) == 3 ); + CPPAD_ASSERT_UNKNOWN( local::NumRes(local::StvvOp) == 0 ); + + // put operator in the tape, ind_ is variable, right is variable + tape->Rec_.PutOp(local::StvvOp); + } + } + else + { + // put operator arguments in tape + tape->Rec_.PutArg(vec_.offset_, ind_taddr, right_taddr); + + // record the setting of this array element + if( con_ind | dyn_ind ) + { CPPAD_ASSERT_UNKNOWN( local::NumArg(local::StppOp) == 3 ); + CPPAD_ASSERT_UNKNOWN( local::NumRes(local::StppOp) == 0 ); + + // put operator in the tape, ind_ is parameter, right is parameter + tape->Rec_.PutOp(local::StppOp); + } + else + { CPPAD_ASSERT_UNKNOWN( local::NumArg(local::StvpOp) == 3 ); + CPPAD_ASSERT_UNKNOWN( local::NumRes(local::StvpOp) == 0 ); + + // put operator in the tape, ind_ is variable, right is parameter + tape->Rec_.PutOp(local::StvpOp); + } + } +} +template +void VecAD_reference::operator=(const Base &right) +{ *this = AD(right); } +// +template +void VecAD_reference::operator= +(const VecAD_reference &right) +{ *this = right.ADBase(); } +// +template +void VecAD_reference::operator=(int right) +{ *this = Base(right); } +// --------------------------------------------------------------------------- + +} // END_CPPAD_NAMESPACE + +// preprocessor symbols that are local to this file +# undef CPPAD_VEC_AD_COMP_ASSIGN + +# endif diff --git a/build-config/cppad/include/cppad/core/zdouble.hpp b/build-config/cppad/include/cppad/core/zdouble.hpp new file mode 100644 index 00000000..8c08f71d --- /dev/null +++ b/build-config/cppad/include/cppad/core/zdouble.hpp @@ -0,0 +1,528 @@ +# ifndef CPPAD_CORE_ZDOUBLE_HPP +# define CPPAD_CORE_ZDOUBLE_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ +/* +$begin zdouble$$ +$spell + zdouble + op + bool + inf + CppAD +$$ +$section zdouble: An AD Base Type With Absolute Zero$$ + +$head Deprecated 2015-09-26$$ +Use the function $cref azmul$$ instead. + +$head Absolute Zero$$ +The $code zdouble$$ class acts like the $code double$$ type +with the added property that zero times any value is zero. +This includes zero time $cref nan$$ and zero times infinity. +In addition, zero divided by any value and any value times zero +are also zero. + +$head Syntax$$ + +$subhead Constructor and Assignment$$ +$codei% zdouble z +%$$ +$codei% zdouble z(x) +%$$ +$icode% z1% %op% %x% +%$$ +where $icode x$$ is a $code double$$ or $code zdouble$$ object +and $icode op$$ is $code =$$, $code +=$$, $code -=$$, $code *=$$ +or $code /=-$$. + +$subhead Comparison Operators$$ +$icode% b% = %z% %op% %x% +%$$ +$icode% b% = %x% %op% %z% +%$$ +where $icode b$$ is a $code bool$$ object, +$icode z$$ is a $code zdouble$$ object, +$icode x$$ is a $code double$$ or $code zdouble$$ object, and +$icode op$$ is $code ==$$, $code !=$$, $code <=$$, $code >=$$, +$code <$$ or $code >$$. + +$subhead Arithmetic Operators$$ +$icode% z2% = %z1% %op% %x% +%$$ +$icode% z2% = %x% %op% %z1% +%$$ +where $icode z1$$, $icode z2$$ are $code zdouble$$ objects, +$icode x$$ is a $code double$$ or $code zdouble$$ object, and +$icode op$$ is $code +$$, $code -$$, $code *$$ or $code /$$. + + +$subhead Standard Math$$ +$icode% z2% = %fun%(%z1%) +%$$ +$icode% z3% = pow(%z1%, %z2%) +%$$ +where $icode z1$$, $icode z2$$, $icode z3$$ are $code zdouble$$ objects and +$icode fun$$ is a $cref unary_standard_math$$ function. + +$subhead Nan$$ +There is a specialization of $cref nan$$ so that +$icode% + z2% = nan(%z1%) +%$$ +returns 'not a number' when $icode z1$$ has type $code zdouble$$. +Note that this template function needs to be specialized because +$codei + zdouble(0.0) == zdouble(0.0) / zdouble(0.0) +$$ + + +$head Motivation$$ + +$subhead General$$ +Often during computing (and more so in parallel computing) alternative +values for an expression are computed and one of the alternatives +is chosen using some boolean variable. +This is often represented by +$codei% + %result% = %flag% * %value_if_true% + (1 - %flag%) * %value_if_false% +%$$ +where $icode flag$$ is one for true and zero for false. +This representation does not work for $code double$$ when the value +being multiplied by zero is $code +inf$$, $code -inf$$, or $code nan$$. + +$subhead CppAD$$ +In CppAD one can use +$cref/conditional expressions/CondExp/$$ to achieve the representation +$codei% + %result% = %flag% * %value_if_true% + (1 - %flag%) * %value_if_false% +%$$ +This works fine except when there are +$cref/multiple levels of AD/mul_level/$$; e.g., +when using $codei%AD< AD >%$$. +In this case the corresponding AD function objects have type +$cref/ADFun< AD >/FunConstruct/$$. +When these AD function objects compute derivatives using +$cref reverse$$ mode, the conditional expressions are represented use +zeros to multiply the expression that is not used. +Using $codei%AD< AD >%$$ instead of $code AD< AD >$$ +makes this representation work and fixes the problem. + +$head Base Type Requirements$$ +The type $code zdouble$$ satisfies all of the CppAD +$cref/base type requirements/base_require/$$. + +$end +*/ +# include +# include + +/*! +\file zdouble.hpp +Define a class like double but with an absolute zero. +*/ + +/*! +\def CPPAD_ZDOUBLE_NORMAL_ASSIGN_OPERATOR(op) +Define a compound assignment member operator that functions the same +as corresponding double operator. +*/ +# define CPPAD_ZDOUBLE_NORMAL_ASSIGN_OPERATOR(op) \ + zdouble& operator op (const zdouble& z) \ + { dbl_ op z.dbl_; \ + return *this; \ + } \ + zdouble& operator op (const double& x) \ + { dbl_ op x; \ + return *this; \ + } + +/*! +\def CPPAD_ZDOUBLE_UNARY_OPERATOR(op) +Define a unary compound assignment member operator. +*/ +# define CPPAD_ZDOUBLE_UNARY_OPERATOR(op) \ + zdouble operator op (void) const \ + { return zdouble( op dbl_ ); } + +/*! +# define CPPAD_ZDOUBLE_NORMAL_BINARY_OPERATOR(op) +Define a binary arithmetic member operator that functions the same +as corresponding double operator. +*/ +# define CPPAD_ZDOUBLE_NORMAL_BINARY_OPERATOR(op) \ + zdouble operator op (const zdouble& z) const \ + { return zdouble( dbl_ op z.dbl_ ); } \ + zdouble operator op (const double& x) const \ + { return zdouble( dbl_ op x ); } + +/*! +\def CPPAD_ZDOUBLE_COMPARE_OPERATOR(op) +Define a comparison member operator. +*/ +# define CPPAD_ZDOUBLE_COMPARE_OPERATOR(op) \ + bool operator op (const zdouble& z) const \ + { return dbl_ op z.dbl_; } \ + bool operator op (const double& x) const \ + { return dbl_ op x; } + +/*! +\def CPPAD_ZDOUBLE_OTHER_BINARY_OPERATOR(op) +Define a binary arithmetic operator that is not a member because +the double operand is on the left. +*/ +# define CPPAD_ZDOUBLE_OTHER_BINARY_OPERATOR(op) \ + inline zdouble operator op(const double& x, const zdouble& z) \ + { return zdouble(x) op z; } + +/*! +\def CPPAD_ZDOUBLE_OTHER_COMPARE_OPERATOR(op, op_switch) +Define a comparison operator that is not a member because +the double operand is on the left. +Convert it to the case where the double operand is on the right by +by using op_switch instead of op. +*/ +# define CPPAD_ZDOUBLE_OTHER_COMPARE_OPERATOR(op, op_switch) \ + inline bool operator op(const double& x, const zdouble& z) \ + { return z op_switch x; } + +/*! +\def CPPAD_ZDOUBLE_STD_MATH_FRIEND(fun) +Declare that a standard math function is a friend. +*/ +# define CPPAD_ZDOUBLE_STD_MATH_FRIEND(fun) \ + friend zdouble fun(const zdouble& z); +/*! +\def CPPAD_ZDOUBLE_STD_MATH(fun) +Define a standard math function. +*/ +# define CPPAD_ZDOUBLE_STD_MATH(fun) \ + inline zdouble fun(const zdouble& z ) \ + { return zdouble( std::fun(z.dbl_) ); } + +namespace CppAD { // CPPAD_BEGIN_NAMESPACDE + + +/*! +Class that is like double, except that it has an absolute zero. +*/ +class zdouble { + /*! + For zdouble objects z1, z2, and std::ostream os, + declare the following friends: + \code + os << z1 + Integer(z1) + fabs(z1) + pow(z1, z2) + fabs_geq(z1, z2) + fun(z1) + \endcode + where fun is any of the standard math unary functions. + */ + friend std::ostream& operator << (std::ostream &os, const zdouble& z); + friend int Integer(const zdouble& z); + friend zdouble pow(const zdouble& x, const zdouble& y); + friend bool abs_geq(const zdouble& x, const zdouble& y); + // + CPPAD_ZDOUBLE_STD_MATH_FRIEND(acos) + CPPAD_ZDOUBLE_STD_MATH_FRIEND(asin) + CPPAD_ZDOUBLE_STD_MATH_FRIEND(atan) + CPPAD_ZDOUBLE_STD_MATH_FRIEND(cos) + CPPAD_ZDOUBLE_STD_MATH_FRIEND(cosh) + CPPAD_ZDOUBLE_STD_MATH_FRIEND(exp) + CPPAD_ZDOUBLE_STD_MATH_FRIEND(fabs) + CPPAD_ZDOUBLE_STD_MATH_FRIEND(log) + CPPAD_ZDOUBLE_STD_MATH_FRIEND(log10) + CPPAD_ZDOUBLE_STD_MATH_FRIEND(sin) + CPPAD_ZDOUBLE_STD_MATH_FRIEND(sinh) + CPPAD_ZDOUBLE_STD_MATH_FRIEND(sqrt) + CPPAD_ZDOUBLE_STD_MATH_FRIEND(tan) + CPPAD_ZDOUBLE_STD_MATH_FRIEND(tanh) + // + CPPAD_ZDOUBLE_STD_MATH_FRIEND(asinh) + CPPAD_ZDOUBLE_STD_MATH_FRIEND(acosh) + CPPAD_ZDOUBLE_STD_MATH_FRIEND(atanh) + CPPAD_ZDOUBLE_STD_MATH_FRIEND(erf) + CPPAD_ZDOUBLE_STD_MATH_FRIEND(erfc) + CPPAD_ZDOUBLE_STD_MATH_FRIEND(expm1) + CPPAD_ZDOUBLE_STD_MATH_FRIEND(log1p) + // +private: + /// The value for this object + double dbl_; +public: + /// Default constructor + zdouble(void) + : dbl_() + { } + /// Copy constructor + zdouble(const zdouble& z) + : dbl_(z.dbl_) + { } + /// Constructor from double + zdouble(const double& dbl) + : dbl_(dbl) + { } + // + /// Destructor + ~zdouble(void) + { } + // + /// Assignment from zdouble + zdouble& operator=(const zdouble& z) + { dbl_ = z.dbl_; + return *this; + } + /// Assignment from double + zdouble& operator=(const double& dbl) + { dbl_ = dbl; + return *this; + } + // + /// Normal compound assignment + CPPAD_ZDOUBLE_NORMAL_ASSIGN_OPERATOR(+=) + /// Normal compound assignment + CPPAD_ZDOUBLE_NORMAL_ASSIGN_OPERATOR(-=) + /// Normal unary operator + CPPAD_ZDOUBLE_UNARY_OPERATOR(+) + /// Normal unary operator + CPPAD_ZDOUBLE_UNARY_OPERATOR(-) + /// Normal compare operator + CPPAD_ZDOUBLE_COMPARE_OPERATOR(==) + /// Normal compare operator + CPPAD_ZDOUBLE_COMPARE_OPERATOR(!=) + /// Normal compare operator + CPPAD_ZDOUBLE_COMPARE_OPERATOR(<=) + /// Normal compare operator + CPPAD_ZDOUBLE_COMPARE_OPERATOR(>=) + /// Normal compare operator + CPPAD_ZDOUBLE_COMPARE_OPERATOR(<) + /// Normal compare operator + CPPAD_ZDOUBLE_COMPARE_OPERATOR(>) + // + /// Normal binary arithmetic operator + CPPAD_ZDOUBLE_NORMAL_BINARY_OPERATOR(+) + /// Normal binary arithmetic operator + CPPAD_ZDOUBLE_NORMAL_BINARY_OPERATOR(-) + // + /// Binary arithmetic * with absolute zero + zdouble operator * (const zdouble& z) const + { bool zero = (dbl_ == 0.0) || (z.dbl_ == 0.0); + return zdouble( zero ? 0.0 : (dbl_ * z.dbl_) ); + } + /// Binary arithmetic * with absolute zero + zdouble operator * (const double& x) const + { bool zero = (dbl_ == 0.0) || (x == 0.0); + return zdouble( zero ? 0.0 : (dbl_ * x) ); + } + /// Binary arithmetic / with absolute zero + zdouble operator / (const zdouble& z) const + { bool zero = (dbl_ == 0.0); + return zdouble( zero ? 0.0 : (dbl_ / z.dbl_) ); + } + /// Binary arithmetic / with absolute zero + zdouble operator / (const double& x) const + { bool zero = (dbl_ == 0.0); + return zdouble( zero ? 0.0 : (dbl_ / x) ); + } + // + /// Compute assignmnet *= with absolute zero + zdouble& operator *= (const zdouble& z) + { bool zero = (dbl_ == 0.0) || (z.dbl_ == 0.0); + zero ? (dbl_ = 0.0) : (dbl_ *= z.dbl_); + return *this; + } + /// Compute assignmnet *= with absolute zero + zdouble& operator *= (const double& x) + { bool zero = (dbl_ == 0.0) || (x == 0.0); + zero ? (dbl_ = 0.0) : (dbl_ *= x); + return *this; + } + // + /// Compute assignmnet /= with absolute zero + zdouble& operator /= (const zdouble& z) + { bool zero = (dbl_ == 0.0); + zero ? (dbl_ = 0.0) : (dbl_ /= z.dbl_); + return *this; + } + /// Compute assignmnet /= with absolute zero + zdouble& operator /= (const double& x) + { bool zero = (dbl_ == 0.0); + zero ? (dbl_ = 0.0) : (dbl_ /= x); + return *this; + } +}; +// BEGIN nan +/// Must specialize CppAD::nan because zdouble 0/0 is not nan. +template <> inline +zdouble nan(const zdouble& zero) +{ + return zdouble( std::numeric_limits::quiet_NaN() ); +} +// END nan +// +/// Normal non-member compare operator +CPPAD_ZDOUBLE_OTHER_COMPARE_OPERATOR(==, ==) +/// Normal non-member compare operator +CPPAD_ZDOUBLE_OTHER_COMPARE_OPERATOR(!=, !=) +/// Normal non-member compare operator +CPPAD_ZDOUBLE_OTHER_COMPARE_OPERATOR(<=, >=) +/// Normal non-member compare operator +CPPAD_ZDOUBLE_OTHER_COMPARE_OPERATOR(>=, <=) +/// Normal non-member compare operator +CPPAD_ZDOUBLE_OTHER_COMPARE_OPERATOR(<, >) +/// Normal non-member compare operator +CPPAD_ZDOUBLE_OTHER_COMPARE_OPERATOR(>, <) +// +/// Normal binary arithmetic operator +CPPAD_ZDOUBLE_OTHER_BINARY_OPERATOR(+) +/// Normal binary arithmetic operator +CPPAD_ZDOUBLE_OTHER_BINARY_OPERATOR(-) +/// Binary arithmetic operator with absolute zero +CPPAD_ZDOUBLE_OTHER_BINARY_OPERATOR(*) +/// Binary arithmetic operator with absolute zero +CPPAD_ZDOUBLE_OTHER_BINARY_OPERATOR(/) +// ------------------------------------------------------------------------- +// Base type requirements +// ------------------------------------------------------------------------- + +/// Base type requirement: CondExpOp +inline zdouble CondExpOp( + enum CompareOp cop , + const zdouble& left , + const zdouble& right , + const zdouble& exp_if_true , + const zdouble& exp_if_false ) +{ return CondExpTemplate(cop, left, right, exp_if_true, exp_if_false); +} + +/// Base type requirement: CondExpRel +CPPAD_COND_EXP_REL(zdouble) + +/// Base type requirement: EqualOpSeq +inline bool EqualOpSeq(const zdouble& x, const zdouble& y) +{ return x == y; } + +/// Base type requirement: Identical +inline bool IdenticalCon(const zdouble& x) +{ return true; } +inline bool IdenticalZero(const zdouble& x) +{ return (x == 0.0); } +inline bool IdenticalOne(const zdouble& x) +{ return (x == 1.); } +inline bool IdenticalEqualCon(const zdouble& x, const zdouble& y) +{ return (x == y); } + +/// Base type requirement: output operator +inline std::ostream& operator << (std::ostream &os, const zdouble& z) +{ os << z.dbl_; + return os; +} + +/// Base type requirement: Integer +inline int Integer(const zdouble& x) +{ return static_cast(x.dbl_); } + +/// Base type requirement: azmul +inline zdouble azmul(const zdouble& x, const zdouble& y) +{ return x * y; } + +/// Base type requirement: Ordered +inline bool GreaterThanZero(const zdouble& x) +{ return x > 0.0; } +inline bool GreaterThanOrZero(const zdouble& x) +{ return x >= 0.0; } +inline bool LessThanZero(const zdouble& x) +{ return x < 0.0; } +inline bool LessThanOrZero(const zdouble& x) +{ return x <= 0.0; } +inline bool abs_geq(const zdouble& x, const zdouble& y) +{ return std::fabs(x.dbl_) >= std::fabs(y.dbl_); } + +/// Normal standard math function +CPPAD_ZDOUBLE_STD_MATH(acos) +/// Normal standard math function +CPPAD_ZDOUBLE_STD_MATH(asin) +/// Normal standard math function +CPPAD_ZDOUBLE_STD_MATH(atan) +/// Normal standard math function +CPPAD_ZDOUBLE_STD_MATH(cos) +/// Normal standard math function +CPPAD_ZDOUBLE_STD_MATH(cosh) +/// Normal standard math function +CPPAD_ZDOUBLE_STD_MATH(exp) +/// Normal standard math function +CPPAD_ZDOUBLE_STD_MATH(fabs) +/// Normal standard math function +CPPAD_ZDOUBLE_STD_MATH(log) +/// Normal standard math function +CPPAD_ZDOUBLE_STD_MATH(log10) +/// Normal standard math function +CPPAD_ZDOUBLE_STD_MATH(sin) +/// Normal standard math function +CPPAD_ZDOUBLE_STD_MATH(sinh) +/// Normal standard math function +CPPAD_ZDOUBLE_STD_MATH(sqrt) +/// Normal standard math function +CPPAD_ZDOUBLE_STD_MATH(tan) +/// Normal standard math function +CPPAD_ZDOUBLE_STD_MATH(tanh) +// +/// C++2011 standard math function +CPPAD_ZDOUBLE_STD_MATH(asinh) +/// C++2011 standard math function +CPPAD_ZDOUBLE_STD_MATH(acosh) +/// C++2011 standard math function +CPPAD_ZDOUBLE_STD_MATH(atanh) +/// C++2011 standard math function +CPPAD_ZDOUBLE_STD_MATH(erf) +/// C++2011 standard math function +CPPAD_ZDOUBLE_STD_MATH(erfc) +/// C++2011 standard math function +CPPAD_ZDOUBLE_STD_MATH(expm1) +/// C++2011 standard math function +CPPAD_ZDOUBLE_STD_MATH(log1p) + +/// Base type requirement: abs +inline zdouble abs(const zdouble& x) +{ return fabs(x); } + +/// Base type requirement: sign +inline zdouble sign(const zdouble& x) +{ if( x > 0.0 ) + return zdouble(1.); + if( x == 0.0 ) + return zdouble(0.0); + return zdouble(-1.); +} + +/// Base type requirement: pow +inline zdouble pow(const zdouble& x, const zdouble& y) +{ return std::pow(x.dbl_, y.dbl_); } + +/// Base type requirement: limits +CPPAD_NUMERIC_LIMITS(double, zdouble) + +} // CPPAD_END_NAMESPACE + +/// undef all macros defined in this file +# undef CPPAD_ZDOUBLE_NORMAL_ASSIGN_OPERATOR +# undef CPPAD_ZDOUBLE_UNARY_OPERATOR +# undef CPPAD_ZDOUBLE_NORMAL_BINARY_OPERATOR +# undef CPPAD_ZDOUBLE_COMPARE_OPERATOR +# undef CPPAD_ZDOUBLE_OTHER_BINARY_OPERATOR +# undef CPPAD_ZDOUBLE_OTHER_COMPARE_OPERATOR +# undef CPPAD_ZDOUBLE_STD_MATH_FRIEND +# undef CPPAD_ZDOUBLE_STD_MATH + +# endif diff --git a/build-config/cppad/include/cppad/cppad.hpp b/build-config/cppad/include/cppad/cppad.hpp new file mode 100644 index 00000000..4bfdfc94 --- /dev/null +++ b/build-config/cppad/include/cppad/cppad.hpp @@ -0,0 +1,79 @@ +# ifndef CPPAD_CPPAD_HPP +# define CPPAD_CPPAD_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ +/*! +\file cppad.hpp +\brief includes the entire CppAD package in the necessary order. + +\namespace CppAD +\brief contains all the variables and functions defined by the CppAD package. +*/ + +# include // all base type requirements +// --------------------------------------------------------------------------- +// CppAD general purpose library routines (can be included separately) +# include +// -------------------------------------------------------------------------- +// System routines that can be used by rest of CppAD with out including + +# include +# include +# include +# include + +// --------------------------------------------------------------------------- +// definitions needed by rest of includes + +// definitions that come from the installation +# include + +// definitions that are local to the CppAD include files +# include + +// vectors used with CppAD +# include + +// deprecated vectors used with CppAD +# include + +// Declare classes and fucntions that are used before defined +# include + +// --------------------------------------------------------------------------- +// declare the AD template class + +# include + +// --------------------------------------------------------------------------- + +# include // AD class methods available to the user +// tape that tape for AD acts as a user of Base operations +// so user_ad.hpp must come before op.hpp +# include // executes taped operations +# include // ADFun objects + +// --------------------------------------------------------------------------- +// library routines that require the rest of CppAD +# include +# include +# include +# include +# include +# if CPPAD_HAS_IPOPT +# include +# endif + +// undo definitions in Define.h +# include + +# endif diff --git a/build-config/cppad/include/cppad/example/atomic_three/mat_mul.hpp b/build-config/cppad/include/cppad/example/atomic_three/mat_mul.hpp new file mode 100644 index 00000000..b0c1af48 --- /dev/null +++ b/build-config/cppad/include/cppad/example/atomic_three/mat_mul.hpp @@ -0,0 +1,661 @@ +# ifndef CPPAD_EXAMPLE_ATOMIC_THREE_MAT_MUL_HPP +# define CPPAD_EXAMPLE_ATOMIC_THREE_MAT_MUL_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +/* +$begin atomic_three_mat_mul.hpp$$ +$spell + Taylor + ty + px + CppAD + jac + hes + nr + nc + afun + mul +$$ + +$section Matrix Multiply as an Atomic Operation$$ + +$head See Also$$ +$cref atomic_two_eigen_mat_mul.hpp$$ + +$head Purpose$$ +Use scalar $code double$$ operations in an $cref atomic_three$$ operation +that computes the matrix product for $code AD +namespace { // Begin empty namespace +using CppAD::vector; +// +// matrix result = left * right +class atomic_mat_mul : public CppAD::atomic_three { +/* %$$ +$head Constructor$$ +$srccode%cpp% */ +public: + // --------------------------------------------------------------------- + // constructor + atomic_mat_mul(void) : CppAD::atomic_three("mat_mul") + { } +private: +/* %$$ +$head Left Operand Element Index$$ +Index in the Taylor coefficient matrix $icode tx$$ of a left matrix element. +$srccode%cpp% */ + size_t left( + size_t i , // left matrix row index + size_t j , // left matrix column index + size_t k , // Taylor coeffocient order + size_t nk , // number of Taylor coefficients in tx + size_t nr_left , // rows in left matrix + size_t n_middle , // rows in left and columns in right + size_t nc_right ) // columns in right matrix + { assert( i < nr_left ); + assert( j < n_middle ); + return (3 + i * n_middle + j) * nk + k; + } +/* %$$ +$head Right Operand Element Index$$ +Index in the Taylor coefficient matrix $icode tx$$ of a right matrix element. +$srccode%cpp% */ + size_t right( + size_t i , // right matrix row index + size_t j , // right matrix column index + size_t k , // Taylor coeffocient order + size_t nk , // number of Taylor coefficients in tx + size_t nr_left , // rows in left matrix + size_t n_middle , // rows in left and columns in right + size_t nc_right ) // columns in right matrix + { assert( i < n_middle ); + assert( j < nc_right ); + size_t offset = 3 + nr_left * n_middle; + return (offset + i * nc_right + j) * nk + k; + } +/* %$$ +$head Result Element Index$$ +Index in the Taylor coefficient matrix $icode ty$$ of a result matrix element. +$srccode%cpp% */ + size_t result( + size_t i , // result matrix row index + size_t j , // result matrix column index + size_t k , // Taylor coeffocient order + size_t nk , // number of Taylor coefficients in ty + size_t nr_left , // rows in left matrix + size_t n_middle , // rows in left and columns in right + size_t nc_right ) // columns in right matrix + { assert( i < nr_left ); + assert( j < nc_right ); + return (i * nc_right + j) * nk + k; + } +/* %$$ +$head Forward Matrix Multiply$$ +Forward mode multiply Taylor coefficients in $icode tx$$ and sum into +$icode ty$$ (for one pair of left and right orders) +$srccode%cpp% */ + void forward_multiply( + size_t k_left , // order for left coefficients + size_t k_right , // order for right coefficients + const vector& tx , // domain space Taylor coefficients + vector& ty , // range space Taylor coefficients + size_t nr_left , // rows in left matrix + size_t n_middle , // rows in left and columns in right + size_t nc_right ) // columns in right matrix + { + size_t nx = 3 + (nr_left + nc_right) * n_middle; + size_t nk = tx.size() / nx; +# ifndef NDEBUG + size_t ny = nr_left * nc_right; + assert( nk == ty.size() / ny ); +# endif + // + size_t k_result = k_left + k_right; + assert( k_result < nk ); + // + for(size_t i = 0; i < nr_left; i++) + { for(size_t j = 0; j < nc_right; j++) + { double sum = 0.0; + for(size_t ell = 0; ell < n_middle; ell++) + { size_t i_left = left( + i, ell, k_left, nk, nr_left, n_middle, nc_right + ); + size_t i_right = right( + ell, j, k_right, nk, nr_left, n_middle, nc_right + ); + sum += tx[i_left] * tx[i_right]; + } + size_t i_result = result( + i, j, k_result, nk, nr_left, n_middle, nc_right + ); + ty[i_result] += sum; + } + } + } +/* %$$ +$head Reverse Matrix Multiply$$ +Reverse mode partials of Taylor coefficients and sum into $icode px$$ +(for one pair of left and right orders) +$srccode%cpp% */ + void reverse_multiply( + size_t k_left , // order for left coefficients + size_t k_right , // order for right coefficients + const vector& tx , // domain space Taylor coefficients + const vector& ty , // range space Taylor coefficients + vector& px , // partials w.r.t. tx + const vector& py , // partials w.r.t. ty + size_t nr_left , // rows in left matrix + size_t n_middle , // rows in left and columns in right + size_t nc_right ) // columns in right matrix + { + size_t nx = 3 + (nr_left + nc_right) * n_middle; + size_t nk = tx.size() / nx; +# ifndef NDEBUG + size_t ny = nr_left * nc_right; + assert( nk == ty.size() / ny ); +# endif + assert( tx.size() == px.size() ); + assert( ty.size() == py.size() ); + // + size_t k_result = k_left + k_right; + assert( k_result < nk ); + // + for(size_t i = 0; i < nr_left; i++) + { for(size_t j = 0; j < nc_right; j++) + { size_t i_result = result( + i, j, k_result, nk, nr_left, n_middle, nc_right + ); + for(size_t ell = 0; ell < n_middle; ell++) + { size_t i_left = left( + i, ell, k_left, nk, nr_left, n_middle, nc_right + ); + size_t i_right = right( + ell, j, k_right, nk, nr_left, n_middle, nc_right + ); + // sum += tx[i_left] * tx[i_right]; + px[i_left] += tx[i_right] * py[i_result]; + px[i_right] += tx[i_left] * py[i_result]; + } + } + } + return; + } +/* %$$ +$head for_type$$ +Routine called by CppAD during $cref/afun(ax, ay)/atomic_three_afun/$$. +$srccode%cpp% */ + // calculate type_y + virtual bool for_type( + const vector& parameter_x , + const vector& type_x , + vector& type_y ) + { assert( parameter_x.size() == type_x.size() ); + bool ok = true; + ok &= type_x[0] == CppAD::constant_enum; + ok &= type_x[1] == CppAD::constant_enum; + ok &= type_x[2] == CppAD::constant_enum; + if( ! ok ) + return false; + // + size_t nr_left = size_t( parameter_x[0] ); + size_t n_middle = size_t( parameter_x[1] ); + size_t nc_right = size_t( parameter_x[2] ); + // + ok &= type_x.size() == 3 + (nr_left + nc_right) * n_middle; + ok &= type_y.size() == n_middle * nc_right; + if( ! ok ) + return false; + // + // commpute type_y + size_t nk = 1; // number of orders + size_t k = 0; // order + for(size_t i = 0; i < nr_left; ++i) + { for(size_t j = 0; j < nc_right; ++j) + { // compute type for result[i, j] + CppAD::ad_type_enum type_yij = CppAD::constant_enum; + for(size_t ell = 0; ell < n_middle; ++ell) + { // index for left(i, ell) + size_t i_left = left( + i, ell, k, nk, nr_left, n_middle, nc_right + ); + // indx for right(ell, j) + size_t i_right = right( + ell, j, k, nk, nr_left, n_middle, nc_right + ); + // multiplication on left or right by the constant zero + // always results in a constant + bool zero_left = type_x[i_left] == CppAD::constant_enum; + zero_left &= parameter_x[i_left] == 0.0; + bool zero_right = type_x[i_right] == CppAD::constant_enum; + zero_right &= parameter_x[i_right] == 0.0; + if( ! (zero_left | zero_right) ) + { type_yij = std::max(type_yij, type_x[i_left] ); + type_yij = std::max(type_yij, type_x[i_right] ); + } + } + size_t i_result = result( + i, j, k, nk, nr_left, n_middle, nc_right + ); + type_y[i_result] = type_yij; + } + } + return true; + } +/* %$$ +$head forward$$ +Routine called by CppAD during $cref Forward$$ mode. +$srccode%cpp% */ + virtual bool forward( + const vector& parameter_x , + const vector& type_x , + size_t need_y , + size_t q , + size_t p , + const vector& tx , + vector& ty ) + { size_t n_order = p + 1; + size_t nr_left = size_t( tx[ 0 * n_order + 0 ] ); + size_t n_middle = size_t( tx[ 1 * n_order + 0 ] ); + size_t nc_right = size_t( tx[ 2 * n_order + 0 ] ); +# ifndef NDEBUG + size_t nx = 3 + (nr_left + nc_right) * n_middle; + size_t ny = nr_left * nc_right; +# endif + assert( nx * n_order == tx.size() ); + assert( ny * n_order == ty.size() ); + size_t i, j, ell; + + // initialize result as zero + size_t k; + for(i = 0; i < nr_left; i++) + { for(j = 0; j < nc_right; j++) + { for(k = q; k <= p; k++) + { size_t i_result = result( + i, j, k, n_order, nr_left, n_middle, nc_right + ); + ty[i_result] = 0.0; + } + } + } + for(k = q; k <= p; k++) + { // sum the produces that result in order k + for(ell = 0; ell <= k; ell++) + forward_multiply( + ell, k - ell, tx, ty, nr_left, n_middle, nc_right + ); + } + + // all orders are implemented, so always return true + return true; + } +/* %$$ +$head reverse$$ +Routine called by CppAD during $cref Reverse$$ mode. +$srccode%cpp% */ + virtual bool reverse( + const vector& parameter_x , + const vector& type_x , + size_t p , + const vector& tx , + const vector& ty , + vector& px , + const vector& py ) + { size_t n_order = p + 1; + size_t nr_left = size_t( tx[ 0 * n_order + 0 ] ); + size_t n_middle = size_t( tx[ 1 * n_order + 0 ] ); + size_t nc_right = size_t( tx[ 2 * n_order + 0 ] ); +# ifndef NDEBUG + size_t nx = 3 + (nr_left + nc_right) * n_middle; + size_t ny = nr_left * nc_right; +# endif + assert( nx * n_order == tx.size() ); + assert( ny * n_order == ty.size() ); + assert( px.size() == tx.size() ); + assert( py.size() == ty.size() ); + + // initialize summation + for(size_t i = 0; i < px.size(); i++) + px[i] = 0.0; + + // number of orders to differentiate + size_t k = n_order; + while(k--) + { // differentiate the produces that result in order k + for(size_t ell = 0; ell <= k; ell++) + reverse_multiply( + ell, k - ell, tx, ty, px, py, nr_left, n_middle, nc_right + ); + } + + // all orders are implented, so always return true + return true; + } +/* %$$ +$head jac_sparsity$$ +$srccode%cpp% */ + // Jacobian sparsity routine called by CppAD + virtual bool jac_sparsity( + const vector& parameter_x , + const vector& type_x , + bool dependency , + const vector& select_x , + const vector& select_y , + CppAD::sparse_rc< vector >& pattern_out ) + { + size_t n = select_x.size(); + size_t m = select_y.size(); + assert( parameter_x.size() == n ); + assert( type_x.size() == n ); + // + size_t nr_left = size_t( parameter_x[0] ); + size_t n_middle = size_t( parameter_x[1] ); + size_t nc_right = size_t( parameter_x[2] ); + size_t nk = 1; // only one order + size_t k = 0; // order zero + // + // count number of non-zeros in sparsity pattern + size_t nnz = 0; + for(size_t i = 0; i < nr_left; ++i) + { for(size_t j = 0; j < nc_right; ++j) + { size_t i_result = result( + i, j, k, nk, nr_left, n_middle, nc_right + ); + if( select_y[i_result] ) + { for(size_t ell = 0; ell < n_middle; ++ell) + { size_t i_left = left( + i, ell, k, nk, nr_left, n_middle, nc_right + ); + size_t i_right = right( + ell, j, k, nk, nr_left, n_middle, nc_right + ); + bool zero_left = + type_x[i_left] == CppAD::constant_enum; + zero_left &= parameter_x[i_left] == 0.0; + bool zero_right = + type_x[i_right] == CppAD::constant_enum; + zero_right &= parameter_x[i_right] == 0.0; + if( ! (zero_left | zero_right ) ) + { bool var_left = + type_x[i_left] == CppAD::variable_enum; + bool var_right = + type_x[i_right] == CppAD::variable_enum; + if( select_x[i_left] & var_left ) + ++nnz; + if( select_x[i_right] & var_right ) + ++nnz; + } + } + } + } + } + // + // fill in the sparsity pattern + pattern_out.resize(m, n, nnz); + size_t idx = 0; + for(size_t i = 0; i < nr_left; ++i) + { for(size_t j = 0; j < nc_right; ++j) + { size_t i_result = result( + i, j, k, nk, nr_left, n_middle, nc_right + ); + if( select_y[i_result] ) + { for(size_t ell = 0; ell < n_middle; ++ell) + { size_t i_left = left( + i, ell, k, nk, nr_left, n_middle, nc_right + ); + size_t i_right = right( + ell, j, k, nk, nr_left, n_middle, nc_right + ); + bool zero_left = + type_x[i_left] == CppAD::constant_enum; + zero_left &= parameter_x[i_left] == 0.0; + bool zero_right = + type_x[i_right] == CppAD::constant_enum; + zero_right &= parameter_x[i_right] == 0.0; + if( ! (zero_left | zero_right ) ) + { bool var_left = + type_x[i_left] == CppAD::variable_enum; + bool var_right = + type_x[i_right] == CppAD::variable_enum; + if( select_x[i_left] & var_left ) + pattern_out.set(idx++, i_result, i_left); + if( select_x[i_right] & var_right ) + pattern_out.set(idx++, i_result, i_right); + } + } + } + } + } + assert( idx == nnz ); + // + return true; + } +/* %$$ +$head hes_sparsity$$ +$srccode%cpp% */ + // Jacobian sparsity routine called by CppAD + virtual bool hes_sparsity( + const vector& parameter_x , + const vector& type_x , + const vector& select_x , + const vector& select_y , + CppAD::sparse_rc< vector >& pattern_out ) + { + size_t n = select_x.size(); + assert( parameter_x.size() == n ); + assert( type_x.size() == n ); + // + size_t nr_left = size_t( parameter_x[0] ); + size_t n_middle = size_t( parameter_x[1] ); + size_t nc_right = size_t( parameter_x[2] ); + size_t nk = 1; // only one order + size_t k = 0; // order zero + // + // count number of non-zeros in sparsity pattern + size_t nnz = 0; + for(size_t i = 0; i < nr_left; ++i) + { for(size_t j = 0; j < nc_right; ++j) + { size_t i_result = result( + i, j, k, nk, nr_left, n_middle, nc_right + ); + if( select_y[i_result] ) + { for(size_t ell = 0; ell < n_middle; ++ell) + { // i_left depends on i, ell + size_t i_left = left( + i, ell, k, nk, nr_left, n_middle, nc_right + ); + // i_right depens on ell, j + size_t i_right = right( + ell, j, k, nk, nr_left, n_middle, nc_right + ); + bool var_left = select_x[i_left] & + (type_x[i_left] == CppAD::variable_enum); + bool var_right = select_x[i_right] & + (type_x[i_right] == CppAD::variable_enum); + if( var_left & var_right ) + nnz += 2; + } + } + } + } + // + // fill in the sparsity pattern + pattern_out.resize(n, n, nnz); + size_t idx = 0; + for(size_t i = 0; i < nr_left; ++i) + { for(size_t j = 0; j < nc_right; ++j) + { size_t i_result = result( + i, j, k, nk, nr_left, n_middle, nc_right + ); + if( select_y[i_result] ) + { for(size_t ell = 0; ell < n_middle; ++ell) + { size_t i_left = left( + i, ell, k, nk, nr_left, n_middle, nc_right + ); + size_t i_right = right( + ell, j, k, nk, nr_left, n_middle, nc_right + ); + bool var_left = select_x[i_left] & + (type_x[i_left] == CppAD::variable_enum); + bool var_right = select_x[i_right] & + (type_x[i_right] == CppAD::variable_enum); + if( var_left & var_right ) + { // Cannot possibly set the same (i_left, i_right) + // pair twice. + assert( i_left != i_right ); + pattern_out.set(idx++, i_left, i_right); + pattern_out.set(idx++, i_right, i_left); + } + } + } + } + } + assert( idx == nnz ); + // + return true; + } +/* %$$ +$head rev_depend$$ +Routine called when a function using $code mat_mul$$ is optimized. +$srccode%cpp% */ + // calculate depend_x + virtual bool rev_depend( + const vector& parameter_x , + const vector& type_x , + vector& depend_x , + const vector& depend_y ) + { assert( parameter_x.size() == depend_x.size() ); + assert( parameter_x.size() == type_x.size() ); + bool ok = true; + // + size_t nr_left = size_t( parameter_x[0] ); + size_t n_middle = size_t( parameter_x[1] ); + size_t nc_right = size_t( parameter_x[2] ); + // + ok &= depend_x.size() == 3 + (nr_left + nc_right) * n_middle; + ok &= depend_y.size() == n_middle * nc_right; + if( ! ok ) + return false; + // + // initialize depend_x + for(size_t ell = 0; ell < 3; ++ell) + depend_x[ell] = true; // always need these parameters + for(size_t ell = 3; ell < depend_x.size(); ++ell) + depend_x[ell] = false; // initialize as false + // + // commpute depend_x + size_t nk = 1; // number of orders + size_t k = 0; // order + for(size_t i = 0; i < nr_left; ++i) + { for(size_t j = 0; j < nc_right; ++j) + { // check depend for result[i, j] + size_t i_result = result( + i, j, k, nk, nr_left, n_middle, nc_right + ); + if( depend_y[i_result] ) + { for(size_t ell = 0; ell < n_middle; ++ell) + { // index for left(i, ell) + size_t i_left = left( + i, ell, k, nk, nr_left, n_middle, nc_right + ); + // indx for right(ell, j) + size_t i_right = right( + ell, j, k, nk, nr_left, n_middle, nc_right + ); + bool zero_left = + type_x[i_left] == CppAD::constant_enum; + zero_left &= parameter_x[i_left] == 0.0; + bool zero_right = + type_x[i_right] == CppAD::constant_enum; + zero_right &= parameter_x[i_right] == 0.0; + if( ! zero_right ) + depend_x[i_left] = true; + if( ! zero_left ) + depend_x[i_right] = true; + } + } + } + } + return true; + } +/* %$$ +$head End Class Definition$$ +$srccode%cpp% */ +}; // End of mat_mul class +} // End empty namespace +/* %$$ +$comment end nospell$$ +$end +*/ + + +# endif diff --git a/build-config/cppad/include/cppad/example/atomic_two/eigen_cholesky.hpp b/build-config/cppad/include/cppad/example/atomic_two/eigen_cholesky.hpp new file mode 100644 index 00000000..0b2b0861 --- /dev/null +++ b/build-config/cppad/include/cppad/example/atomic_two/eigen_cholesky.hpp @@ -0,0 +1,376 @@ +# ifndef CPPAD_EXAMPLE_ATOMIC_TWO_EIGEN_CHOLESKY_HPP +# define CPPAD_EXAMPLE_ATOMIC_TWO_EIGEN_CHOLESKY_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +/* +$begin atomic_two_eigen_cholesky.hpp$$ +$spell + Eigen + Taylor + Cholesky + op +$$ + +$section atomic_two Eigen Cholesky Factorization Class$$ + +$head Purpose$$ +Construct an atomic operation that computes a lower triangular matrix +$latex L $$ such that $latex L L^\R{T} = A$$ +for any positive integer $latex p$$ +and symmetric positive definite matrix $latex A \in \B{R}^{p \times p}$$. + +$head Start Class Definition$$ +$srccode%cpp% */ +# include +# include + + +/* %$$ +$head Public$$ + +$subhead Types$$ +$srccode%cpp% */ +namespace { // BEGIN_EMPTY_NAMESPACE + +template +class atomic_eigen_cholesky : public CppAD::atomic_base { +public: + // ----------------------------------------------------------- + // type of elements during calculation of derivatives + typedef Base scalar; + // type of elements during taping + typedef CppAD::AD ad_scalar; + // + // type of matrix during calculation of derivatives + typedef Eigen::Matrix< + scalar, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor> matrix; + // type of matrix during taping + typedef Eigen::Matrix< + ad_scalar, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor > ad_matrix; + // + // lower triangular scalar matrix + typedef Eigen::TriangularView lower_view; +/* %$$ +$subhead Constructor$$ +$srccode%cpp% */ + // constructor + atomic_eigen_cholesky(void) : CppAD::atomic_base( + "atom_eigen_cholesky" , + CppAD::atomic_base::set_sparsity_enum + ) + { } +/* %$$ +$subhead op$$ +$srccode%cpp% */ + // use atomic operation to invert an AD matrix + ad_matrix op(const ad_matrix& arg) + { size_t nr = size_t( arg.rows() ); + size_t ny = ( (nr + 1 ) * nr ) / 2; + size_t nx = 1 + ny; + assert( nr == size_t( arg.cols() ) ); + // ------------------------------------------------------------------- + // packed version of arg + CPPAD_TESTVECTOR(ad_scalar) packed_arg(nx); + size_t index = 0; + packed_arg[index++] = ad_scalar( nr ); + // lower triangle of symmetric matrix A + for(size_t i = 0; i < nr; i++) + { for(size_t j = 0; j <= i; j++) + packed_arg[index++] = arg( long(i), long(j) ); + } + assert( index == nx ); + // ------------------------------------------------------------------- + // packed version of result = arg^{-1}. + // This is an atomic_base function call that CppAD uses to + // store the atomic operation on the tape. + CPPAD_TESTVECTOR(ad_scalar) packed_result(ny); + (*this)(packed_arg, packed_result); + // ------------------------------------------------------------------- + // unpack result matrix L + ad_matrix result = ad_matrix::Zero( long(nr), long(nr) ); + index = 0; + for(size_t i = 0; i < nr; i++) + { for(size_t j = 0; j <= i; j++) + result( long(i), long(j) ) = packed_result[index++]; + } + return result; + } + /* %$$ +$head Private$$ + +$subhead Variables$$ +$srccode%cpp% */ +private: + // ------------------------------------------------------------- + // one forward mode vector of matrices for argument and result + CppAD::vector f_arg_, f_result_; + // one reverse mode vector of matrices for argument and result + CppAD::vector r_arg_, r_result_; + // ------------------------------------------------------------- +/* %$$ +$subhead forward$$ +$srccode%cpp% */ + // forward mode routine called by CppAD + virtual bool forward( + // lowest order Taylor coefficient we are evaluating + size_t p , + // highest order Taylor coefficient we are evaluating + size_t q , + // which components of x are variables + const CppAD::vector& vx , + // which components of y are variables + CppAD::vector& vy , + // tx [ j * (q+1) + k ] is x_j^k + const CppAD::vector& tx , + // ty [ i * (q+1) + k ] is y_i^k + CppAD::vector& ty + ) + { size_t n_order = q + 1; + size_t nr = size_t( CppAD::Integer( tx[ 0 * n_order + 0 ] ) ); + size_t ny = ((nr + 1) * nr) / 2; +# ifndef NDEBUG + size_t nx = 1 + ny; +# endif + assert( vx.size() == 0 || nx == vx.size() ); + assert( vx.size() == 0 || ny == vy.size() ); + assert( nx * n_order == tx.size() ); + assert( ny * n_order == ty.size() ); + // + // ------------------------------------------------------------------- + // make sure f_arg_ and f_result_ are large enough + assert( f_arg_.size() == f_result_.size() ); + if( f_arg_.size() < n_order ) + { f_arg_.resize(n_order); + f_result_.resize(n_order); + // + for(size_t k = 0; k < n_order; k++) + { f_arg_[k].resize( long(nr), long(nr) ); + f_result_[k].resize( long(nr), long(nr) ); + } + } + // ------------------------------------------------------------------- + // unpack tx into f_arg_ + for(size_t k = 0; k < n_order; k++) + { size_t index = 1; + // unpack arg values for this order + for(long i = 0; i < long(nr); i++) + { for(long j = 0; j <= i; j++) + { f_arg_[k](i, j) = tx[ index * n_order + k ]; + f_arg_[k](j, i) = f_arg_[k](i, j); + index++; + } + } + } + // ------------------------------------------------------------------- + // result for each order + // (we could avoid recalculting f_result_[k] for k=0,...,p-1) + // + Eigen::LLT cholesky(f_arg_[0]); + f_result_[0] = cholesky.matrixL(); + lower_view L_0 = f_result_[0].template triangularView(); + for(size_t k = 1; k < n_order; k++) + { // initialize sum as A_k + matrix f_sum = f_arg_[k]; + // compute A_k - B_k + for(size_t ell = 1; ell < k; ell++) + f_sum -= f_result_[ell] * f_result_[k-ell].transpose(); + // compute L_0^{-1} * (A_k - B_k) * L_0^{-T} + matrix temp = L_0.template solve(f_sum); + temp = L_0.transpose().template solve(temp); + // divide the diagonal by 2 + for(long i = 0; i < long(nr); i++) + temp(i, i) /= scalar(2.0); + // L_k = L_0 * low[ L_0^{-1} * (A_k - B_k) * L_0^{-T} ] + lower_view view = temp.template triangularView(); + f_result_[k] = f_result_[0] * view; + } + // ------------------------------------------------------------------- + // pack result_ into ty + for(size_t k = 0; k < n_order; k++) + { size_t index = 0; + for(long i = 0; i < long(nr); i++) + { for(long j = 0; j <= i; j++) + { ty[ index * n_order + k ] = f_result_[k](i, j); + index++; + } + } + } + // ------------------------------------------------------------------- + // check if we are computing vy + if( vx.size() == 0 ) + return true; + // ------------------------------------------------------------------ + // This is a very dumb algorithm that over estimates which + // elements of the inverse are variables (which is not efficient). + bool var = false; + for(size_t i = 0; i < ny; i++) + var |= vx[1 + i]; + for(size_t i = 0; i < ny; i++) + vy[i] = var; + // + return true; + } +/* %$$ +$subhead reverse$$ +$srccode%cpp% */ + // reverse mode routine called by CppAD + virtual bool reverse( + // highest order Taylor coefficient that we are computing derivative of + size_t q , + // forward mode Taylor coefficients for x variables + const CppAD::vector& tx , + // forward mode Taylor coefficients for y variables + const CppAD::vector& ty , + // upon return, derivative of G[ F[ {x_j^k} ] ] w.r.t {x_j^k} + CppAD::vector& px , + // derivative of G[ {y_i^k} ] w.r.t. {y_i^k} + const CppAD::vector& py + ) + { size_t n_order = q + 1; + size_t nr = size_t( CppAD::Integer( tx[ 0 * n_order + 0 ] ) ); +# ifndef NDEBUG + size_t ny = ( (nr + 1 ) * nr ) / 2; + size_t nx = 1 + ny; +# endif + // + assert( nx * n_order == tx.size() ); + assert( ny * n_order == ty.size() ); + assert( px.size() == tx.size() ); + assert( py.size() == ty.size() ); + // ------------------------------------------------------------------- + // make sure f_arg_ is large enough + assert( f_arg_.size() == f_result_.size() ); + // must have previous run forward with order >= n_order + assert( f_arg_.size() >= n_order ); + // ------------------------------------------------------------------- + // make sure r_arg_, r_result_ are large enough + assert( r_arg_.size() == r_result_.size() ); + if( r_arg_.size() < n_order ) + { r_arg_.resize(n_order); + r_result_.resize(n_order); + // + for(size_t k = 0; k < n_order; k++) + { r_arg_[k].resize( long(nr), long(nr) ); + r_result_[k].resize( long(nr), long(nr) ); + } + } + // ------------------------------------------------------------------- + // unpack tx into f_arg_ + for(size_t k = 0; k < n_order; k++) + { size_t index = 1; + // unpack arg values for this order + for(long i = 0; i < long(nr); i++) + { for(long j = 0; j <= i; j++) + { f_arg_[k](i, j) = tx[ index * n_order + k ]; + f_arg_[k](j, i) = f_arg_[k](i, j); + index++; + } + } + } + // ------------------------------------------------------------------- + // unpack py into r_result_ + for(size_t k = 0; k < n_order; k++) + { r_result_[k] = matrix::Zero( long(nr), long(nr) ); + size_t index = 0; + for(long i = 0; i < long(nr); i++) + { for(long j = 0; j <= i; j++) + { r_result_[k](i, j) = py[ index * n_order + k ]; + index++; + } + } + } + // ------------------------------------------------------------------- + // initialize r_arg_ as zero + for(size_t k = 0; k < n_order; k++) + r_arg_[k] = matrix::Zero( long(nr), long(nr) ); + // ------------------------------------------------------------------- + // matrix reverse mode calculation + lower_view L_0 = f_result_[0].template triangularView(); + // + for(size_t k1 = n_order; k1 > 1; k1--) + { size_t k = k1 - 1; + // + // L_0^T * bar{L}_k + matrix tmp1 = L_0.transpose() * r_result_[k]; + // + //low[ L_0^T * bar{L}_k ] + for(long i = 0; i < long(nr); i++) + tmp1(i, i) /= scalar(2.0); + matrix tmp2 = tmp1.template triangularView(); + // + // L_0^{-T} low[ L_0^T * bar{L}_k ] + tmp1 = L_0.transpose().template solve( tmp2 ); + // + // M_k = L_0^{-T} * low[ L_0^T * bar{L}_k ]^{T} L_0^{-1} + matrix M_k = L_0.transpose().template + solve( tmp1.transpose() ); + // + // remove L_k and compute bar{B}_k + matrix barB_k = scalar(0.5) * ( M_k + M_k.transpose() ); + r_arg_[k] += barB_k; + barB_k = scalar(-1.0) * barB_k; + // + // 2.0 * lower( bar{B}_k L_k ) + matrix temp = scalar(2.0) * barB_k * f_result_[k]; + temp = temp.template triangularView(); + // + // remove C_k + r_result_[0] += temp; + // + // remove B_k + for(size_t ell = 1; ell < k; ell++) + { // bar{L}_ell = 2 * lower( \bar{B}_k * L_{k-ell} ) + temp = scalar(2.0) * barB_k * f_result_[k-ell]; + r_result_[ell] += temp.template triangularView(); + } + } + // M_0 = L_0^{-T} * low[ L_0^T * bar{L}_0 ]^{T} L_0^{-1} + matrix M_0 = L_0.transpose() * r_result_[0]; + for(long i = 0; i < long(nr); i++) + M_0(i, i) /= scalar(2.0); + M_0 = M_0.template triangularView(); + M_0 = L_0.template solve( M_0 ); + M_0 = L_0.transpose().template solve( M_0 ); + // remove L_0 + r_arg_[0] += scalar(0.5) * ( M_0 + M_0.transpose() ); + // ------------------------------------------------------------------- + // pack r_arg into px + // note that only the lower triangle of barA_k is stored in px + for(size_t k = 0; k < n_order; k++) + { size_t index = 0; + px[ index * n_order + k ] = 0.0; + index++; + for(long i = 0; i < long(nr); i++) + { for(long j = 0; j < i; j++) + { px[ index * n_order + k ] = 2.0 * r_arg_[k](i, j); + index++; + } + px[ index * n_order + k] = r_arg_[k](i, i); + index++; + } + } + // ------------------------------------------------------------------- + return true; + } +/* %$$ +$head End Class Definition$$ +$srccode%cpp% */ +}; // End of atomic_eigen_cholesky class + +} // END_EMPTY_NAMESPACE +/* %$$ +$end +*/ + + +# endif diff --git a/build-config/cppad/include/cppad/example/atomic_two/eigen_mat_inv.hpp b/build-config/cppad/include/cppad/example/atomic_two/eigen_mat_inv.hpp new file mode 100644 index 00000000..41b242e9 --- /dev/null +++ b/build-config/cppad/include/cppad/example/atomic_two/eigen_mat_inv.hpp @@ -0,0 +1,395 @@ +# ifndef CPPAD_EXAMPLE_ATOMIC_TWO_EIGEN_MAT_INV_HPP +# define CPPAD_EXAMPLE_ATOMIC_TWO_EIGEN_MAT_INV_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +/* +$begin atomic_two_eigen_mat_inv.hpp$$ +$spell + Eigen + Taylor +$$ + +$section atomic_two Eigen Matrix Inversion Class$$ + +$head Purpose$$ +Construct an atomic operation that computes the matrix inverse +$latex R = A^{-1}$$ +for any positive integer $latex p$$ +and invertible matrix $latex A \in \B{R}^{p \times p}$$. + +$head Matrix Dimensions$$ +This example puts the matrix dimension $latex p$$ +in the atomic function arguments, +instead of the $cref/constructor/atomic_two_ctor/$$, +so it can be different for different calls to the atomic function. + +$head Theory$$ + +$subhead Forward$$ +The zero order forward mode Taylor coefficient is give by +$latex \[ + R_0 = A_0^{-1} +\]$$ +For $latex k = 1 , \ldots$$, +the $th k$$ order Taylor coefficient of $latex A R$$ is given by +$latex \[ + 0 = \sum_{\ell=0}^k A_\ell R_{k-\ell} +\] $$ +Solving for $latex R_k$$ in terms of the coefficients +for $latex A$$ and the lower order coefficients for $latex R$$ we have +$latex \[ + R_k = - R_0 \left( \sum_{\ell=1}^k A_\ell R_{k-\ell} \right) +\] $$ +Furthermore, once we have $latex R_k$$ we can compute the sum using +$latex \[ + A_0 R_k = - \left( \sum_{\ell=1}^k A_\ell R_{k-\ell} \right) +\] $$ + + +$subhead Product of Three Matrices$$ +Suppose $latex \bar{E}$$ is the derivative of the +scalar value function $latex s(E)$$ with respect to $latex E$$; i.e., +$latex \[ + \bar{E}_{i,j} = \frac{ \partial s } { \partial E_{i,j} } +\] $$ +Also suppose that $latex t$$ is a scalar valued argument and +$latex \[ + E(t) = B(t) C(t) D(t) +\] $$ +It follows that +$latex \[ + E'(t) = B'(t) C(t) D(t) + B(t) C'(t) D(t) + B(t) C(t) D'(t) +\] $$ + +$latex \[ + (s \circ E)'(t) + = + \R{tr} [ \bar{E}^\R{T} E'(t) ] +\] $$ +$latex \[ + = + \R{tr} [ \bar{E}^\R{T} B'(t) C(t) D(t) ] + + \R{tr} [ \bar{E}^\R{T} B(t) C'(t) D(t) ] + + \R{tr} [ \bar{E}^\R{T} B(t) C(t) D'(t) ] +\] $$ +$latex \[ + = + \R{tr} [ B(t) D(t) \bar{E}^\R{T} B'(t) ] + + \R{tr} [ D(t) \bar{E}^\R{T} B(t) C'(t) ] + + \R{tr} [ \bar{E}^\R{T} B(t) C(t) D'(t) ] +\] $$ +$latex \[ + \bar{B} = \bar{E} (C D)^\R{T} \W{,} + \bar{C} = \B{R}^\R{T} \bar{E} D^\R{T} \W{,} + \bar{D} = (B C)^\R{T} \bar{E} +\] $$ + +$subhead Reverse$$ +For $latex k > 0$$, reverse mode +eliminates $latex R_k$$ and expresses the function values +$latex s$$ in terms of the coefficients of $latex A$$ +and the lower order coefficients of $latex R$$. +The effect on $latex \bar{R}_0$$ +(of eliminating $latex R_k$$) is +$latex \[ +\bar{R}_0 += \bar{R}_0 - \bar{R}_k \left( \sum_{\ell=1}^k A_\ell R_{k-\ell} \right)^\R{T} += \bar{R}_0 + \bar{R}_k ( A_0 R_k )^\R{T} +\] $$ +For $latex \ell = 1 , \ldots , k$$, +the effect on $latex \bar{R}_{k-\ell}$$ and $latex A_\ell$$ +(of eliminating $latex R_k$$) is +$latex \[ +\bar{A}_\ell = \bar{A}_\ell - R_0^\R{T} \bar{R}_k R_{k-\ell}^\R{T} +\] $$ +$latex \[ +\bar{R}_{k-\ell} = \bar{R}_{k-\ell} - ( R_0 A_\ell )^\R{T} \bar{R}_k +\] $$ +We note that +$latex \[ + R_0 '(t) A_0 (t) + R_0 (t) A_0 '(t) = 0 +\] $$ +$latex \[ + R_0 '(t) = - R_0 (t) A_0 '(t) R_0 (t) +\] $$ +The reverse mode formula that eliminates $latex R_0$$ is +$latex \[ + \bar{A}_0 + = \bar{A}_0 - R_0^\R{T} \bar{R}_0 R_0^\R{T} +\]$$ + +$nospell + +$head Start Class Definition$$ +$srccode%cpp% */ +# include +# include +# include + + + +/* %$$ +$head Public$$ + +$subhead Types$$ +$srccode%cpp% */ +namespace { // BEGIN_EMPTY_NAMESPACE + +template +class atomic_eigen_mat_inv : public CppAD::atomic_base { +public: + // ----------------------------------------------------------- + // type of elements during calculation of derivatives + typedef Base scalar; + // type of elements during taping + typedef CppAD::AD ad_scalar; + // type of matrix during calculation of derivatives + typedef Eigen::Matrix< + scalar, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor> matrix; + // type of matrix during taping + typedef Eigen::Matrix< + ad_scalar, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor > ad_matrix; +/* %$$ +$subhead Constructor$$ +$srccode%cpp% */ + // constructor + atomic_eigen_mat_inv(void) : CppAD::atomic_base( + "atom_eigen_mat_inv" , + CppAD::atomic_base::set_sparsity_enum + ) + { } +/* %$$ +$subhead op$$ +$srccode%cpp% */ + // use atomic operation to invert an AD matrix + ad_matrix op(const ad_matrix& arg) + { size_t nr = size_t( arg.rows() ); + size_t ny = nr * nr; + size_t nx = 1 + ny; + assert( nr == size_t( arg.cols() ) ); + // ------------------------------------------------------------------- + // packed version of arg + CPPAD_TESTVECTOR(ad_scalar) packed_arg(nx); + packed_arg[0] = ad_scalar( nr ); + for(size_t i = 0; i < ny; i++) + packed_arg[1 + i] = arg.data()[i]; + // ------------------------------------------------------------------- + // packed version of result = arg^{-1}. + // This is an atomic_base function call that CppAD uses to + // store the atomic operation on the tape. + CPPAD_TESTVECTOR(ad_scalar) packed_result(ny); + (*this)(packed_arg, packed_result); + // ------------------------------------------------------------------- + // unpack result matrix + ad_matrix result(nr, nr); + for(size_t i = 0; i < ny; i++) + result.data()[i] = packed_result[i]; + return result; + } + /* %$$ +$head Private$$ + +$subhead Variables$$ +$srccode%cpp% */ +private: + // ------------------------------------------------------------- + // one forward mode vector of matrices for argument and result + CppAD::vector f_arg_, f_result_; + // one reverse mode vector of matrices for argument and result + CppAD::vector r_arg_, r_result_; + // ------------------------------------------------------------- +/* %$$ +$subhead forward$$ +$srccode%cpp% */ + // forward mode routine called by CppAD + virtual bool forward( + // lowest order Taylor coefficient we are evaluating + size_t p , + // highest order Taylor coefficient we are evaluating + size_t q , + // which components of x are variables + const CppAD::vector& vx , + // which components of y are variables + CppAD::vector& vy , + // tx [ j * (q+1) + k ] is x_j^k + const CppAD::vector& tx , + // ty [ i * (q+1) + k ] is y_i^k + CppAD::vector& ty + ) + { size_t n_order = q + 1; + size_t nr = size_t( CppAD::Integer( tx[ 0 * n_order + 0 ] ) ); + size_t ny = nr * nr; +# ifndef NDEBUG + size_t nx = 1 + ny; +# endif + assert( vx.size() == 0 || nx == vx.size() ); + assert( vx.size() == 0 || ny == vy.size() ); + assert( nx * n_order == tx.size() ); + assert( ny * n_order == ty.size() ); + // + // ------------------------------------------------------------------- + // make sure f_arg_ and f_result_ are large enough + assert( f_arg_.size() == f_result_.size() ); + if( f_arg_.size() < n_order ) + { f_arg_.resize(n_order); + f_result_.resize(n_order); + // + for(size_t k = 0; k < n_order; k++) + { f_arg_[k].resize( long(nr), long(nr) ); + f_result_[k].resize( long(nr), long(nr) ); + } + } + // ------------------------------------------------------------------- + // unpack tx into f_arg_ + for(size_t k = 0; k < n_order; k++) + { // unpack arg values for this order + for(size_t i = 0; i < ny; i++) + f_arg_[k].data()[i] = tx[ (1 + i) * n_order + k ]; + } + // ------------------------------------------------------------------- + // result for each order + // (we could avoid recalculting f_result_[k] for k=0,...,p-1) + // + f_result_[0] = f_arg_[0].inverse(); + for(size_t k = 1; k < n_order; k++) + { // initialize sum + matrix f_sum = matrix::Zero( long(nr), long(nr) ); + // compute sum + for(size_t ell = 1; ell <= k; ell++) + f_sum -= f_arg_[ell] * f_result_[k-ell]; + // result_[k] = arg_[0]^{-1} * sum_ + f_result_[k] = f_result_[0] * f_sum; + } + // ------------------------------------------------------------------- + // pack result_ into ty + for(size_t k = 0; k < n_order; k++) + { for(size_t i = 0; i < ny; i++) + ty[ i * n_order + k ] = f_result_[k].data()[i]; + } + // ------------------------------------------------------------------- + // check if we are computing vy + if( vx.size() == 0 ) + return true; + // ------------------------------------------------------------------ + // This is a very dumb algorithm that over estimates which + // elements of the inverse are variables (which is not efficient). + bool var = false; + for(size_t i = 0; i < ny; i++) + var |= vx[1 + i]; + for(size_t i = 0; i < ny; i++) + vy[i] = var; + return true; + } +/* %$$ +$subhead reverse$$ +$srccode%cpp% */ + // reverse mode routine called by CppAD + virtual bool reverse( + // highest order Taylor coefficient that we are computing derivative of + size_t q , + // forward mode Taylor coefficients for x variables + const CppAD::vector& tx , + // forward mode Taylor coefficients for y variables + const CppAD::vector& ty , + // upon return, derivative of G[ F[ {x_j^k} ] ] w.r.t {x_j^k} + CppAD::vector& px , + // derivative of G[ {y_i^k} ] w.r.t. {y_i^k} + const CppAD::vector& py + ) + { size_t n_order = q + 1; + size_t nr = size_t( CppAD::Integer( tx[ 0 * n_order + 0 ] ) ); + size_t ny = nr * nr; +# ifndef NDEBUG + size_t nx = 1 + ny; +# endif + // + assert( nx * n_order == tx.size() ); + assert( ny * n_order == ty.size() ); + assert( px.size() == tx.size() ); + assert( py.size() == ty.size() ); + // ------------------------------------------------------------------- + // make sure f_arg_ is large enough + assert( f_arg_.size() == f_result_.size() ); + // must have previous run forward with order >= n_order + assert( f_arg_.size() >= n_order ); + // ------------------------------------------------------------------- + // make sure r_arg_, r_result_ are large enough + assert( r_arg_.size() == r_result_.size() ); + if( r_arg_.size() < n_order ) + { r_arg_.resize(n_order); + r_result_.resize(n_order); + // + for(size_t k = 0; k < n_order; k++) + { r_arg_[k].resize( long(nr), long(nr) ); + r_result_[k].resize( long(nr), long(nr) ); + } + } + // ------------------------------------------------------------------- + // unpack tx into f_arg_ + for(size_t k = 0; k < n_order; k++) + { // unpack arg values for this order + for(size_t i = 0; i < ny; i++) + f_arg_[k].data()[i] = tx[ (1 + i) * n_order + k ]; + } + // ------------------------------------------------------------------- + // unpack py into r_result_ + for(size_t k = 0; k < n_order; k++) + { for(size_t i = 0; i < ny; i++) + r_result_[k].data()[i] = py[ i * n_order + k ]; + } + // ------------------------------------------------------------------- + // initialize r_arg_ as zero + for(size_t k = 0; k < n_order; k++) + r_arg_[k] = matrix::Zero( long(nr), long(nr) ); + // ------------------------------------------------------------------- + // matrix reverse mode calculation + // + for(size_t k1 = n_order; k1 > 1; k1--) + { size_t k = k1 - 1; + // bar{R}_0 = bar{R}_0 + bar{R}_k (A_0 R_k)^T + r_result_[0] += + r_result_[k] * f_result_[k].transpose() * f_arg_[0].transpose(); + // + for(size_t ell = 1; ell <= k; ell++) + { // bar{A}_l = bar{A}_l - R_0^T bar{R}_k R_{k-l}^T + r_arg_[ell] -= f_result_[0].transpose() + * r_result_[k] * f_result_[k-ell].transpose(); + // bar{R}_{k-l} = bar{R}_{k-1} - (R_0 A_l)^T bar{R}_k + r_result_[k-ell] -= f_arg_[ell].transpose() + * f_result_[0].transpose() * r_result_[k]; + } + } + r_arg_[0] -= + f_result_[0].transpose() * r_result_[0] * f_result_[0].transpose(); + // ------------------------------------------------------------------- + // pack r_arg into px + for(size_t k = 0; k < n_order; k++) + { for(size_t i = 0; i < ny; i++) + px[ (1 + i) * n_order + k ] = r_arg_[k].data()[i]; + } + // + return true; + } +/* %$$ +$head End Class Definition$$ +$srccode%cpp% */ +}; // End of atomic_eigen_mat_inv class + +} // END_EMPTY_NAMESPACE +/* %$$ +$$ $comment end nospell$$ +$end +*/ + + +# endif diff --git a/build-config/cppad/include/cppad/example/atomic_two/eigen_mat_mul.hpp b/build-config/cppad/include/cppad/example/atomic_two/eigen_mat_mul.hpp new file mode 100644 index 00000000..d8a4c7e6 --- /dev/null +++ b/build-config/cppad/include/cppad/example/atomic_two/eigen_mat_mul.hpp @@ -0,0 +1,658 @@ +# ifndef CPPAD_EXAMPLE_ATOMIC_TWO_EIGEN_MAT_MUL_HPP +# define CPPAD_EXAMPLE_ATOMIC_TWO_EIGEN_MAT_MUL_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +/* +$begin atomic_two_eigen_mat_mul.hpp$$ +$spell + Eigen + Taylor + nr + nc +$$ + +$section atomic_two Eigen Matrix Multiply Class$$ + +$head See Also$$ +$cref atomic_three_mat_mul.hpp$$ + +$head Purpose$$ +Construct an atomic operation that computes the matrix product, +$latex R = A \times \B{R}$$ +for any positive integers $latex r$$, $latex m$$, $latex c$$, +and any $latex A \in \B{R}^{r \times m}$$, +$latex B \in \B{R}^{m \times c}$$. + +$head Matrix Dimensions$$ +This example puts the matrix dimensions in the atomic function arguments, +instead of the $cref/constructor/atomic_two_ctor/$$, so that they can +be different for different calls to the atomic function. +These dimensions are: +$table +$icode nr_left$$ + $cnext number of rows in the left matrix; i.e, $latex r$$ $rend +$icode n_middle$$ + $cnext rows in the left matrix and columns in right; i.e, $latex m$$ $rend +$icode nc_right$$ + $cnext number of columns in the right matrix; i.e., $latex c$$ +$tend + +$head Theory$$ + +$subhead Forward$$ +For $latex k = 0 , \ldots $$, the $th k$$ order Taylor coefficient +$latex R_k$$ is given by +$latex \[ + R_k = \sum_{\ell = 0}^{k} A_\ell B_{k-\ell} +\] $$ + +$subhead Product of Two Matrices$$ +Suppose $latex \bar{E}$$ is the derivative of the +scalar value function $latex s(E)$$ with respect to $latex E$$; i.e., +$latex \[ + \bar{E}_{i,j} = \frac{ \partial s } { \partial E_{i,j} } +\] $$ +Also suppose that $latex t$$ is a scalar valued argument and +$latex \[ + E(t) = C(t) D(t) +\] $$ +It follows that +$latex \[ + E'(t) = C'(t) D(t) + C(t) D'(t) +\] $$ + +$latex \[ + (s \circ E)'(t) + = + \R{tr} [ \bar{E}^\R{T} E'(t) ] +\] $$ +$latex \[ + = + \R{tr} [ \bar{E}^\R{T} C'(t) D(t) ] + + \R{tr} [ \bar{E}^\R{T} C(t) D'(t) ] +\] $$ +$latex \[ + = + \R{tr} [ D(t) \bar{E}^\R{T} C'(t) ] + + \R{tr} [ \bar{E}^\R{T} C(t) D'(t) ] +\] $$ +$latex \[ + \bar{C} = \bar{E} D^\R{T} \W{,} + \bar{D} = C^\R{T} \bar{E} +\] $$ + +$subhead Reverse$$ +Reverse mode eliminates $latex R_k$$ as follows: +for $latex \ell = 0, \ldots , k-1$$, +$latex \[ +\bar{A}_\ell = \bar{A}_\ell + \bar{R}_k B_{k-\ell}^\R{T} +\] $$ +$latex \[ +\bar{B}_{k-\ell} = \bar{B}_{k-\ell} + A_\ell^\R{T} \bar{R}_k +\] $$ + + +$nospell + +$head Start Class Definition$$ +$srccode%cpp% */ +# include +# include + + +/* %$$ +$head Public$$ + +$subhead Types$$ +$srccode%cpp% */ +namespace { // BEGIN_EMPTY_NAMESPACE + +template +class atomic_eigen_mat_mul : public CppAD::atomic_base { +public: + // ----------------------------------------------------------- + // type of elements during calculation of derivatives + typedef Base scalar; + // type of elements during taping + typedef CppAD::AD ad_scalar; + // type of matrix during calculation of derivatives + typedef Eigen::Matrix< + scalar, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor> matrix; + // type of matrix during taping + typedef Eigen::Matrix< + ad_scalar, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor > ad_matrix; +/* %$$ +$subhead Constructor$$ +$srccode%cpp% */ + // constructor + atomic_eigen_mat_mul(void) : CppAD::atomic_base( + "atom_eigen_mat_mul" , + CppAD::atomic_base::set_sparsity_enum + ) + { } +/* %$$ +$subhead op$$ +$srccode%cpp% */ + // use atomic operation to multiply two AD matrices + ad_matrix op( + const ad_matrix& left , + const ad_matrix& right ) + { size_t nr_left = size_t( left.rows() ); + size_t n_middle = size_t( left.cols() ); + size_t nc_right = size_t( right.cols() ); + assert( n_middle == size_t( right.rows() ) ); + size_t nx = 3 + (nr_left + nc_right) * n_middle; + size_t ny = nr_left * nc_right; + size_t n_left = nr_left * n_middle; + size_t n_right = n_middle * nc_right; + size_t n_result = nr_left * nc_right; + // + assert( 3 + n_left + n_right == nx ); + assert( n_result == ny ); + // ----------------------------------------------------------------- + // packed version of left and right + CPPAD_TESTVECTOR(ad_scalar) packed_arg(nx); + // + packed_arg[0] = ad_scalar( nr_left ); + packed_arg[1] = ad_scalar( n_middle ); + packed_arg[2] = ad_scalar( nc_right ); + for(size_t i = 0; i < n_left; i++) + packed_arg[3 + i] = left.data()[i]; + for(size_t i = 0; i < n_right; i++) + packed_arg[ 3 + n_left + i ] = right.data()[i]; + // ------------------------------------------------------------------ + // Packed version of result = left * right. + // This as an atomic_base funciton call that CppAD uses + // to store the atomic operation on the tape. + CPPAD_TESTVECTOR(ad_scalar) packed_result(ny); + (*this)(packed_arg, packed_result); + // ------------------------------------------------------------------ + // unpack result matrix + ad_matrix result(nr_left, nc_right); + for(size_t i = 0; i < n_result; i++) + result.data()[i] = packed_result[ i ]; + // + return result; + } +/* %$$ +$head Private$$ + +$subhead Variables$$ +$srccode%cpp% */ +private: + // ------------------------------------------------------------- + // one forward mode vector of matrices for left, right, and result + CppAD::vector f_left_, f_right_, f_result_; + // one reverse mode vector of matrices for left, right, and result + CppAD::vector r_left_, r_right_, r_result_; + // ------------------------------------------------------------- +/* %$$ +$subhead forward$$ +$srccode%cpp% */ + // forward mode routine called by CppAD + virtual bool forward( + // lowest order Taylor coefficient we are evaluating + size_t p , + // highest order Taylor coefficient we are evaluating + size_t q , + // which components of x are variables + const CppAD::vector& vx , + // which components of y are variables + CppAD::vector& vy , + // tx [ 3 + j * (q+1) + k ] is x_j^k + const CppAD::vector& tx , + // ty [ i * (q+1) + k ] is y_i^k + CppAD::vector& ty + ) + { size_t n_order = q + 1; + size_t nr_left = size_t( CppAD::Integer( tx[ 0 * n_order + 0 ] ) ); + size_t n_middle = size_t( CppAD::Integer( tx[ 1 * n_order + 0 ] ) ); + size_t nc_right = size_t( CppAD::Integer( tx[ 2 * n_order + 0 ] ) ); +# ifndef NDEBUG + size_t nx = 3 + (nr_left + nc_right) * n_middle; + size_t ny = nr_left * nc_right; +# endif + // + assert( vx.size() == 0 || nx == vx.size() ); + assert( vx.size() == 0 || ny == vy.size() ); + assert( nx * n_order == tx.size() ); + assert( ny * n_order == ty.size() ); + // + size_t n_left = nr_left * n_middle; + size_t n_right = n_middle * nc_right; + size_t n_result = nr_left * nc_right; + assert( 3 + n_left + n_right == nx ); + assert( n_result == ny ); + // + // ------------------------------------------------------------------- + // make sure f_left_, f_right_, and f_result_ are large enough + assert( f_left_.size() == f_right_.size() ); + assert( f_left_.size() == f_result_.size() ); + if( f_left_.size() < n_order ) + { f_left_.resize(n_order); + f_right_.resize(n_order); + f_result_.resize(n_order); + // + for(size_t k = 0; k < n_order; k++) + { f_left_[k].resize( long(nr_left), long(n_middle) ); + f_right_[k].resize( long(n_middle), long(nc_right) ); + f_result_[k].resize( long(nr_left), long(nc_right) ); + } + } + // ------------------------------------------------------------------- + // unpack tx into f_left and f_right + for(size_t k = 0; k < n_order; k++) + { // unpack left values for this order + for(size_t i = 0; i < n_left; i++) + f_left_[k].data()[i] = tx[ (3 + i) * n_order + k ]; + // + // unpack right values for this order + for(size_t i = 0; i < n_right; i++) + f_right_[k].data()[i] = tx[ ( 3 + n_left + i) * n_order + k ]; + } + // ------------------------------------------------------------------- + // result for each order + // (we could avoid recalculting f_result_[k] for k=0,...,p-1) + for(size_t k = 0; k < n_order; k++) + { // result[k] = sum_ell left[ell] * right[k-ell] + f_result_[k] = matrix::Zero( long(nr_left), long(nc_right) ); + for(size_t ell = 0; ell <= k; ell++) + f_result_[k] += f_left_[ell] * f_right_[k-ell]; + } + // ------------------------------------------------------------------- + // pack result_ into ty + for(size_t k = 0; k < n_order; k++) + { for(size_t i = 0; i < n_result; i++) + ty[ i * n_order + k ] = f_result_[k].data()[i]; + } + // ------------------------------------------------------------------ + // check if we are computing vy + if( vx.size() == 0 ) + return true; + // ------------------------------------------------------------------ + // compute variable information for y; i.e., vy + // (note that the constant zero times a variable is a constant) + scalar zero(0.0); + assert( n_order == 1 ); + for(size_t i = 0; i < nr_left; i++) + { for(size_t j = 0; j < nc_right; j++) + { bool var = false; + for(size_t ell = 0; ell < n_middle; ell++) + { // left information + size_t index = 3 + i * n_middle + ell; + bool var_left = vx[index]; + bool nz_left = var_left | + (f_left_[0]( long(i), long(ell) ) != zero); + // right information + index = 3 + n_left + ell * nc_right + j; + bool var_right = vx[index]; + bool nz_right = var_right | + (f_right_[0]( long(ell), long(j) ) != zero); + // effect of result + var |= var_left & nz_right; + var |= nz_left & var_right; + } + size_t index = i * nc_right + j; + vy[index] = var; + } + } + return true; + } +/* %$$ +$subhead reverse$$ +$srccode%cpp% */ + // reverse mode routine called by CppAD + virtual bool reverse( + // highest order Taylor coefficient that we are computing derivative of + size_t q , + // forward mode Taylor coefficients for x variables + const CppAD::vector& tx , + // forward mode Taylor coefficients for y variables + const CppAD::vector& ty , + // upon return, derivative of G[ F[ {x_j^k} ] ] w.r.t {x_j^k} + CppAD::vector& px , + // derivative of G[ {y_i^k} ] w.r.t. {y_i^k} + const CppAD::vector& py + ) + { size_t n_order = q + 1; + size_t nr_left = size_t( CppAD::Integer( tx[ 0 * n_order + 0 ] ) ); + size_t n_middle = size_t( CppAD::Integer( tx[ 1 * n_order + 0 ] ) ); + size_t nc_right = size_t( CppAD::Integer( tx[ 2 * n_order + 0 ] ) ); +# ifndef NDEBUG + size_t nx = 3 + (nr_left + nc_right) * n_middle; + size_t ny = nr_left * nc_right; +# endif + // + assert( nx * n_order == tx.size() ); + assert( ny * n_order == ty.size() ); + assert( px.size() == tx.size() ); + assert( py.size() == ty.size() ); + // + size_t n_left = nr_left * n_middle; + size_t n_right = n_middle * nc_right; + size_t n_result = nr_left * nc_right; + assert( 3 + n_left + n_right == nx ); + assert( n_result == ny ); + // ------------------------------------------------------------------- + // make sure f_left_, f_right_ are large enough + assert( f_left_.size() == f_right_.size() ); + assert( f_left_.size() == f_result_.size() ); + // must have previous run forward with order >= n_order + assert( f_left_.size() >= n_order ); + // ------------------------------------------------------------------- + // make sure r_left_, r_right_, and r_result_ are large enough + assert( r_left_.size() == r_right_.size() ); + assert( r_left_.size() == r_result_.size() ); + if( r_left_.size() < n_order ) + { r_left_.resize(n_order); + r_right_.resize(n_order); + r_result_.resize(n_order); + // + for(size_t k = 0; k < n_order; k++) + { r_left_[k].resize( long(nr_left), long(n_middle) ); + r_right_[k].resize( long(n_middle), long(nc_right) ); + r_result_[k].resize( long(nr_left), long(nc_right) ); + } + } + // ------------------------------------------------------------------- + // unpack tx into f_left and f_right + for(size_t k = 0; k < n_order; k++) + { // unpack left values for this order + for(size_t i = 0; i < n_left; i++) + f_left_[k].data()[i] = tx[ (3 + i) * n_order + k ]; + // + // unpack right values for this order + for(size_t i = 0; i < n_right; i++) + f_right_[k].data()[i] = tx[ (3 + n_left + i) * n_order + k ]; + } + // ------------------------------------------------------------------- + // unpack py into r_result_ + for(size_t k = 0; k < n_order; k++) + { for(size_t i = 0; i < n_result; i++) + r_result_[k].data()[i] = py[ i * n_order + k ]; + } + // ------------------------------------------------------------------- + // initialize r_left_ and r_right_ as zero + for(size_t k = 0; k < n_order; k++) + { r_left_[k] = matrix::Zero( long(nr_left), long(n_middle) ); + r_right_[k] = matrix::Zero( long(n_middle), long(nc_right) ); + } + // ------------------------------------------------------------------- + // matrix reverse mode calculation + for(size_t k1 = n_order; k1 > 0; k1--) + { size_t k = k1 - 1; + for(size_t ell = 0; ell <= k; ell++) + { // nr x nm = nr x nc * nc * nm + r_left_[ell] += r_result_[k] * f_right_[k-ell].transpose(); + // nm x nc = nm x nr * nr * nc + r_right_[k-ell] += f_left_[ell].transpose() * r_result_[k]; + } + } + // ------------------------------------------------------------------- + // pack r_left and r_right int px + for(size_t k = 0; k < n_order; k++) + { // dimensions are integer constants + px[ 0 * n_order + k ] = 0.0; + px[ 1 * n_order + k ] = 0.0; + px[ 2 * n_order + k ] = 0.0; + // + // pack left values for this order + for(size_t i = 0; i < n_left; i++) + px[ (3 + i) * n_order + k ] = r_left_[k].data()[i]; + // + // pack right values for this order + for(size_t i = 0; i < n_right; i++) + px[ (3 + i + n_left) * n_order + k] = r_right_[k].data()[i]; + } + // + return true; + } +/* %$$ +$subhead for_sparse_jac$$ +$srccode%cpp% */ + // forward Jacobian sparsity routine called by CppAD + virtual bool for_sparse_jac( + // number of columns in the matrix R + size_t q , + // sparsity pattern for the matrix R + const CppAD::vector< std::set >& r , + // sparsity pattern for the matrix S = f'(x) * R + CppAD::vector< std::set >& s , + const CppAD::vector& x ) + { + size_t nr_left = size_t( CppAD::Integer( x[0] ) ); + size_t n_middle = size_t( CppAD::Integer( x[1] ) ); + size_t nc_right = size_t( CppAD::Integer( x[2] ) ); +# ifndef NDEBUG + size_t nx = 3 + (nr_left + nc_right) * n_middle; + size_t ny = nr_left * nc_right; +# endif + // + assert( nx == r.size() ); + assert( ny == s.size() ); + // + size_t n_left = nr_left * n_middle; + for(size_t i = 0; i < nr_left; i++) + { for(size_t j = 0; j < nc_right; j++) + { // pack index for entry (i, j) in result + size_t i_result = i * nc_right + j; + s[i_result].clear(); + for(size_t ell = 0; ell < n_middle; ell++) + { // pack index for entry (i, ell) in left + size_t i_left = 3 + i * n_middle + ell; + // pack index for entry (ell, j) in right + size_t i_right = 3 + n_left + ell * nc_right + j; + // check if result of for this product is alwasy zero + // note that x is nan for commponents that are variables + bool zero = x[i_left] == Base(0.0) || x[i_right] == Base(0); + if( ! zero ) + { s[i_result] = + CppAD::set_union(s[i_result], r[i_left] ); + s[i_result] = + CppAD::set_union(s[i_result], r[i_right] ); + } + } + } + } + return true; + } +/* %$$ +$subhead rev_sparse_jac$$ +$srccode%cpp% */ + // reverse Jacobian sparsity routine called by CppAD + virtual bool rev_sparse_jac( + // number of columns in the matrix R^T + size_t q , + // sparsity pattern for the matrix R^T + const CppAD::vector< std::set >& rt , + // sparsoity pattern for the matrix S^T = f'(x)^T * R^T + CppAD::vector< std::set >& st , + const CppAD::vector& x ) + { + size_t nr_left = size_t( CppAD::Integer( x[0] ) ); + size_t n_middle = size_t( CppAD::Integer( x[1] ) ); + size_t nc_right = size_t( CppAD::Integer( x[2] ) ); + size_t nx = 3 + (nr_left + nc_right) * n_middle; +# ifndef NDEBUG + size_t ny = nr_left * nc_right; +# endif + // + assert( nx == st.size() ); + assert( ny == rt.size() ); + // + // initialize S^T as empty + for(size_t i = 0; i < nx; i++) + st[i].clear(); + + // sparsity for S(x)^T = f'(x)^T * R^T + size_t n_left = nr_left * n_middle; + for(size_t i = 0; i < nr_left; i++) + { for(size_t j = 0; j < nc_right; j++) + { // pack index for entry (i, j) in result + size_t i_result = i * nc_right + j; + st[i_result].clear(); + for(size_t ell = 0; ell < n_middle; ell++) + { // pack index for entry (i, ell) in left + size_t i_left = 3 + i * n_middle + ell; + // pack index for entry (ell, j) in right + size_t i_right = 3 + n_left + ell * nc_right + j; + // + st[i_left] = CppAD::set_union(st[i_left], rt[i_result]); + st[i_right] = CppAD::set_union(st[i_right], rt[i_result]); + } + } + } + return true; + } +/* %$$ +$subhead for_sparse_hes$$ +$srccode%cpp% */ + virtual bool for_sparse_hes( + // which components of x are variables for this call + const CppAD::vector& vx, + // sparsity pattern for the diagonal of R + const CppAD::vector& r , + // sparsity pattern for the vector S + const CppAD::vector& s , + // sparsity patternfor the Hessian H(x) + CppAD::vector< std::set >& h , + const CppAD::vector& x ) + { + size_t nr_left = size_t( CppAD::Integer( x[0] ) ); + size_t n_middle = size_t( CppAD::Integer( x[1] ) ); + size_t nc_right = size_t( CppAD::Integer( x[2] ) ); + size_t nx = 3 + (nr_left + nc_right) * n_middle; +# ifndef NDEBUG + size_t ny = nr_left * nc_right; +# endif + // + assert( vx.size() == nx ); + assert( r.size() == nx ); + assert( s.size() == ny ); + assert( h.size() == nx ); + // + // initilize h as empty + for(size_t i = 0; i < nx; i++) + h[i].clear(); + // + size_t n_left = nr_left * n_middle; + for(size_t i = 0; i < nr_left; i++) + { for(size_t j = 0; j < nc_right; j++) + { // pack index for entry (i, j) in result + size_t i_result = i * nc_right + j; + if( s[i_result] ) + { for(size_t ell = 0; ell < n_middle; ell++) + { // pack index for entry (i, ell) in left + size_t i_left = 3 + i * n_middle + ell; + // pack index for entry (ell, j) in right + size_t i_right = 3 + n_left + ell * nc_right + j; + if( r[i_left] & r[i_right] ) + { h[i_left].insert(i_right); + h[i_right].insert(i_left); + } + } + } + } + } + return true; + } +/* %$$ +$subhead rev_sparse_hes$$ +$srccode%cpp% */ + // reverse Hessian sparsity routine called by CppAD + virtual bool rev_sparse_hes( + // which components of x are variables for this call + const CppAD::vector& vx, + // sparsity pattern for S(x) = g'[f(x)] + const CppAD::vector& s , + // sparsity pattern for d/dx g[f(x)] = S(x) * f'(x) + CppAD::vector& t , + // number of columns in R, U(x), and V(x) + size_t q , + // sparsity pattern for R + const CppAD::vector< std::set >& r , + // sparsity pattern for U(x) = g^{(2)} [ f(x) ] * f'(x) * R + const CppAD::vector< std::set >& u , + // sparsity pattern for + // V(x) = f'(x)^T * U(x) + sum_{i=0}^{m-1} S_i(x) f_i^{(2)} (x) * R + CppAD::vector< std::set >& v , + // parameters as integers + const CppAD::vector& x ) + { + size_t nr_left = size_t( CppAD::Integer( x[0] ) ); + size_t n_middle = size_t( CppAD::Integer( x[1] ) ); + size_t nc_right = size_t( CppAD::Integer( x[2] ) ); + size_t nx = 3 + (nr_left + nc_right) * n_middle; +# ifndef NDEBUG + size_t ny = nr_left * nc_right; +# endif + // + assert( vx.size() == nx ); + assert( s.size() == ny ); + assert( t.size() == nx ); + assert( r.size() == nx ); + assert( v.size() == nx ); + // + // initilaize return sparsity patterns as false + for(size_t j = 0; j < nx; j++) + { t[j] = false; + v[j].clear(); + } + // + size_t n_left = nr_left * n_middle; + for(size_t i = 0; i < nr_left; i++) + { for(size_t j = 0; j < nc_right; j++) + { // pack index for entry (i, j) in result + size_t i_result = i * nc_right + j; + for(size_t ell = 0; ell < n_middle; ell++) + { // pack index for entry (i, ell) in left + size_t i_left = 3 + i * n_middle + ell; + // pack index for entry (ell, j) in right + size_t i_right = 3 + n_left + ell * nc_right + j; + // + // back propagate T(x) = S(x) * f'(x). + t[i_left] |= bool( s[i_result] ); + t[i_right] |= bool( s[i_result] ); + // + // V(x) = f'(x)^T * U(x) + sum_i S_i(x) * f_i''(x) * R + // U(x) = g''[ f(x) ] * f'(x) * R + // S_i(x) = g_i'[ f(x) ] + // + // back propagate f'(x)^T * U(x) + v[i_left] = CppAD::set_union(v[i_left], u[i_result] ); + v[i_right] = CppAD::set_union(v[i_right], u[i_result] ); + // + // back propagate S_i(x) * f_i''(x) * R + // (here is where we use vx to check for cross terms) + if( s[i_result] & vx[i_left] & vx[i_right] ) + { v[i_left] = CppAD::set_union(v[i_left], r[i_right] ); + v[i_right] = CppAD::set_union(v[i_right], r[i_left] ); + } + } + } + } + return true; + } +/* %$$ +$head End Class Definition$$ +$srccode%cpp% */ +}; // End of atomic_eigen_mat_mul class + +} // END_EMPTY_NAMESPACE +/* %$$ +$$ $comment end nospell$$ +$end +*/ + + +# endif diff --git a/build-config/cppad/include/cppad/example/base_adolc.hpp b/build-config/cppad/include/cppad/example/base_adolc.hpp new file mode 100644 index 00000000..009b8982 --- /dev/null +++ b/build-config/cppad/include/cppad/example/base_adolc.hpp @@ -0,0 +1,359 @@ +# ifndef CPPAD_EXAMPLE_BASE_ADOLC_HPP +# define CPPAD_EXAMPLE_BASE_ADOLC_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ +/* +$begin base_adolc.hpp$$ +$spell + stringstream + struct + string + setprecision + str + valgrind + azmul + expm1 + atanh + acosh + asinh + erf + erfc + ifndef + define + endif + Rel + codassign + eps + std + abs_geq + fabs + cppad.hpp + undef + Lt + Le + Eq + Ge + Gt + namespace + cassert + condassign + hpp + bool + const + Adolc + adouble + CondExpOp + inline + enum + CppAD + pow + acos + asin + atan + cos + cosh + exp + sqrt + atrig +$$ + + +$section Enable use of AD where Base is Adolc's adouble Type$$ + +$head Syntax$$ +$codei%# include +%$$ +$children% + example/general/mul_level_adolc.cpp +%$$ + +$head Example$$ +The file $cref mul_level_adolc.cpp$$ contains an example use of +Adolc's $code adouble$$ type for a CppAD $icode Base$$ type. +The file $cref mul_level_adolc_ode.cpp$$ contains a more realistic +(and complex) example. + +$head Include Files$$ +This file $code base_adolc.hpp$$ requires $code adouble$$ to be defined. +In addition, it is included before $code $$, +but it needs to include parts of CppAD that are used by this file. +This is done with the following include commands: +$srccode%cpp% */ +# include +# include +/* %$$ + +$head CondExpOp$$ +The type $code adouble$$ supports a conditional assignment function +with the syntax +$codei% + condassign(%a%, %b%, %c%, %d%) +%$$ +which evaluates to +$codei% + %a% = (%b% > 0) ? %c% : %d%; +%$$ +This enables one to include conditionals in the recording of +$code adouble$$ operations and later evaluation for different +values of the independent variables +(in the same spirit as the CppAD $cref CondExp$$ function). +$srccode%cpp% */ +namespace CppAD { + inline adouble CondExpOp( + enum CppAD::CompareOp cop , + const adouble &left , + const adouble &right , + const adouble &trueCase , + const adouble &falseCase ) + { adouble result; + switch( cop ) + { + case CompareLt: // left < right + condassign(result, right - left, trueCase, falseCase); + break; + + case CompareLe: // left <= right + condassign(result, left - right, falseCase, trueCase); + break; + + case CompareEq: // left == right + condassign(result, left - right, falseCase, trueCase); + condassign(result, right - left, falseCase, result); + break; + + case CompareGe: // left >= right + condassign(result, right - left, falseCase, trueCase); + break; + + case CompareGt: // left > right + condassign(result, left - right, trueCase, falseCase); + break; + default: + CppAD::ErrorHandler::Call( + true , __LINE__ , __FILE__ , + "CppAD::CondExp", + "Error: for unknown reason." + ); + result = trueCase; + } + return result; + } +} +/* %$$ + +$head CondExpRel$$ +The $cref/CPPAD_COND_EXP_REL/base_cond_exp/CondExpRel/$$ macro invocation +$srccode%cpp% */ +namespace CppAD { + CPPAD_COND_EXP_REL(adouble) +} +/* %$$ + +$head EqualOpSeq$$ +The Adolc user interface does not specify a way to determine if +two $code adouble$$ variables correspond to the same operations sequence. +Make $code EqualOpSeq$$ an error if it gets used: +$srccode%cpp% */ +namespace CppAD { + inline bool EqualOpSeq(const adouble &x, const adouble &y) + { CppAD::ErrorHandler::Call( + true , __LINE__ , __FILE__ , + "CppAD::EqualOpSeq(x, y)", + "Error: adouble does not support EqualOpSeq." + ); + return false; + } +} +/* %$$ + +$head Identical$$ +The Adolc user interface does not specify a way to determine if an +$code adouble$$ depends on the independent variables. +To be safe (but slow) return $code false$$ in all the cases below. +$srccode%cpp% */ +namespace CppAD { + inline bool IdenticalCon(const adouble &x) + { return false; } + inline bool IdenticalZero(const adouble &x) + { return false; } + inline bool IdenticalOne(const adouble &x) + { return false; } + inline bool IdenticalEqualCon(const adouble &x, const adouble &y) + { return false; } +} +/* %$$ + +$head Integer$$ +$srccode%cpp% */ + inline int Integer(const adouble &x) + { return static_cast( x.getValue() ); } +/* %$$ + +$head azmul$$ +$srccode%cpp% */ +namespace CppAD { + CPPAD_AZMUL( adouble ) +} +/* %$$ + +$head Ordered$$ +$srccode%cpp% */ +namespace CppAD { + inline bool GreaterThanZero(const adouble &x) + { return (x > 0); } + inline bool GreaterThanOrZero(const adouble &x) + { return (x >= 0); } + inline bool LessThanZero(const adouble &x) + { return (x < 0); } + inline bool LessThanOrZero(const adouble &x) + { return (x <= 0); } + inline bool abs_geq(const adouble& x, const adouble& y) + { return fabs(x) >= fabs(y); } +} +/* %$$ + +$head Unary Standard Math$$ +The following $cref/required/base_require/$$ functions +are defined by the Adolc package for the $code adouble$$ base case: +$pre +$$ +$code acos$$, +$code acosh$$, +$code asin$$, +$code asinh$$, +$code atan$$, +$code atanh$$, +$code cos$$, +$code cosh$$, +$code erf$$, +$code exp$$, +$code fabs$$, +$code log$$, +$code sin$$, +$code sinh$$, +$code sqrt$$, +$code tan$$. + +$head erfc$$ +If you provide $code --enable-atrig-erf$$ on the configure command line, +the adolc package supports all the c++11 math functions except +$code erfc$$, $code expm1$$, and $code log1p$$. +For the reason, we make using $code erfc$$ an error: +$srccode%cpp% */ +namespace CppAD { +# define CPPAD_BASE_ADOLC_NO_SUPPORT(fun) \ + inline adouble fun(const adouble& x) \ + { CPPAD_ASSERT_KNOWN( \ + false, \ + #fun ": adolc does not support this function" \ + ); \ + return 0.0; \ + } + CPPAD_BASE_ADOLC_NO_SUPPORT(erfc) + CPPAD_BASE_ADOLC_NO_SUPPORT(expm1) + CPPAD_BASE_ADOLC_NO_SUPPORT(log1p) +# undef CPPAD_BASE_ADOLC_NO_SUPPORT +} +/* %$$ + +$head sign$$ +This $cref/required/base_require/$$ function is defined using the +$code codassign$$ function so that its $code adouble$$ operation sequence +does not depend on the value of $icode x$$. +$srccode%cpp% */ +namespace CppAD { + inline adouble sign(const adouble& x) + { adouble s_plus, s_minus, half(.5); + // set s_plus to sign(x)/2, except for case x == 0, s_plus = -.5 + condassign(s_plus, +x, -half, +half); + // set s_minus to -sign(x)/2, except for case x == 0, s_minus = -.5 + condassign(s_minus, -x, -half, +half); + // set s to sign(x) + return s_plus - s_minus; + } +} +/* %$$ + +$head abs$$ +This $cref/required/base_require/$$ function uses the adolc $code fabs$$ +function: +$srccode%cpp% */ +namespace CppAD { + inline adouble abs(const adouble& x) + { return fabs(x); } +} +/* %$$ + +$head pow$$ +This $cref/required/base_require/$$ function +is defined by the Adolc package for the $code adouble$$ base case. + +$head numeric_limits$$ +The following defines the CppAD $cref numeric_limits$$ +for the type $code adouble$$: +$srccode%cpp% */ +namespace CppAD { + CPPAD_NUMERIC_LIMITS(double, adouble) +} +/* %$$ + +$head to_string$$ +The following defines the CppAD $cref to_string$$ function +for the type $code adouble$$: +$srccode%cpp% */ +namespace CppAD { + template <> struct to_string_struct + { std::string operator()(const adouble& x) + { std::stringstream os; + int n_digits = 1 + std::numeric_limits::digits10; + os << std::setprecision(n_digits); + os << x.value(); + return os.str(); + } + }; +} +/* %$$ + +$head hash_code$$ +It appears that an $code adouble$$ object can have fields +that are not initialized. +This results in a $code valgrind$$ error when these fields are used by the +$cref/default/base_hash/Default/$$ hashing function. +For this reason, the $code adouble$$ class overrides the default definition. +$srccode|cpp| */ +namespace CppAD { + inline unsigned short hash_code(const adouble& x) + { unsigned short code = 0; + double value = x.value(); + if( value == 0.0 ) + return code; + double log_x = std::log( fabs( value ) ); + // assume log( std::numeric_limits::max() ) is near 700 + code = static_cast( + (CPPAD_HASH_TABLE_SIZE / 700 + 1) * log_x + ); + code = code % CPPAD_HASH_TABLE_SIZE; + return code; + } +} +/* |$$ +Note that after the hash codes match, the +$cref/Identical/base_adolc.hpp/Identical/$$ function will be used +to make sure two values are the same and one can replace the other. +A more sophisticated implementation of the $code Identical$$ function +would detect which $code adouble$$ values depend on the +$code adouble$$ independent variables (and hence can change). + + +$end +*/ +# endif diff --git a/build-config/cppad/include/cppad/example/code_gen_fun.hpp b/build-config/cppad/include/cppad/example/code_gen_fun.hpp new file mode 100644 index 00000000..6f7efdc5 --- /dev/null +++ b/build-config/cppad/include/cppad/example/code_gen_fun.hpp @@ -0,0 +1,62 @@ +# ifndef CPPAD_EXAMPLE_CODE_GEN_FUN_HPP +# define CPPAD_EXAMPLE_CODE_GEN_FUN_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell + + CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + + This Source Code may also be made available under the following + Secondary License when the conditions for such availability set forth + in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +-------------------------------------------------------------------------- */ +// BEGIN C++ +# include + +class code_gen_fun { +public: + // type of evaluation for Jacobians (possibly Hessians in the future) + enum evaluation_enum { none_enum, dense_enum, sparse_enum }; +private: + // dynamic_lib_ + std::unique_ptr< CppAD::cg::DynamicLib > dynamic_lib_; + // + // model_ (contains a reference to dynamic_lib_) + std::unique_ptr< CppAD::cg::GenericModel > model_; + // +public: + // ----------------------------------------------------------------------- + // constructors + // ----------------------------------------------------------------------- + // fun_name() + code_gen_fun(void); + // + // fun_name( file_name ) + code_gen_fun(const std::string& file_name); + // + // fun_name(file_name, cg_fun, eval_jac) + code_gen_fun( + const std::string& file_name , + CppAD::ADFun< CppAD::cg::CG >& cg_fun , + evaluation_enum eval_jac = none_enum + ); + // ----------------------------------------------------------------------- + // operations + // ----------------------------------------------------------------------- + // swap(other_fun) + void swap(code_gen_fun& other_fun); + // + // y = fun_name(x) + CppAD::vector operator()(const CppAD::vector & x); + // + // J = fun_name.jacobian(x) + CppAD::vector jacobian(const CppAD::vector & x); + // + // Jrcv = fun_name.sparse_jacobian(x) + CppAD::sparse_rcv< CppAD::vector, CppAD::vector > + sparse_jacobian(const CppAD::vector& x); +}; +// END C++ + +# endif diff --git a/build-config/cppad/include/cppad/example/cppad_eigen.hpp b/build-config/cppad/include/cppad/example/cppad_eigen.hpp new file mode 100644 index 00000000..a7b06f29 --- /dev/null +++ b/build-config/cppad/include/cppad/example/cppad_eigen.hpp @@ -0,0 +1,195 @@ +# ifndef CPPAD_EXAMPLE_CPPAD_EIGEN_HPP +# define CPPAD_EXAMPLE_CPPAD_EIGEN_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ +// cppad.hpp gets included at the end +# define EIGEN_MATRIXBASE_PLUGIN +# include + +/* +$begin cppad_eigen.hpp$$ +$spell + impl + typename + Real Real + inline + neg + eps + atan + Num + acos + asin + CppAD + std::numeric + enum + Mul + Eigen + cppad.hpp + namespace + struct + typedef + const + imag + sqrt + exp + cos +$$ +$section Enable Use of Eigen Linear Algebra Package with CppAD$$ + +$head Syntax$$ +$codei%# include +%$$ +$children% + include/cppad/example/eigen_plugin.hpp% + example/general/eigen_array.cpp% + example/general/eigen_det.cpp +%$$ + +$head Purpose$$ +Enables the use of the $cref eigen$$ +linear algebra package with the type $icode%AD<%Base%>%$$; see +$href% + https://eigen.tuxfamily.org/dox/TopicCustomizing_CustomScalar.html% + custom scalar types +%$$. + +$head Example$$ +The files $cref eigen_array.cpp$$ and $cref eigen_det.cpp$$ +contain an example and test of this include file. +They return true if they succeed and false otherwise. + +$head Include Files$$ +The file $code $$ is included before +these definitions and $code $$ is included after. + +$head CppAD Declarations$$ +First declare some items that are defined by cppad.hpp: +$srccode%cpp% */ +namespace CppAD { + // AD + template class AD; + // numeric_limits + template class numeric_limits; +} +/* %$$ +$head Eigen NumTraits$$ +Eigen needs the following definitions to work properly +with $codei%AD<%Base%>%$$ scalars: +$srccode%cpp% */ +namespace Eigen { + template struct NumTraits< CppAD::AD > + { // type that corresponds to the real part of an AD value + typedef CppAD::AD Real; + // type for AD operations that result in non-integer values + typedef CppAD::AD NonInteger; + // type to use for numeric literals such as "2" or "0.5". + typedef CppAD::AD Literal; + // type for nested value inside an AD expression tree + typedef CppAD::AD Nested; + + enum { + // does not support complex Base types + IsComplex = 0 , + // does not support integer Base types + IsInteger = 0 , + // only support signed Base types + IsSigned = 1 , + // must initialize an AD object + RequireInitialization = 1 , + // computational cost of the corresponding operations + ReadCost = 1 , + AddCost = 2 , + MulCost = 2 + }; + + // machine epsilon with type of real part of x + // (use assumption that Base is not complex) + static CppAD::AD epsilon(void) + { return CppAD::numeric_limits< CppAD::AD >::epsilon(); } + + // relaxed version of machine epsilon for comparison of different + // operations that should result in the same value + static CppAD::AD dummy_precision(void) + { return 100. * + CppAD::numeric_limits< CppAD::AD >::epsilon(); + } + + // minimum normalized positive value + static CppAD::AD lowest(void) + { return CppAD::numeric_limits< CppAD::AD >::min(); } + + // maximum finite value + static CppAD::AD highest(void) + { return CppAD::numeric_limits< CppAD::AD >::max(); } + + // number of decimal digits that can be represented without change. + static int digits10(void) + { return CppAD::numeric_limits< CppAD::AD >::digits10; } + }; +} +/* %$$ +$head CppAD Namespace$$ +Eigen also needs the following definitions to work properly +with $codei%AD<%Base%>%$$ scalars: +$srccode%cpp% */ +namespace CppAD { + // functions that return references + template const AD& conj(const AD& x) + { return x; } + template const AD& real(const AD& x) + { return x; } + + // functions that return values (note abs is defined by cppad.hpp) + template AD imag(const AD& x) + { return CppAD::AD(0.); } + template AD abs2(const AD& x) + { return x * x; } +} + +/* %$$ +$head eigen_vector$$ +The class $code CppAD::eigen_vector$$ is a wrapper for Eigen column vectors +so that they are $cref/simple vectors/SimpleVector/$$. +To be specific, it converts $code Eigen::Index$$ arguments and +return values to $code size_t$$. +$srccode%cpp% */ +namespace CppAD { + template + class eigen_vector : public Eigen::Matrix { + private: + // base_class + typedef Eigen::Matrix base_class; + public: + // constructor + eigen_vector(size_t n) : base_class( Eigen::Index(n) ) + { } + eigen_vector(void) : base_class() + { } + // operator[] + Scalar& operator[](size_t i) + { return base_class::operator[]( Eigen::Index(i) ); } + const Scalar& operator[](size_t i) const + { return base_class::operator[]( Eigen::Index(i) ); } + // size + size_t size(void) const + { return size_t( base_class::size() ); } + // resize + void resize(size_t n) + { base_class::resize( Eigen::Index(n) ); } + }; +} +// +# include +/* %$$ +$end +*/ +# endif diff --git a/build-config/cppad/include/cppad/example/eigen_plugin.hpp b/build-config/cppad/include/cppad/example/eigen_plugin.hpp new file mode 100644 index 00000000..73f1aeec --- /dev/null +++ b/build-config/cppad/include/cppad/example/eigen_plugin.hpp @@ -0,0 +1,28 @@ +# ifndef CPPAD_EXAMPLE_EIGEN_PLUGIN_HPP +# define CPPAD_EXAMPLE_EIGEN_PLUGIN_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-17 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ +/*$ +$begin eigen_plugin.hpp$$ +$spell + eigen_plugin.hpp + typedef +$$ + +$section Source Code for eigen_plugin.hpp$$ +$srccode%cpp% */ +// Declaration needed, before eigen-3.3.3, so Eigen vector is a simple vector +typedef Scalar value_type; +/* %$$ +$end +*/ +# endif diff --git a/build-config/cppad/include/cppad/ipopt/solve.hpp b/build-config/cppad/include/cppad/ipopt/solve.hpp new file mode 100644 index 00000000..f353621b --- /dev/null +++ b/build-config/cppad/include/cppad/ipopt/solve.hpp @@ -0,0 +1,639 @@ +# ifndef CPPAD_IPOPT_SOLVE_HPP +# define CPPAD_IPOPT_SOLVE_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ +/* +$begin ipopt_solve$$ +$spell + Jacobian + Jacobians + retape + Bvector + bool + infeasibility + const + cpp + cppad + doesn't + ADvector + eval + fg + gl + gu + hpp + inf + ipopt + maxiter + naninf + nf + ng + nx + obj + optimizer + std + xi + xl + xu + zl + zu + cmake +$$ + +$section Use Ipopt to Solve a Nonlinear Programming Problem$$ + +$head Syntax$$ +$codei%# include +%$$ +$codei%ipopt::solve( + %options%, %xi%, %xl%, %xu%, %gl%, %gu%, %fg_eval%, %solution% +)%$$ + +$head Purpose$$ +The function $code ipopt::solve$$ solves nonlinear programming +problems of the form +$latex \[ +\begin{array}{rll} +{\rm minimize} & f (x) +\\ +{\rm subject \; to} & gl \leq g(x) \leq gu +\\ + & xl \leq x \leq xu +\end{array} +\] $$ +This is done using +$href% + http://www.coin-or.org/projects/Ipopt.xml% + Ipopt +%$$ +optimizer and CppAD for the derivative and sparsity calculations. + +$head Include File$$ +If $cref/include_ipopt/cmake/include_ipopt/$$ is on the cmake command line, +the file $code cppad/ipopt/solve.hpp$$ is included by $code cppad/cppad.hpp$$. +Otherwise, +$code cppad/ipopt/solve.hpp$$ can be included directly +(If $code cppad/cppad.hpp$$ has not yet been included, +$code cppad/ipopt/solve.hpp$$ will automatically include it.) + +$head Bvector$$ +The type $icode Bvector$$ must be a $cref SimpleVector$$ class with +$cref/elements of type/SimpleVector/Elements of Specified Type/$$ +$code bool$$. + +$head Dvector$$ +The type $icode DVector$$ must be a $cref SimpleVector$$ class with +$cref/elements of type/SimpleVector/Elements of Specified Type/$$ +$code double$$. + +$head options$$ +The argument $icode options$$ has prototype +$codei% + const std::string %options% +%$$ +It contains a list of options. +Each option, including the last option, +is terminated by the $code '\n'$$ character. +Each line consists of two or three tokens separated by one or more spaces. + +$subhead Retape$$ +You can set the retape flag with the following syntax: +$codei% + Retape %value% +%$$ +If the value is $code true$$, $code ipopt::solve$$ with retape the +$cref/operation sequence/glossary/Operation/Sequence/$$ for each +new value of $icode x$$. +If the value is $code false$$, $code ipopt::solve$$ +will tape the operation sequence at the value +of $icode xi$$ and use that sequence for the entire optimization process. +The default value is $code false$$. + +$subhead Sparse$$ +You can set the sparse Jacobian and Hessian flag with the following syntax: +$codei% + Sparse %value% %direction% +%$$ +If the value is $code true$$, $code ipopt::solve$$ will use a sparse +matrix representation for the computation of Jacobians and Hessians. +Otherwise, it will use a full matrix representation for +these calculations. +The default for $icode value$$ is $code false$$. +If sparse is true, retape must be false. +$pre + +$$ +It is unclear if $cref sparse_jacobian$$ would be faster user +forward or reverse mode so you are able to choose the direction. +If +$codei% + %value% == true && %direction% == forward +%$$ +the Jacobians will be calculated using $code SparseJacobianForward$$. +If +$codei% + %value% == true && %direction% == reverse +%$$ +the Jacobians will be calculated using $code SparseJacobianReverse$$. + +$subhead String$$ +You can set any Ipopt string option using a line with the following syntax: +$codei% + String %name% %value% +%$$ +Here $icode name$$ is any valid Ipopt string option +and $icode value$$ is its setting. + +$subhead Numeric$$ +You can set any Ipopt numeric option using a line with the following syntax: +$codei% + Numeric %name% %value% +%$$ +Here $icode name$$ is any valid Ipopt numeric option +and $icode value$$ is its setting. + +$subhead Integer$$ +You can set any Ipopt integer option using a line with the following syntax: +$codei% + Integer %name% %value% +%$$ +Here $icode name$$ is any valid Ipopt integer option +and $icode value$$ is its setting. + +$head xi$$ +The argument $icode xi$$ has prototype +$codei% + const %Vector%& %xi% +%$$ +and its size is equal to $icode nx$$. +It specifies the initial point where Ipopt starts the optimization process. + +$head xl$$ +The argument $icode xl$$ has prototype +$codei% + const %Vector%& %xl% +%$$ +and its size is equal to $icode nx$$. +It specifies the lower limits for the argument in the optimization problem. + +$head xu$$ +The argument $icode xu$$ has prototype +$codei% + const %Vector%& %xu% +%$$ +and its size is equal to $icode nx$$. +It specifies the upper limits for the argument in the optimization problem. + +$head gl$$ +The argument $icode gl$$ has prototype +$codei% + const %Vector%& %gl% +%$$ +and its size is equal to $icode ng$$. +It specifies the lower limits for the constraints in the optimization problem. + +$head gu$$ +The argument $icode gu$$ has prototype +$codei% + const %Vector%& %gu% +%$$ +and its size is equal to $icode ng$$. +It specifies the upper limits for the constraints in the optimization problem. + +$head fg_eval$$ +The argument $icode fg_eval$$ has prototype +$codei% + %FG_eval% %fg_eval% +%$$ +where the class $icode FG_eval$$ is unspecified except for the fact that +it supports the syntax +$codei% + %FG_eval%::ADvector + %fg_eval%(%fg%, %x%) +%$$ +The type $icode ADvector$$ +and the arguments to $icode fg$$, $icode x$$ have the following meaning: + +$subhead ADvector$$ +The type $icode%FG_eval%::ADvector%$$ must be a $cref SimpleVector$$ class with +$cref/elements of type/SimpleVector/Elements of Specified Type/$$ +$code AD$$. + +$subhead x$$ +The $icode fg_eval$$ argument $icode x$$ has prototype +$codei% + const %ADvector%& %x% +%$$ +where $icode%nx% = %x%.size()%$$. + +$subhead fg$$ +The $icode fg_eval$$ argument $icode fg$$ has prototype +$codei% + %ADvector%& %fg% +%$$ +where $codei%1 + %ng% = %fg%.size()%$$. +The input value of the elements of $icode fg$$ does not matter. +Upon return from $icode fg_eval$$, +$codei% + %fg%[0] =%$$ $latex f (x)$$ $codei% +%$$ +and for $latex i = 0, \ldots , ng-1$$, +$codei% + %fg%[1 + %i%] =%$$ $latex g_i (x)$$ + +$head solution$$ +The argument $icode solution$$ has prototype +$codei% + ipopt::solve_result<%Dvector%>& %solution% +%$$ +After the optimization process is completed, $icode solution$$ contains +the following information: + +$subhead status$$ +The $icode status$$ field of $icode solution$$ has prototype +$codei% + ipopt::solve_result<%Dvector%>::status_type %solution%.status +%$$ +It is the final Ipopt status for the optimizer. +Here is a list of the possible values for the status: + +$table +$icode status$$ $cnext Meaning +$rnext +not_defined $cnext +The optimizer did not return a final status for this problem. +$rnext +unknown $cnext +The status returned by the optimizer is not defined in the Ipopt +documentation for $code finalize_solution$$. +$rnext +success $cnext +Algorithm terminated successfully at a point satisfying the convergence +tolerances (see Ipopt options). +$rnext +maxiter_exceeded $cnext +The maximum number of iterations was exceeded (see Ipopt options). +$rnext +stop_at_tiny_step $cnext +Algorithm terminated because progress was very slow. +$rnext +stop_at_acceptable_point $cnext +Algorithm stopped at a point that was converged, +not to the 'desired' tolerances, but to 'acceptable' tolerances +(see Ipopt options). +$rnext +local_infeasibility $cnext +Algorithm converged to a non-feasible point +(problem may have no solution). +$rnext +user_requested_stop $cnext +This return value should not happen. +$rnext +diverging_iterates $cnext +It the iterates are diverging. +$rnext +restoration_failure $cnext +Restoration phase failed, algorithm doesn't know how to proceed. +$rnext +error_in_step_computation $cnext +An unrecoverable error occurred while Ipopt tried to +compute the search direction. +$rnext +invalid_number_detected $cnext +Algorithm received an invalid number (such as $code nan$$ or $code inf$$) +from the users function $icode%fg_info%.eval%$$ or from the CppAD evaluations +of its derivatives +(see the Ipopt option $code check_derivatives_for_naninf$$). +$rnext +internal_error $cnext +An unknown Ipopt internal error occurred. +Contact the Ipopt authors through the mailing list. +$tend + +$subhead x$$ +The $code x$$ field of $icode solution$$ has prototype +$codei% + %Vector% %solution%.x +%$$ +and its size is equal to $icode nx$$. +It is the final $latex x$$ value for the optimizer. + +$subhead zl$$ +The $code zl$$ field of $icode solution$$ has prototype +$codei% + %Vector% %solution%.zl +%$$ +and its size is equal to $icode nx$$. +It is the final Lagrange multipliers for the +lower bounds on $latex x$$. + +$subhead zu$$ +The $code zu$$ field of $icode solution$$ has prototype +$codei% + %Vector% %solution%.zu +%$$ +and its size is equal to $icode nx$$. +It is the final Lagrange multipliers for the +upper bounds on $latex x$$. + +$subhead g$$ +The $code g$$ field of $icode solution$$ has prototype +$codei% + %Vector% %solution%.g +%$$ +and its size is equal to $icode ng$$. +It is the final value for the constraint function $latex g(x)$$. + +$subhead lambda$$ +The $code lambda$$ field of $icode solution$$ has prototype +$codei% + %Vector%> %solution%.lambda +%$$ +and its size is equal to $icode ng$$. +It is the final value for the +Lagrange multipliers corresponding to the constraint function. + +$subhead obj_value$$ +The $code obj_value$$ field of $icode solution$$ has prototype +$codei% + double %solution%.obj_value +%$$ +It is the final value of the objective function $latex f(x)$$. + +$children% + example/ipopt_solve/get_started.cpp% + example/ipopt_solve/retape.cpp% + example/ipopt_solve/ode_inverse.cpp +%$$ +$head Example$$ +All the examples return true if it succeeds and false otherwise. + +$subhead get_started$$ +The file +$cref%example/ipopt_solve/get_started.cpp%ipopt_solve_get_started.cpp%$$ +is an example and test of $code ipopt::solve$$ +taken from the Ipopt manual. + +$subhead retape$$ +The file +$cref%example/ipopt_solve/retape.cpp%ipopt_solve_retape.cpp%$$ +demonstrates when it is necessary to specify +$cref/retape/ipopt_solve/options/Retape/$$ as true. + +$subhead ode_inverse$$ +The file +$cref%example/ipopt_solve/ode_inverse.cpp%ipopt_solve_ode_inverse.cpp%$$ +demonstrates using Ipopt to solve for parameters in an ODE model. + +$end +------------------------------------------------------------------------------- +*/ +# include +# include + +namespace CppAD { // BEGIN_CPPAD_NAMESPACE +namespace ipopt { +/*! +\file solve.hpp +\brief Implement the ipopt::solve Nonlinear Programming Solver +*/ + +/*! +Use Ipopt to Solve a Nonlinear Programming Problem + +\tparam Bvector +simple vector class with elements of type bool. + +\tparam Dvector +simple vector class with elements of type double. + +\tparam FG_eval +function object used to evaluate f(x) and g(x); see fg_eval below. +It must also support +\code + FG_eval::ADvector +\endcode +to dentify the type used for the arguments to fg_eval. + +\param options +list of options, one for each line. +Ipopt options (are optional) and have one of the following forms +\code + String name value + Numeric name value + Integer name value +\endcode +The following other possible options are listed below: +\code + Retape value +\endcode + + +\param xi +initial argument value to start optimization procedure at. + +\param xl +lower limit for argument during optimization + +\param xu +upper limit for argument during optimization + +\param gl +lower limit for g(x) during optimization. + +\param gu +upper limit for g(x) during optimization. + +\param fg_eval +function that evaluates the objective and constraints using the syntax +\code + fg_eval(fg, x) +\endcode + +\param solution +structure that holds the solution of the optimization. +*/ +template +void solve( + const std::string& options , + const Dvector& xi , + const Dvector& xl , + const Dvector& xu , + const Dvector& gl , + const Dvector& gu , + FG_eval& fg_eval , + ipopt::solve_result& solution ) +{ bool ok = true; + + typedef typename FG_eval::ADvector ADvector; + + CPPAD_ASSERT_KNOWN( + xi.size() == xl.size() && xi.size() == xu.size() , + "ipopt::solve: size of xi, xl, and xu are not all equal." + ); + CPPAD_ASSERT_KNOWN( + gl.size() == gu.size() , + "ipopt::solve: size of gl and gu are not equal." + ); + size_t nx = xi.size(); + size_t ng = gl.size(); + + // Create an IpoptApplication + using Ipopt::IpoptApplication; + Ipopt::SmartPtr app = new IpoptApplication(); + + // process the options argument + size_t begin_1, end_1, begin_2, end_2, begin_3, end_3; + begin_1 = 0; + bool retape = false; + bool sparse_forward = false; + bool sparse_reverse = false; + while( begin_1 < options.size() ) + { // split this line into tokens + while( options[begin_1] == ' ') + begin_1++; + end_1 = options.find_first_of(" \n", begin_1); + begin_2 = end_1; + while( options[begin_2] == ' ') + begin_2++; + end_2 = options.find_first_of(" \n", begin_2); + begin_3 = end_2; + while( options[begin_3] == ' ') + begin_3++; + end_3 = options.find_first_of(" \n", begin_3); + + // check for errors + CPPAD_ASSERT_KNOWN( + (end_1 != std::string::npos) & + (end_2 != std::string::npos) & + (end_3 != std::string::npos) , + "ipopt::solve: missing '\\n' at end of an option line" + ); + CPPAD_ASSERT_KNOWN( + (end_1 > begin_1) & (end_2 > begin_2) , + "ipopt::solve: an option line does not have two tokens" + ); + + // get first two tokens + std::string tok_1 = options.substr(begin_1, end_1 - begin_1); + std::string tok_2 = options.substr(begin_2, end_2 - begin_2); + + // get third token + std::string tok_3; + bool three_tok = false; + three_tok |= tok_1 == "Sparse"; + three_tok |= tok_1 == "String"; + three_tok |= tok_1 == "Numeric"; + three_tok |= tok_1 == "Integer"; + if( three_tok ) + { CPPAD_ASSERT_KNOWN( + (end_3 > begin_3) , + "ipopt::solve: a Sparse, String, Numeric, or Integer\n" + "option line does not have three tokens." + ); + tok_3 = options.substr(begin_3, end_3 - begin_3); + } + + // switch on option type + if( tok_1 == "Retape" ) + { CPPAD_ASSERT_KNOWN( + (tok_2 == "true") | (tok_2 == "false") , + "ipopt::solve: Retape value is not true or false" + ); + retape = (tok_2 == "true"); + } + else if( tok_1 == "Sparse" ) + { CPPAD_ASSERT_KNOWN( + (tok_2 == "true") | (tok_2 == "false") , + "ipopt::solve: Sparse value is not true or false" + ); + CPPAD_ASSERT_KNOWN( + (tok_3 == "forward") | (tok_3 == "reverse") , + "ipopt::solve: Sparse direction is not forward or reverse" + ); + if( tok_2 == "false" ) + { sparse_forward = false; + sparse_reverse = false; + } + else + { sparse_forward = tok_3 == "forward"; + sparse_reverse = tok_3 == "reverse"; + } + } + else if ( tok_1 == "String" ) + app->Options()->SetStringValue(tok_2.c_str(), tok_3.c_str()); + else if ( tok_1 == "Numeric" ) + { Ipopt::Number value = std::atof( tok_3.c_str() ); + app->Options()->SetNumericValue(tok_2.c_str(), value); + } + else if ( tok_1 == "Integer" ) + { Ipopt::Index value = std::atoi( tok_3.c_str() ); + app->Options()->SetIntegerValue(tok_2.c_str(), value); + } + else + CPPAD_ASSERT_KNOWN( + false, + "ipopt::solve: First token is not one of\n" + "Retape, Sparse, String, Numeric, Integer" + ); + + begin_1 = end_3; + while( options[begin_1] == ' ') + begin_1++; + if( options[begin_1] != '\n' ) CPPAD_ASSERT_KNOWN( + false, + "ipopt::solve: either more than three tokens " + "or no '\\n' at end of a line" + ); + begin_1++; + } + CPPAD_ASSERT_KNOWN( + ! ( retape & (sparse_forward | sparse_reverse) ) , + "ipopt::solve: retape and sparse both true is not supported." + ); + + // Initialize the IpoptApplication and process the options + Ipopt::ApplicationReturnStatus status = app->Initialize(); + ok &= status == Ipopt::Solve_Succeeded; + if( ! ok ) + { solution.status = solve_result::unknown; + return; + } + + // Create an interface from Ipopt to this specific problem. + // Note the assumption here that ADvector is same as cppd_ipopt::ADvector + size_t nf = 1; + Ipopt::SmartPtr cppad_nlp = + new CppAD::ipopt::solve_callback( + nf, + nx, + ng, + xi, + xl, + xu, + gl, + gu, + fg_eval, + retape, + sparse_forward, + sparse_reverse, + solution + ); + + // Run the IpoptApplication + app->OptimizeTNLP(cppad_nlp); + + return; +} + +} // end ipopt namespace +} // END_CPPAD_NAMESPACE +# endif diff --git a/build-config/cppad/include/cppad/ipopt/solve_callback.hpp b/build-config/cppad/include/cppad/ipopt/solve_callback.hpp new file mode 100644 index 00000000..898f6ff1 --- /dev/null +++ b/build-config/cppad/include/cppad/ipopt/solve_callback.hpp @@ -0,0 +1,1192 @@ +# ifndef CPPAD_IPOPT_SOLVE_CALLBACK_HPP +# define CPPAD_IPOPT_SOLVE_CALLBACK_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +# include +# include +# include +# include + +namespace CppAD { // BEGIN_CPPAD_NAMESPACE +namespace ipopt { +/*! +\file solve_callback.hpp +\brief Class that connects ipopt::solve to Ipopt +*/ + +/*! +Class that Ipopt uses for obtaining information about this problem. + + +\section Evaluation_Methods Evaluation Methods +The set of evaluation methods for this class is +\verbatim + { eval_f, eval_grad_f, eval_g, eval_jac_g, eval_h } +\endverbatim +Note that the bool return flag for the evaluations methods +does not appear in the Ipopt documentation. +Looking at the code, it seems to be a flag telling Ipopt to abort +when the flag is false. +*/ +template +class solve_callback : public Ipopt::TNLP +{ +private: + // ------------------------------------------------------------------ + // Types used by this class + // ------------------------------------------------------------------ + /// A Scalar value used by Ipopt + typedef Ipopt::Number Number; + /// An index value used by Ipopt + typedef Ipopt::Index Index; + /// Indexing style used in Ipopt sparsity structure + typedef Ipopt::TNLP::IndexStyleEnum IndexStyleEnum; + // ------------------------------------------------------------------ + // Values directly passed in to constuctor + // ------------------------------------------------------------------ + /// dimension of the range space for f(x). + /// The objective is sum_i f_i (x). + /// Note that, at this point, there is no advantage having nf_ > 1. + const size_t nf_; + /// dimension of the domain space for f(x) and g(x) + const size_t nx_; + /// dimension of the range space for g(x) + const size_t ng_; + /// initial value for x + const Dvector& xi_; + /// lower limit for x + const Dvector& xl_; + /// upper limit for x + const Dvector& xu_; + /// lower limit for g(x) + const Dvector& gl_; + /// upper limit for g(x) + const Dvector& gu_; + /// object that evaluates f(x) and g(x) + FG_eval& fg_eval_; + /// should operation sequence be retaped for each new x. + bool retape_; + /// Should sparse methods be used to compute Jacobians and Hessians + /// with forward mode used for Jacobian. + bool sparse_forward_; + /// Should sparse methods be used to compute Jacobians and Hessians + /// with reverse mode used for Jacobian. + bool sparse_reverse_; + /// final results are returned to this structure + solve_result& solution_; + // ------------------------------------------------------------------ + // Values that are initilaized by the constructor + // ------------------------------------------------------------------ + /// AD function object that evaluates x -> [ f(x) , g(x) ] + /// If retape is false, this object is initialzed by constructor + /// otherwise it is set by cache_new_x each time it is called. + CppAD::ADFun adfun_; + /// value of x corresponding to previous new_x + Dvector x0_; + /// value of fg corresponding to previous new_x + Dvector fg0_; + // ---------------------------------------------------------------------- + // Jacobian information + // ---------------------------------------------------------------------- + /// Sparsity pattern for Jacobian of [f(x), g(x) ]. + /// If sparse is true, this pattern set by constructor and does not change. + /// Otherwise this vector has size zero. + CppAD::vectorBool pattern_jac_; + /// Row indices of [f(x), g(x)] for Jacobian of g(x) in row order. + /// (Set by constructor and not changed.) + CppAD::vector row_jac_; + /// Column indices for Jacobian of g(x), same order as row_jac_. + /// (Set by constructor and not changed.) + CppAD::vector col_jac_; + /// col_order_jac_ sorts row_jac_ and col_jac_ in column order. + /// (Set by constructor and not changed.) + CppAD::vector col_order_jac_; + /// Work vector used by SparseJacobian, stored here to avoid recalculation. + CppAD::sparse_jacobian_work work_jac_; + // ---------------------------------------------------------------------- + // Hessian information + // ---------------------------------------------------------------------- + /// Sparsity pattern for Hessian of Lagragian + /// \f[ L(x) = \sigma \sum_i f_i (x) + \sum_i \lambda_i g_i (x) \f] + /// If sparse is true, this pattern set by constructor and does not change. + /// Otherwise this vector has size zero. + CppAD::vectorBool pattern_hes_; + /// Row indices of Hessian lower left triangle in row order. + /// (Set by constructor and not changed.) + CppAD::vector row_hes_; + /// Column indices of Hessian left triangle in same order as row_hes_. + /// (Set by constructor and not changed.) + CppAD::vector col_hes_; + /// Work vector used by SparseJacobian, stored here to avoid recalculation. + CppAD::sparse_hessian_work work_hes_; + // ------------------------------------------------------------------ + // Private member functions + // ------------------------------------------------------------------ + /*! + Cache information for a new value of x. + + \param x + is the new value for x. + + \par x0_ + the elements of this vector are set to the new value for x. + + \par fg0_ + the elements of this vector are set to the new value for [f(x), g(x)] + + \par adfun_ + If retape is true, the operation sequence for this function + is changes to correspond to the argument x. + If retape is false, the operation sequence is not changed. + The zero order Taylor coefficients for this function are set + so they correspond to the argument x. + */ + void cache_new_x(const Number* x) + { size_t i; + if( retape_ ) + { // make adfun_, as well as x0_ and fg0_ correspond to this x + ADvector a_x(nx_), a_fg(nf_ + ng_); + for(i = 0; i < nx_; i++) + { x0_[i] = x[i]; + a_x[i] = x[i]; + } + CppAD::Independent(a_x); + fg_eval_(a_fg, a_x); + adfun_.Dependent(a_x, a_fg); + } + else + { // make x0_ and fg0_ correspond to this x + for(i = 0; i < nx_; i++) + x0_[i] = x[i]; + } + fg0_ = adfun_.Forward(0, x0_); + } +public: + // ---------------------------------------------------------------------- + /*! + Constructor for the interface between ipopt::solve and Ipopt + + \param nf + dimension of the range space for f(x) + + \param nx + dimension of the domain space for f(x) and g(x). + + \param ng + dimension of the range space for g(x) + + \param xi + initial value of x during the optimization procedure (size nx). + + \param xl + lower limit for x (size nx). + + \param xu + upper limit for x (size nx). + + \param gl + lower limit for g(x) (size ng). + + \param gu + upper limit for g(x) (size ng). + + \param fg_eval + function object that evaluations f(x) and g(x) using fg_eval(fg, x) + + \param retape + should the operation sequence be retaped for each argument value. + + \param sparse_forward + should sparse matrix computations be used for Jacobians and Hessians + with forward mode for Jacobian. + + \param sparse_reverse + should sparse matrix computations be used for Jacobians and Hessians + with reverse mode for Jacobian. + (sparse_forward and sparse_reverse cannot both be true). + + \param solution + object where final results are stored. + */ + solve_callback( + size_t nf , + size_t nx , + size_t ng , + const Dvector& xi , + const Dvector& xl , + const Dvector& xu , + const Dvector& gl , + const Dvector& gu , + FG_eval& fg_eval , + bool retape , + bool sparse_forward , + bool sparse_reverse , + solve_result& solution ) : + nf_ ( nf ), + nx_ ( nx ), + ng_ ( ng ), + xi_ ( xi ), + xl_ ( xl ), + xu_ ( xu ), + gl_ ( gl ), + gu_ ( gu ), + fg_eval_ ( fg_eval ), + retape_ ( retape ), + sparse_forward_ ( sparse_forward ), + sparse_reverse_ ( sparse_reverse ), + solution_ ( solution ) + { CPPAD_ASSERT_UNKNOWN( ! ( sparse_forward_ & sparse_reverse_ ) ); + + size_t i, j; + size_t nfg = nf_ + ng_; + + // initialize x0_ and fg0_ wih proper dimensions and value nan + x0_.resize(nx); + fg0_.resize(nfg); + for(i = 0; i < nx_; i++) + x0_[i] = CppAD::nan(0.0); + for(i = 0; i < nfg; i++) + fg0_[i] = CppAD::nan(0.0); + + if( ! retape_ ) + { // make adfun_ correspond to x -> [ f(x), g(x) ] + ADvector a_x(nx_), a_fg(nfg); + for(i = 0; i < nx_; i++) + a_x[i] = xi_[i]; + CppAD::Independent(a_x); + fg_eval_(a_fg, a_x); + adfun_.Dependent(a_x, a_fg); + // optimize because we will make repeated use of this tape + adfun_.optimize(); + } + if( sparse_forward_ | sparse_reverse_ ) + { CPPAD_ASSERT_UNKNOWN( ! retape ); + size_t m = nf_ + ng_; + // + // ----------------------------------------------------------- + // Jacobian + pattern_jac_.resize( m * nx_ ); + if( nx_ <= m ) + { // use forward mode to compute sparsity + + // number of bits that are packed into one unit in vectorBool + size_t n_column = vectorBool::bit_per_unit(); + + // sparsity patterns for current columns + vectorBool r(nx_ * n_column), s(m * n_column); + + // compute the sparsity pattern n_column columns at a time + size_t n_loop = (nx_ - 1) / n_column + 1; + for(size_t i_loop = 0; i_loop < n_loop; i_loop++) + { // starting column index for this iteration + size_t i_column = i_loop * n_column; + + // pattern that picks out the appropriate columns + for(i = 0; i < nx_; i++) + { for(j = 0; j < n_column; j++) + r[i * n_column + j] = (i == i_column + j); + } + s = adfun_.ForSparseJac(n_column, r); + + // fill in the corresponding columns of total_sparsity + for(i = 0; i < m; i++) + { for(j = 0; j < n_column; j++) + { if( i_column + j < nx_ ) + pattern_jac_[i * nx_ + i_column + j] = + s[i * n_column + j]; + } + } + } + } + else + { // use reverse mode to compute sparsity + + // number of bits that are packed into one unit in vectorBool + size_t n_row = vectorBool::bit_per_unit(); + + // sparsity patterns for current rows + vectorBool r(n_row * m), s(n_row * nx_); + + // compute the sparsity pattern n_row row at a time + size_t n_loop = (m - 1) / n_row + 1; + for(size_t i_loop = 0; i_loop < n_loop; i_loop++) + { // starting row index for this iteration + size_t i_row = i_loop * n_row; + + // pattern that picks out the appropriate rows + for(i = 0; i < n_row; i++) + { for(j = 0; j < m; j++) + r[i * m + j] = (i_row + i == j); + } + s = adfun_.RevSparseJac(n_row, r); + + // fill in correspoding rows of total sparsity + for(i = 0; i < n_row; i++) + { for(j = 0; j < nx_; j++) + if( i_row + i < m ) + pattern_jac_[ (i_row + i) * nx_ + j ] = + s[ i * nx_ + j]; + } + } + } + /* + { // use reverse mode to compute sparsity + CppAD::vectorBool s(m * m); + for(i = 0; i < m; i++) + { for(j = 0; j < m; j++) + s[i * m + j] = (i == j); + } + pattern_jac_ = adfun_.RevSparseJac(m, s); + } + */ + // Set row and column indices in Jacoian of [f(x), g(x)] + // for Jacobian of g(x). These indices are in row major order. + for(i = nf_; i < nfg; i++) + { for(j = 0; j < nx_; j++) + { if( pattern_jac_[ i * nx_ + j ] ) + { row_jac_.push_back(i); + col_jac_.push_back(j); + } + } + } + // Set row and column indices in Jacoian of [f(x), g(x)] + // for Jacobian of g(x). These indices are in row major order. + // ----------------------------------------------------------- + // Hessian + pattern_hes_.resize(nx_ * nx_); + + // number of bits that are packed into one unit in vectorBool + size_t n_column = vectorBool::bit_per_unit(); + + // sparsity patterns for current columns + vectorBool r(nx_ * n_column), h(nx_ * n_column); + + // sparsity pattern for range space of function + vectorBool s(m); + for(i = 0; i < m; i++) + s[i] = true; + + // compute the sparsity pattern n_column columns at a time + size_t n_loop = (nx_ - 1) / n_column + 1; + for(size_t i_loop = 0; i_loop < n_loop; i_loop++) + { // starting column index for this iteration + size_t i_column = i_loop * n_column; + + // pattern that picks out the appropriate columns + for(i = 0; i < nx_; i++) + { for(j = 0; j < n_column; j++) + r[i * n_column + j] = (i == i_column + j); + } + adfun_.ForSparseJac(n_column, r); + + // sparsity pattern corresponding to paritls w.r.t. (theta, u) + // of partial w.r.t. the selected columns + bool transpose = true; + h = adfun_.RevSparseHes(n_column, s, transpose); + + // fill in the corresponding columns of total_sparsity + for(i = 0; i < nx_; i++) + { for(j = 0; j < n_column; j++) + { if( i_column + j < nx_ ) + pattern_hes_[i * nx_ + i_column + j] = + h[i * n_column + j]; + } + } + } + // Set row and column indices for Lower triangle of Hessian + // of Lagragian. These indices are in row major order. + for(i = 0; i < nx_; i++) + { for(j = 0; j < nx_; j++) + { if( pattern_hes_[ i * nx_ + j ] ) + if( j <= i ) + { row_hes_.push_back(i); + col_hes_.push_back(j); + } + } + } + } + else + { // Set row and column indices in Jacoian of [f(x), g(x)] + // for Jacobian of g(x). These indices are in row major order. + for(i = nf_; i < nfg; i++) + { for(j = 0; j < nx_; j++) + { row_jac_.push_back(i); + col_jac_.push_back(j); + } + } + // Set row and column indices for lower triangle of Hessian. + // These indices are in row major order. + for(i = 0; i < nx_; i++) + { for(j = 0; j <= i; j++) + { row_hes_.push_back(i); + col_hes_.push_back(j); + } + } + } + + // Column order indirect sort of the Jacobian indices + col_order_jac_.resize( col_jac_.size() ); + index_sort( col_jac_, col_order_jac_ ); + } + // ----------------------------------------------------------------------- + /*! + Return dimension information about optimization problem. + + \param[out] n + is set to the value nx_. + + \param[out] m + is set to the value ng_. + + \param[out] nnz_jac_g + is set to ng_ * nx_ (sparsity not yet implemented) + + \param[out] nnz_h_lag + is set to nx_*(nx_+1)/2 (sparsity not yet implemented) + + \param[out] index_style + is set to C_STYLE; i.e., zeoro based indexing is used in the + information passed to Ipopt. + */ + virtual bool get_nlp_info( + Index& n , + Index& m , + Index& nnz_jac_g , + Index& nnz_h_lag , + IndexStyleEnum& index_style ) + { + n = static_cast(nx_); + m = static_cast(ng_); + nnz_jac_g = static_cast(row_jac_.size()); + nnz_h_lag = static_cast(row_hes_.size()); + +# ifndef NDEBUG + if( ! (sparse_forward_ | sparse_reverse_) ) + { size_t nnz = static_cast(nnz_jac_g); + CPPAD_ASSERT_UNKNOWN( nnz == ng_ * nx_); + // + nnz = static_cast(nnz_h_lag); + CPPAD_ASSERT_UNKNOWN( nnz == (nx_ * (nx_ + 1)) / 2 ); + } +# endif + + // use the fortran index style for row/col entries + index_style = C_STYLE; + + return true; + } + // ----------------------------------------------------------------------- + /*! + Return bound information about optimization problem. + + \param[in] n + is the dimension of the domain space for f(x) and g(x); i.e., + it must be equal to nx_. + + \param[out] x_l + is a vector of size nx_. + The input value of its elements does not matter. + On output, it is a copy of the lower bound for \f$ x \f$; i.e., + xl_. + + \param[out] x_u + is a vector of size nx_. + The input value of its elements does not matter. + On output, it is a copy of the upper bound for \f$ x \f$; i.e., + xu_. + + \param[in] m + is the dimension of the range space for g(x). i.e., + it must be equal to ng_. + + \param[out] g_l + is a vector of size ng_. + The input value of its elements does not matter. + On output, it is a copy of the lower bound for \f$ g(x) \f$; i.e., gl_. + + \param[out] g_u + is a vector of size ng_. + The input value of its elements does not matter. + On output, it is a copy of the upper bound for \f$ g(x) \f$; i.e, gu_. + */ + virtual bool get_bounds_info( + Index n , + Number* x_l , + Number* x_u , + Index m , + Number* g_l , + Number* g_u ) + { size_t i; + // here, the n and m we gave IPOPT in get_nlp_info are passed back + CPPAD_ASSERT_UNKNOWN(static_cast(n) == nx_); + CPPAD_ASSERT_UNKNOWN(static_cast(m) == ng_); + + // pass back bounds + for(i = 0; i < nx_; i++) + { x_l[i] = xl_[i]; + x_u[i] = xu_[i]; + } + for(i = 0; i < ng_; i++) + { g_l[i] = gl_[i]; + g_u[i] = gu_[i]; + } + + return true; + } + // ----------------------------------------------------------------------- + /*! + Return initial x value where optimiation is started. + + \param[in] n + must be equal to the domain dimension for f(x) and g(x); i.e., + it must be equal to nx_. + + \param[in] init_x + must be equal to true. + + \param[out] x + is a vector of size nx_. + The input value of its elements does not matter. + On output, it is a copy of the initial value for \f$ x \f$; i.e. xi_. + + \param[in] init_z + must be equal to false. + + \param z_L + is not used. + + \param z_U + is not used. + + \param[in] m + must be equal to the domain dimension for f(x) and g(x); i.e., + it must be equal to ng_. + + \param init_lambda + must be equal to false. + + \param lambda + is not used. + */ + virtual bool get_starting_point( + Index n , + bool init_x , + Number* x , + bool init_z , + Number* z_L , + Number* z_U , + Index m , + bool init_lambda , + Number* lambda ) + { size_t j; + + CPPAD_ASSERT_UNKNOWN(static_cast(n) == nx_ ); + CPPAD_ASSERT_UNKNOWN(static_cast(m) == ng_ ); + CPPAD_ASSERT_UNKNOWN(init_x == true); + CPPAD_ASSERT_UNKNOWN(init_z == false); + CPPAD_ASSERT_UNKNOWN(init_lambda == false); + + for(j = 0; j < nx_; j++) + x[j] = xi_[j]; + + return true; + } + // ----------------------------------------------------------------------- + /*! + Evaluate the objective fucntion f(x). + + \param[in] n + is the dimension of the argument space for f(x); i.e., must be equal nx_. + + \param[in] x + is a vector of size nx_ containing the point at which to evaluate + the function sum_i f_i (x). + + \param[in] new_x + is false if the previous call to any one of the + \ref Evaluation_Methods used the same value for x. + + \param[out] obj_value + is the value of the objective sum_i f_i (x) at this value of x. + + \return + The return value is always true; see \ref Evaluation_Methods. + */ + virtual bool eval_f( + Index n , + const Number* x , + bool new_x , + Number& obj_value ) + { size_t i; + if( new_x ) + cache_new_x(x); + // + double sum = 0.0; + for(i = 0; i < nf_; i++) + sum += fg0_[i]; + obj_value = static_cast(sum); + return true; + } + // ----------------------------------------------------------------------- + /*! + Evaluate the gradient of f(x). + + \param[in] n + is the dimension of the argument space for f(x); i.e., must be equal nx_. + + \param[in] x + has a vector of size nx_ containing the point at which to evaluate + the gradient of f(x). + + \param[in] new_x + is false if the previous call to any one of the + \ref Evaluation_Methods used the same value for x. + + \param[out] grad_f + is a vector of size nx_. + The input value of its elements does not matter. + The output value of its elements is the gradient of f(x) + at this value of. + + \return + The return value is always true; see \ref Evaluation_Methods. + */ + virtual bool eval_grad_f( + Index n , + const Number* x , + bool new_x , + Number* grad_f ) + { size_t i; + if( new_x ) + cache_new_x(x); + // + Dvector w(nf_ + ng_), dw(nx_); + for(i = 0; i < nf_; i++) + w[i] = 1.0; + for(i = 0; i < ng_; i++) + w[nf_ + i] = 0.0; + dw = adfun_.Reverse(1, w); + for(i = 0; i < nx_; i++) + grad_f[i] = dw[i]; + return true; + } + // ----------------------------------------------------------------------- + /*! + Evaluate the function g(x). + + \param[in] n + is the dimension of the argument space for g(x); i.e., must be equal nx_. + + \param[in] x + has a vector of size n containing the point at which to evaluate + the gradient of g(x). + + \param[in] new_x + is false if the previous call to any one of the + \ref Evaluation_Methods used the same value for x. + + \param[in] m + is the dimension of the range space for g(x); i.e., must be equal to ng_. + + \param[out] g + is a vector of size ng_. + The input value of its elements does not matter. + The output value of its elements is + the value of the function g(x) at this value of x. + + \return + The return value is always true; see \ref Evaluation_Methods. + */ + virtual bool eval_g( + Index n , + const Number* x , + bool new_x , + Index m , + Number* g ) + { size_t i; + if( new_x ) + cache_new_x(x); + // + for(i = 0; i < ng_; i++) + g[i] = fg0_[nf_ + i]; + return true; + } + // ----------------------------------------------------------------------- + /*! + Evaluate the Jacobian of g(x). + + \param[in] n + is the dimension of the argument space for g(x); + i.e., must be equal nx_. + + \param x + If values is not NULL, + x is a vector of size nx_ containing the point at which to evaluate + the gradient of g(x). + + \param[in] new_x + is false if the previous call to any one of the + \ref Evaluation_Methods used the same value for x. + + \param[in] m + is the dimension of the range space for g(x); + i.e., must be equal to ng_. + + \param[in] nele_jac + is the number of possibly non-zero elements in the Jacobian of g(x); + i.e., must be equal to ng_ * nx_. + + \param iRow + if values is not NULL, iRow is not defined. + if values is NULL, iRow + is a vector with size nele_jac. + The input value of its elements does not matter. + On output, + For k = 0 , ... , nele_jac-1, iRow[k] is the + base zero row index for the + k-th possibly non-zero entry in the Jacobian of g(x). + + \param jCol + if values is not NULL, jCol is not defined. + if values is NULL, jCol + is a vector with size nele_jac. + The input value of its elements does not matter. + On output, + For k = 0 , ... , nele_jac-1, jCol[k] is the + base zero column index for the + k-th possibly non-zero entry in the Jacobian of g(x). + + \param values + if values is not NULL, values + is a vector with size nele_jac. + The input value of its elements does not matter. + On output, + For k = 0 , ... , nele_jac-1, values[k] is the + value for the + k-th possibly non-zero entry in the Jacobian of g(x). + + \return + The return value is always true; see \ref Evaluation_Methods. + */ + virtual bool eval_jac_g( + Index n, + const Number* x, + bool new_x, + + Index m, + Index nele_jac, + Index* iRow, + Index *jCol, + + Number* values) + { size_t i, j, k, ell; + CPPAD_ASSERT_UNKNOWN(static_cast(m) == ng_ ); + CPPAD_ASSERT_UNKNOWN(static_cast(n) == nx_ ); + // + size_t nk = row_jac_.size(); + CPPAD_ASSERT_UNKNOWN( static_cast(nele_jac) == nk ); + // + if( new_x ) + cache_new_x(x); + + if( values == NULL ) + { for(k = 0; k < nk; k++) + { i = row_jac_[k]; + j = col_jac_[k]; + CPPAD_ASSERT_UNKNOWN( i >= nf_ ); + iRow[k] = static_cast(i - nf_); + jCol[k] = static_cast(j); + } + return true; + } + // + if( nk == 0 ) + return true; + // + if( sparse_forward_ ) + { Dvector jac(nk); + adfun_.SparseJacobianForward( + x0_ , pattern_jac_, row_jac_, col_jac_, jac, work_jac_ + ); + for(k = 0; k < nk; k++) + values[k] = jac[k]; + } + else if( sparse_reverse_ ) + { Dvector jac(nk); + adfun_.SparseJacobianReverse( + x0_ , pattern_jac_, row_jac_, col_jac_, jac, work_jac_ + ); + for(k = 0; k < nk; k++) + values[k] = jac[k]; + } + else if( nx_ < ng_ ) + { // use forward mode + Dvector x1(nx_), fg1(nf_ + ng_); + for(j = 0; j < nx_; j++) + x1[j] = 0.0; + // index in col_order_jac_ of next entry + ell = 0; + k = col_order_jac_[ell]; + for(j = 0; j < nx_; j++) + { // compute j-th column of Jacobian of g(x) + x1[j] = 1.0; + fg1 = adfun_.Forward(1, x1); + while( ell < nk && col_jac_[k] <= j ) + { CPPAD_ASSERT_UNKNOWN( col_jac_[k] == j ); + i = row_jac_[k]; + CPPAD_ASSERT_UNKNOWN( i >= nf_ ) + values[k] = fg1[i]; + ell++; + if( ell < nk ) + k = col_order_jac_[ell]; + } + x1[j] = 0.0; + } + } + else + { // user reverse mode + size_t nfg = nf_ + ng_; + // user reverse mode + Dvector w(nfg), dw(nx_); + for(i = 0; i < nfg; i++) + w[i] = 0.0; + // index in row_jac_ of next entry + k = 0; + for(i = nf_; i < nfg; i++) + { // compute i-th row of Jacobian of g(x) + w[i] = 1.0; + dw = adfun_.Reverse(1, w); + while( k < nk && row_jac_[k] <= i ) + { CPPAD_ASSERT_UNKNOWN( row_jac_[k] == i ); + j = col_jac_[k]; + values[k] = dw[j]; + k++; + } + w[i] = 0.0; + } + } + return true; + } + // ----------------------------------------------------------------------- + /*! + Evaluate the Hessian of the Lagragian + + \section The_Hessian_of_the_Lagragian The Hessian of the Lagragian + The Hessian of the Lagragian is defined as + \f[ + H(x, \sigma, \lambda ) + = + \sigma \nabla^2 f(x) + \sum_{i=0}^{m-1} \lambda_i \nabla^2 g(x)_i + \f] + + \param[in] n + is the dimension of the argument space for g(x); + i.e., must be equal nx_. + + \param x + if values is not NULL, x + is a vector of size nx_ containing the point at which to evaluate + the Hessian of the Lagragian. + + \param[in] new_x + is false if the previous call to any one of the + \ref Evaluation_Methods used the same value for x. + + \param[in] obj_factor + the value \f$ \sigma \f$ multiplying the Hessian of + f(x) in the expression for \ref The_Hessian_of_the_Lagragian. + + \param[in] m + is the dimension of the range space for g(x); + i.e., must be equal to ng_. + + \param[in] lambda + if values is not NULL, lambda + is a vector of size ng_ specifing the value of \f$ \lambda \f$ + in the expression for \ref The_Hessian_of_the_Lagragian. + + \param[in] new_lambda + is true if the previous call to eval_h had the same value for + lambda and false otherwise. + (Not currently used.) + + \param[in] nele_hess + is the number of possibly non-zero elements in the + Hessian of the Lagragian; + i.e., must be equal to nx_*(nx_+1)/2. + + \param iRow + if values is not NULL, iRow is not defined. + if values is NULL, iRow + is a vector with size nele_hess. + The input value of its elements does not matter. + On output, + For k = 0 , ... , nele_hess-1, iRow[k] is the + base zero row index for the + k-th possibly non-zero entry in the Hessian fo the Lagragian. + + \param jCol + if values is not NULL, jCol is not defined. + if values is NULL, jCol + is a vector with size nele_hess. + The input value of its elements does not matter. + On output, + For k = 0 , ... , nele_hess-1, jCol[k] is the + base zero column index for the + k-th possibly non-zero entry in the Hessian of the Lagragian. + + \param values + if values is not NULL, it + is a vector with size nele_hess. + The input value of its elements does not matter. + On output, + For k = 0 , ... , nele_hess-1, values[k] is the + value for the + k-th possibly non-zero entry in the Hessian of the Lagragian. + + \return + The return value is always true; see \ref Evaluation_Methods. + */ + virtual bool eval_h( + Index n , + const Number* x , + bool new_x , + Number obj_factor , + Index m , + const Number* lambda , + bool new_lambda , + Index nele_hess , + Index* iRow , + Index* jCol , + Number* values ) + { size_t i, j, k; + CPPAD_ASSERT_UNKNOWN(static_cast(m) == ng_ ); + CPPAD_ASSERT_UNKNOWN(static_cast(n) == nx_ ); + // + size_t nk = row_hes_.size(); + CPPAD_ASSERT_UNKNOWN( static_cast(nele_hess) == nk ); + // + if( new_x ) + cache_new_x(x); + // + if( values == NULL ) + { for(k = 0; k < nk; k++) + { i = row_hes_[k]; + j = col_hes_[k]; + iRow[k] = static_cast(i); + jCol[k] = static_cast(j); + } + return true; + } + // + if( nk == 0 ) + return true; + + // weigting vector for Lagragian + Dvector w(nf_ + ng_); + for(i = 0; i < nf_; i++) + w[i] = obj_factor; + for(i = 0; i < ng_; i++) + w[i + nf_] = lambda[i]; + // + if( sparse_forward_ | sparse_reverse_ ) + { Dvector hes(nk); + adfun_.SparseHessian( + x0_, w, pattern_hes_, row_hes_, col_hes_, hes, work_hes_ + ); + for(k = 0; k < nk; k++) + values[k] = hes[k]; + } + else + { Dvector hes(nx_ * nx_); + hes = adfun_.Hessian(x0_, w); + for(k = 0; k < nk; k++) + { i = row_hes_[k]; + j = col_hes_[k]; + values[k] = hes[i * nx_ + j]; + } + } + return true; + } + // ---------------------------------------------------------------------- + /*! + Pass solution information from Ipopt to users solution structure. + + \param[in] status + is value that the Ipopt solution status + which gets mapped to a correponding value for + \n + solution_.status + + \param[in] n + is the dimension of the domain space for f(x) and g(x); i.e., + it must be equal to nx_. + + \param[in] x + is a vector with size nx_ specifing the final solution. + This is the output value for + \n + solution_.x + + \param[in] z_L + is a vector with size nx_ specifing the Lagragian multipliers for the + constraint \f$ x^l \leq x \f$. + This is the output value for + \n + solution_.zl + + \param[in] z_U + is a vector with size nx_ specifing the Lagragian multipliers for the + constraint \f$ x \leq x^u \f$. + This is the output value for + \n + solution_.zu + + \param[in] m + is the dimension of the range space for g(x). i.e., + it must be equal to ng_. + + \param[in] g + is a vector with size ng_ containing the value of the constraint function + g(x) at the final solution x. + This is the output value for + \n + solution_.g + + \param[in] lambda + is a vector with size ng_ specifing the Lagragian multipliers for the + constraints \f$ g^l \leq g(x) \leq g^u \f$. + This is the output value for + \n + solution_.lambda + + \param[in] obj_value + is the value of the objective function f(x) at the final solution x. + This is the output value for + \n + solution_.obj_value + + \param[in] ip_data + is unspecified (by Ipopt) and hence not used. + + \param[in] ip_cq + is unspecified (by Ipopt) and hence not used. + + \par solution_[out] + this is a reference to the solution argument + in the constructor for solve_callback. + The results are stored here + (see documentation above). + */ + virtual void finalize_solution( + Ipopt::SolverReturn status , + Index n , + const Number* x , + const Number* z_L , + const Number* z_U , + Index m , + const Number* g , + const Number* lambda , + Number obj_value , + const Ipopt::IpoptData* ip_data , + Ipopt::IpoptCalculatedQuantities* ip_cq + ) + { size_t i, j; + + CPPAD_ASSERT_UNKNOWN(static_cast(n) == nx_ ); + CPPAD_ASSERT_UNKNOWN(static_cast(m) == ng_ ); + + switch(status) + { // convert status from Ipopt enum to solve_result enum + case Ipopt::SUCCESS: + solution_.status = solve_result::success; + break; + + case Ipopt::MAXITER_EXCEEDED: + solution_.status = + solve_result::maxiter_exceeded; + break; + + case Ipopt::STOP_AT_TINY_STEP: + solution_.status = + solve_result::stop_at_tiny_step; + break; + + case Ipopt::STOP_AT_ACCEPTABLE_POINT: + solution_.status = + solve_result::stop_at_acceptable_point; + break; + + case Ipopt::LOCAL_INFEASIBILITY: + solution_.status = + solve_result::local_infeasibility; + break; + + case Ipopt::USER_REQUESTED_STOP: + solution_.status = + solve_result::user_requested_stop; + break; + + case Ipopt::DIVERGING_ITERATES: + solution_.status = + solve_result::diverging_iterates; + break; + + case Ipopt::RESTORATION_FAILURE: + solution_.status = + solve_result::restoration_failure; + break; + + case Ipopt::ERROR_IN_STEP_COMPUTATION: + solution_.status = + solve_result::error_in_step_computation; + break; + + case Ipopt::INVALID_NUMBER_DETECTED: + solution_.status = + solve_result::invalid_number_detected; + break; + + case Ipopt::INTERNAL_ERROR: + solution_.status = + solve_result::internal_error; + break; + + default: + solution_.status = + solve_result::unknown; + } + + solution_.x.resize(nx_); + solution_.zl.resize(nx_); + solution_.zu.resize(nx_); + for(j = 0; j < nx_; j++) + { solution_.x[j] = x[j]; + solution_.zl[j] = z_L[j]; + solution_.zu[j] = z_U[j]; + } + solution_.g.resize(ng_); + solution_.lambda.resize(ng_); + for(i = 0; i < ng_; i++) + { solution_.g[i] = g[i]; + solution_.lambda[i] = lambda[i]; + } + solution_.obj_value = obj_value; + return; + } +}; + +} // end namespace ipopt +} // END_CPPAD_NAMESPACE + +# endif diff --git a/build-config/cppad/include/cppad/ipopt/solve_result.hpp b/build-config/cppad/include/cppad/ipopt/solve_result.hpp new file mode 100644 index 00000000..8cc12ce3 --- /dev/null +++ b/build-config/cppad/include/cppad/ipopt/solve_result.hpp @@ -0,0 +1,73 @@ +# ifndef CPPAD_IPOPT_SOLVE_RESULT_HPP +# define CPPAD_IPOPT_SOLVE_RESULT_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-16 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +namespace CppAD { // BEGIN_CPPAD_NAMESPACE +namespace ipopt { +/*! +\file solve_result.hpp +Class that contains information about solve problem result +*/ + +/*! +Class that contains information about solve problem result + +\tparam Dvector +a simple vector with elements of type double +*/ +template +class solve_result +{ +public: + /// possible values for the result status + enum status_type { + not_defined, + success, + maxiter_exceeded, + stop_at_tiny_step, + stop_at_acceptable_point, + local_infeasibility, + user_requested_stop, + feasible_point_found, + diverging_iterates, + restoration_failure, + error_in_step_computation, + invalid_number_detected, + too_few_degrees_of_freedom, + internal_error, + unknown + }; + + /// possible values for solution status + status_type status; + /// the approximation solution + Dvector x; + /// Lagrange multipliers corresponding to lower bounds on x + Dvector zl; + /// Lagrange multipliers corresponding to upper bounds on x + Dvector zu; + /// value of g(x) + Dvector g; + /// Lagrange multipliers correspondiing constraints on g(x) + Dvector lambda; + /// value of f(x) + double obj_value; + /// constructor initializes solution status as not yet defined + solve_result(void) + { status = not_defined; } +}; + +} // end namespace ipopt +} // END_CPPAD_NAMESPACE + +# endif diff --git a/build-config/cppad/include/cppad/local/abs_op.hpp b/build-config/cppad/include/cppad/local/abs_op.hpp new file mode 100644 index 00000000..f0e7fe41 --- /dev/null +++ b/build-config/cppad/include/cppad/local/abs_op.hpp @@ -0,0 +1,160 @@ +# ifndef CPPAD_LOCAL_ABS_OP_HPP +# define CPPAD_LOCAL_ABS_OP_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-17 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + + +namespace CppAD { namespace local { // BEGIN_CPPAD_LOCAL_NAMESPACE +/*! +\file abs_op.hpp +Forward and reverse mode calculations for z = fabs(x). +*/ + +/*! +Compute forward mode Taylor coefficient for result of op = AbsOp. + +The C++ source code corresponding to this operation is +\verbatim + z = fabs(x) +\endverbatim + +\copydetails CppAD::local::forward_unary1_op +*/ +template +void forward_abs_op( + size_t p , + size_t q , + size_t i_z , + size_t i_x , + size_t cap_order , + Base* taylor ) +{ + // check assumptions + CPPAD_ASSERT_UNKNOWN( NumArg(AbsOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( NumRes(AbsOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( q < cap_order ); + CPPAD_ASSERT_UNKNOWN( p <= q ); + + // Taylor coefficients corresponding to argument and result + Base* x = taylor + i_x * cap_order; + Base* z = taylor + i_z * cap_order; + + for(size_t j = p; j <= q; j++) + z[j] = sign(x[0]) * x[j]; +} + +/*! +Multiple directions forward mode Taylor coefficient for op = AbsOp. + +The C++ source code corresponding to this operation is +\verbatim + z = fabs(x) +\endverbatim + +\copydetails CppAD::local::forward_unary1_op_dir +*/ +template +void forward_abs_op_dir( + size_t q , + size_t r , + size_t i_z , + size_t i_x , + size_t cap_order , + Base* taylor ) +{ + // check assumptions + CPPAD_ASSERT_UNKNOWN( NumArg(AbsOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( NumRes(AbsOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( 0 < q ); + CPPAD_ASSERT_UNKNOWN( q < cap_order ); + + // Taylor coefficients corresponding to argument and result + size_t num_taylor_per_var = (cap_order-1) * r + 1; + Base* x = taylor + i_x * num_taylor_per_var; + Base* z = taylor + i_z * num_taylor_per_var; + + size_t m = (q-1) * r + 1; + for(size_t ell = 0; ell < r; ell++) + z[m + ell] = sign(x[0]) * x[m + ell]; +} + +/*! +Compute zero order forward mode Taylor coefficient for result of op = AbsOp. + +The C++ source code corresponding to this operation is +\verbatim + z = fabs(x) +\endverbatim + +\copydetails CppAD::local::forward_unary1_op_0 +*/ +template +void forward_abs_op_0( + size_t i_z , + size_t i_x , + size_t cap_order , + Base* taylor ) +{ + + // check assumptions + CPPAD_ASSERT_UNKNOWN( NumArg(AbsOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( NumRes(AbsOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( 0 < cap_order ); + + // Taylor coefficients corresponding to argument and result + Base x0 = *(taylor + i_x * cap_order); + Base* z = taylor + i_z * cap_order; + + z[0] = fabs(x0); +} +/*! +Compute reverse mode partial derivatives for result of op = AbsOp. + +The C++ source code corresponding to this operation is +\verbatim + z = fabs(x) +\endverbatim + +\copydetails CppAD::local::reverse_unary1_op +*/ + +template +void reverse_abs_op( + size_t d , + size_t i_z , + size_t i_x , + size_t cap_order , + const Base* taylor , + size_t nc_partial , + Base* partial ) +{ size_t j; + + // check assumptions + CPPAD_ASSERT_UNKNOWN( NumArg(AbsOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( NumRes(AbsOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( d < cap_order ); + CPPAD_ASSERT_UNKNOWN( d < nc_partial ); + + // Taylor coefficients and partials corresponding to argument + const Base* x = taylor + i_x * cap_order; + Base* px = partial + i_x * nc_partial; + + // Taylor coefficients and partials corresponding to result + Base* pz = partial + i_z * nc_partial; + + // do not need azmul because sign is either +1, -1, or zero + for(j = 0; j <= d; j++) + px[j] += sign(x[0]) * pz[j]; +} + +} } // END_CPPAD_LOCAL_NAMESPACE +# endif diff --git a/build-config/cppad/include/cppad/local/acos_op.hpp b/build-config/cppad/include/cppad/local/acos_op.hpp new file mode 100644 index 00000000..512c3b94 --- /dev/null +++ b/build-config/cppad/include/cppad/local/acos_op.hpp @@ -0,0 +1,263 @@ +# ifndef CPPAD_LOCAL_ACOS_OP_HPP +# define CPPAD_LOCAL_ACOS_OP_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-17 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + + +namespace CppAD { namespace local { // BEGIN_CPPAD_LOCAL_NAMESPACE +/*! +\file acos_op.hpp +Forward and reverse mode calculations for z = acos(x). +*/ + + +/*! +Compute forward mode Taylor coefficient for result of op = AcosOp. + +The C++ source code corresponding to this operation is +\verbatim + z = acos(x) +\endverbatim +The auxillary result is +\verbatim + y = sqrt(1 - x * x) +\endverbatim +The value of y, and its derivatives, are computed along with the value +and derivatives of z. + +\copydetails CppAD::local::forward_unary2_op +*/ +template +void forward_acos_op( + size_t p , + size_t q , + size_t i_z , + size_t i_x , + size_t cap_order , + Base* taylor ) +{ + // check assumptions + CPPAD_ASSERT_UNKNOWN( NumArg(AcosOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( NumRes(AcosOp) == 2 ); + CPPAD_ASSERT_UNKNOWN( q < cap_order ); + CPPAD_ASSERT_UNKNOWN( p <= q ); + + // Taylor coefficients corresponding to argument and result + Base* x = taylor + i_x * cap_order; + Base* z = taylor + i_z * cap_order; + Base* b = z - cap_order; // called y in documentation + + size_t k; + Base uj; + if( p == 0 ) + { z[0] = acos( x[0] ); + uj = Base(1.0) - x[0] * x[0]; + b[0] = sqrt( uj ); + p++; + } + for(size_t j = p; j <= q; j++) + { uj = Base(0.0); + for(k = 0; k <= j; k++) + uj -= x[k] * x[j-k]; + b[j] = Base(0.0); + z[j] = Base(0.0); + for(k = 1; k < j; k++) + { b[j] -= Base(double(k)) * b[k] * b[j-k]; + z[j] -= Base(double(k)) * z[k] * b[j-k]; + } + b[j] /= Base(double(j)); + z[j] /= Base(double(j)); + // + b[j] += uj / Base(2.0); + z[j] -= x[j]; + // + b[j] /= b[0]; + z[j] /= b[0]; + } +} +/*! +Multiple directions forward mode Taylor coefficient for op = AcosOp. + +The C++ source code corresponding to this operation is +\verbatim + z = acos(x) +\endverbatim +The auxillary result is +\verbatim + y = sqrt(1 - x * x) +\endverbatim +The value of y, and its derivatives, are computed along with the value +and derivatives of z. + +\copydetails CppAD::local::forward_unary2_op_dir +*/ +template +void forward_acos_op_dir( + size_t q , + size_t r , + size_t i_z , + size_t i_x , + size_t cap_order , + Base* taylor ) +{ + // check assumptions + CPPAD_ASSERT_UNKNOWN( NumArg(AcosOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( NumRes(AcosOp) == 2 ); + CPPAD_ASSERT_UNKNOWN( 0 < q ); + CPPAD_ASSERT_UNKNOWN( q < cap_order ); + + // Taylor coefficients corresponding to argument and result + size_t num_taylor_per_var = (cap_order-1) * r + 1; + Base* x = taylor + i_x * num_taylor_per_var; + Base* z = taylor + i_z * num_taylor_per_var; + Base* b = z - num_taylor_per_var; // called y in documentation + + size_t k, ell; + size_t m = (q-1) * r + 1; + for(ell = 0; ell < r; ell ++) + { Base uq = - 2.0 * x[m + ell] * x[0]; + for(k = 1; k < q; k++) + uq -= x[(k-1)*r+1+ell] * x[(q-k-1)*r+1+ell]; + b[m+ell] = Base(0.0); + z[m+ell] = Base(0.0); + for(k = 1; k < q; k++) + { b[m+ell] += Base(double(k)) * b[(k-1)*r+1+ell] * b[(q-k-1)*r+1+ell]; + z[m+ell] += Base(double(k)) * z[(k-1)*r+1+ell] * b[(q-k-1)*r+1+ell]; + } + b[m+ell] = ( uq / Base(2.0) - b[m+ell] / Base(double(q)) ) / b[0]; + z[m+ell] = -( x[m+ell] + z[m+ell] / Base(double(q)) ) / b[0]; + } +} + +/*! +Compute zero order forward mode Taylor coefficient for result of op = AcosOp. + +The C++ source code corresponding to this operation is +\verbatim + z = acos(x) +\endverbatim +The auxillary result is +\verbatim + y = sqrt( 1 - x * x ) +\endverbatim +The value of y is computed along with the value of z. + +\copydetails CppAD::local::forward_unary2_op_0 +*/ +template +void forward_acos_op_0( + size_t i_z , + size_t i_x , + size_t cap_order , + Base* taylor ) +{ + // check assumptions + CPPAD_ASSERT_UNKNOWN( NumArg(AcosOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( NumRes(AcosOp) == 2 ); + CPPAD_ASSERT_UNKNOWN( 0 < cap_order ); + + // Taylor coefficients corresponding to argument and result + Base* x = taylor + i_x * cap_order; + Base* z = taylor + i_z * cap_order; + Base* b = z - cap_order; // called y in documentation + + z[0] = acos( x[0] ); + b[0] = sqrt( Base(1.0) - x[0] * x[0] ); +} +/*! +Compute reverse mode partial derivatives for result of op = AcosOp. + +The C++ source code corresponding to this operation is +\verbatim + z = acos(x) +\endverbatim +The auxillary result is +\verbatim + y = sqrt( 1 - x * x ) +\endverbatim +The value of y is computed along with the value of z. + +\copydetails CppAD::local::reverse_unary2_op +*/ + +template +void reverse_acos_op( + size_t d , + size_t i_z , + size_t i_x , + size_t cap_order , + const Base* taylor , + size_t nc_partial , + Base* partial ) +{ + // check assumptions + CPPAD_ASSERT_UNKNOWN( NumArg(AcosOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( NumRes(AcosOp) == 2 ); + CPPAD_ASSERT_UNKNOWN( d < cap_order ); + CPPAD_ASSERT_UNKNOWN( d < nc_partial ); + + // Taylor coefficients and partials corresponding to argument + const Base* x = taylor + i_x * cap_order; + Base* px = partial + i_x * nc_partial; + + // Taylor coefficients and partials corresponding to first result + const Base* z = taylor + i_z * cap_order; + Base* pz = partial + i_z * nc_partial; + + // Taylor coefficients and partials corresponding to auxillary result + const Base* b = z - cap_order; // called y in documentation + Base* pb = pz - nc_partial; + + Base inv_b0 = Base(1.0) / b[0]; + + // number of indices to access + size_t j = d; + size_t k; + while(j) + { + // scale partials w.r.t b[j] by 1 / b[0] + pb[j] = azmul(pb[j], inv_b0); + + // scale partials w.r.t z[j] by 1 / b[0] + pz[j] = azmul(pz[j], inv_b0); + + // update partials w.r.t b^0 + pb[0] -= azmul(pz[j], z[j]) + azmul(pb[j], b[j]); + + // update partial w.r.t. x^0 + px[0] -= azmul(pb[j], x[j]); + + // update partial w.r.t. x^j + px[j] -= pz[j] + azmul(pb[j], x[0]); + + // further scale partial w.r.t. z[j] by 1 / j + pz[j] /= Base(double(j)); + + for(k = 1; k < j; k++) + { // update partials w.r.t b^(j-k) + pb[j-k] -= Base(double(k)) * azmul(pz[j], z[k]) + azmul(pb[j], b[k]); + + // update partials w.r.t. x^k + px[k] -= azmul(pb[j], x[j-k]); + + // update partials w.r.t. z^k + pz[k] -= Base(double(k)) * azmul(pz[j], b[j-k]); + } + --j; + } + + // j == 0 case + px[0] -= azmul( pz[0] + azmul(pb[0], x[0]), inv_b0); +} + +} } // END_CPPAD_LOCAL_NAMESPACE +# endif diff --git a/build-config/cppad/include/cppad/local/acosh_op.hpp b/build-config/cppad/include/cppad/local/acosh_op.hpp new file mode 100644 index 00000000..4aabec0a --- /dev/null +++ b/build-config/cppad/include/cppad/local/acosh_op.hpp @@ -0,0 +1,264 @@ +# ifndef CPPAD_LOCAL_ACOSH_OP_HPP +# define CPPAD_LOCAL_ACOSH_OP_HPP + +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + + +namespace CppAD { namespace local { // BEGIN_CPPAD_LOCAL_NAMESPACE +/*! +\file acosh_op.hpp +Forward and reverse mode calculations for z = acosh(x). +*/ + + +/*! +Compute forward mode Taylor coefficient for result of op = AcoshOp. + +The C++ source code corresponding to this operation is +\verbatim + z = acosh(x) +\endverbatim +The auxillary result is +\verbatim + y = sqrt(x * x - 1) +\endverbatim +The value of y, and its derivatives, are computed along with the value +and derivatives of z. + +\copydetails CppAD::local::forward_unary2_op +*/ +template +void forward_acosh_op( + size_t p , + size_t q , + size_t i_z , + size_t i_x , + size_t cap_order , + Base* taylor ) +{ + // check assumptions + CPPAD_ASSERT_UNKNOWN( NumArg(AcoshOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( NumRes(AcoshOp) == 2 ); + CPPAD_ASSERT_UNKNOWN( q < cap_order ); + CPPAD_ASSERT_UNKNOWN( p <= q ); + + // Taylor coefficients corresponding to argument and result + Base* x = taylor + i_x * cap_order; + Base* z = taylor + i_z * cap_order; + Base* b = z - cap_order; // called y in documentation + + size_t k; + Base uj; + if( p == 0 ) + { z[0] = acosh( x[0] ); + uj = x[0] * x[0] - Base(1.0); + b[0] = sqrt( uj ); + p++; + } + for(size_t j = p; j <= q; j++) + { uj = Base(0.0); + for(k = 0; k <= j; k++) + uj += x[k] * x[j-k]; + b[j] = Base(0.0); + z[j] = Base(0.0); + for(k = 1; k < j; k++) + { b[j] -= Base(double(k)) * b[k] * b[j-k]; + z[j] -= Base(double(k)) * z[k] * b[j-k]; + } + b[j] /= Base(double(j)); + z[j] /= Base(double(j)); + // + b[j] += uj / Base(2.0); + z[j] += x[j]; + // + b[j] /= b[0]; + z[j] /= b[0]; + } +} +/*! +Multiple directions forward mode Taylor coefficient for op = AcoshOp. + +The C++ source code corresponding to this operation is +\verbatim + z = acosh(x) +\endverbatim +The auxillary result is +\verbatim + y = sqrt(x * x - 1) +\endverbatim +The value of y, and its derivatives, are computed along with the value +and derivatives of z. + +\copydetails CppAD::local::forward_unary2_op_dir +*/ +template +void forward_acosh_op_dir( + size_t q , + size_t r , + size_t i_z , + size_t i_x , + size_t cap_order , + Base* taylor ) +{ + // check assumptions + CPPAD_ASSERT_UNKNOWN( NumArg(AcoshOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( NumRes(AcoshOp) == 2 ); + CPPAD_ASSERT_UNKNOWN( 0 < q ); + CPPAD_ASSERT_UNKNOWN( q < cap_order ); + + // Taylor coefficients corresponding to argument and result + size_t num_taylor_per_var = (cap_order-1) * r + 1; + Base* x = taylor + i_x * num_taylor_per_var; + Base* z = taylor + i_z * num_taylor_per_var; + Base* b = z - num_taylor_per_var; // called y in documentation + + size_t k, ell; + size_t m = (q-1) * r + 1; + for(ell = 0; ell < r; ell ++) + { Base uq = 2.0 * x[m + ell] * x[0]; + for(k = 1; k < q; k++) + uq += x[(k-1)*r+1+ell] * x[(q-k-1)*r+1+ell]; + b[m+ell] = Base(0.0); + z[m+ell] = Base(0.0); + for(k = 1; k < q; k++) + { b[m+ell] += Base(double(k)) * b[(k-1)*r+1+ell] * b[(q-k-1)*r+1+ell]; + z[m+ell] += Base(double(k)) * z[(k-1)*r+1+ell] * b[(q-k-1)*r+1+ell]; + } + b[m+ell] = ( uq / Base(2.0) - b[m+ell] / Base(double(q)) ) / b[0]; + z[m+ell] = ( x[m+ell] - z[m+ell] / Base(double(q)) ) / b[0]; + } +} + +/*! +Compute zero order forward mode Taylor coefficient for result of op = AcoshOp. + +The C++ source code corresponding to this operation is +\verbatim + z = acosh(x) +\endverbatim +The auxillary result is +\verbatim + y = sqrt( x * x - 1 ) +\endverbatim +The value of y is computed along with the value of z. + +\copydetails CppAD::local::forward_unary2_op_0 +*/ +template +void forward_acosh_op_0( + size_t i_z , + size_t i_x , + size_t cap_order , + Base* taylor ) +{ + // check assumptions + CPPAD_ASSERT_UNKNOWN( NumArg(AcoshOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( NumRes(AcoshOp) == 2 ); + CPPAD_ASSERT_UNKNOWN( 0 < cap_order ); + + // Taylor coefficients corresponding to argument and result + Base* x = taylor + i_x * cap_order; + Base* z = taylor + i_z * cap_order; + Base* b = z - cap_order; // called y in documentation + + z[0] = acosh( x[0] ); + b[0] = sqrt( x[0] * x[0] - Base(1.0) ); +} +/*! +Compute reverse mode partial derivatives for result of op = AcoshOp. + +The C++ source code corresponding to this operation is +\verbatim + z = acosh(x) +\endverbatim +The auxillary result is +\verbatim + y = sqrt( x * x - 1 ) +\endverbatim +The value of y is computed along with the value of z. + +\copydetails CppAD::local::reverse_unary2_op +*/ + +template +void reverse_acosh_op( + size_t d , + size_t i_z , + size_t i_x , + size_t cap_order , + const Base* taylor , + size_t nc_partial , + Base* partial ) +{ + // check assumptions + CPPAD_ASSERT_UNKNOWN( NumArg(AcoshOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( NumRes(AcoshOp) == 2 ); + CPPAD_ASSERT_UNKNOWN( d < cap_order ); + CPPAD_ASSERT_UNKNOWN( d < nc_partial ); + + // Taylor coefficients and partials corresponding to argument + const Base* x = taylor + i_x * cap_order; + Base* px = partial + i_x * nc_partial; + + // Taylor coefficients and partials corresponding to first result + const Base* z = taylor + i_z * cap_order; + Base* pz = partial + i_z * nc_partial; + + // Taylor coefficients and partials corresponding to auxillary result + const Base* b = z - cap_order; // called y in documentation + Base* pb = pz - nc_partial; + + Base inv_b0 = Base(1.0) / b[0]; + + // number of indices to access + size_t j = d; + size_t k; + while(j) + { + // scale partials w.r.t b[j] by 1 / b[0] + pb[j] = azmul(pb[j], inv_b0); + + // scale partials w.r.t z[j] by 1 / b[0] + pz[j] = azmul(pz[j], inv_b0); + + // update partials w.r.t b^0 + pb[0] -= azmul(pz[j], z[j]) + azmul(pb[j], b[j]); + + // update partial w.r.t. x^0 + px[0] += azmul(pb[j], x[j]); + + // update partial w.r.t. x^j + px[j] += pz[j] + azmul(pb[j], x[0]); + + // further scale partial w.r.t. z[j] by 1 / j + pz[j] /= Base(double(j)); + + for(k = 1; k < j; k++) + { // update partials w.r.t b^(j-k) + pb[j-k] -= Base(double(k)) * azmul(pz[j], z[k]) + azmul(pb[j], b[k]); + + // update partials w.r.t. x^k + px[k] += azmul(pb[j], x[j-k]); + + // update partials w.r.t. z^k + pz[k] -= Base(double(k)) * azmul(pz[j], b[j-k]); + } + --j; + } + + // j == 0 case + px[0] += azmul(pz[0] + azmul(pb[0], x[0]), inv_b0); +} + +} } // END_CPPAD_LOCAL_NAMESPACE +# endif diff --git a/build-config/cppad/include/cppad/local/ad_tape.hpp b/build-config/cppad/include/cppad/local/ad_tape.hpp new file mode 100644 index 00000000..d0f19af1 --- /dev/null +++ b/build-config/cppad/include/cppad/local/ad_tape.hpp @@ -0,0 +1,186 @@ +# ifndef CPPAD_LOCAL_AD_TAPE_HPP +# define CPPAD_LOCAL_AD_TAPE_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ +# include + +namespace CppAD { namespace local { // BEGIN_CPPAD_LOCAL__NAMESPACE + +/*! +Class used to hold tape that records AD operations. + +\tparam Base +An AD object is used to recording AD operations. +*/ + +template +class ADTape { + // Friends ============================================================= + + // classes ------------------------------------------------------------- + friend class AD; + friend class ADFun; + friend class atomic_base; + friend class atomic_three; + friend class discrete; + friend class VecAD; + friend class VecAD_reference; + + // functions ----------------------------------------------------------- + // PrintFor + friend void CppAD::PrintFor ( + const AD& flag , + const char* before , + const AD& var , + const char* after + ); + // CondExpOp + friend AD CppAD::CondExpOp ( + enum CompareOp cop , + const AD &left , + const AD &right , + const AD &trueCase , + const AD &falseCase + ); + // pow + friend AD CppAD::pow + (const AD &x, const AD &y); + // azmul + friend AD CppAD::azmul + (const AD &x, const AD &y); + // Parameter + friend bool CppAD::Parameter + (const AD &u); + // Variable + friend bool CppAD::Variable + (const AD &u); + // operators ----------------------------------------------------------- + // arithematic binary operators +# if _MSC_VER + // see https://stackoverflow.com/questions/63288453 + template friend AD CppAD::operator * + (const AD &left, const AD &right); +# else + friend AD CppAD::operator * + (const AD &left, const AD &right); +# endif + friend AD CppAD::operator + + (const AD &left, const AD &right); + friend AD CppAD::operator - + (const AD &left, const AD &right); + friend AD CppAD::operator / + (const AD &left, const AD &right); + + // comparison operators +# if _MSC_VER + template friend bool CppAD::operator == + (const AD &left, const AD &right); + template friend bool CppAD::operator != + (const AD &left, const AD &right); +# else + friend bool CppAD::operator == + (const AD &left, const AD &right); + friend bool CppAD::operator != + (const AD &left, const AD &right); +# endif + friend bool CppAD::operator < + (const AD &left, const AD &right); + friend bool CppAD::operator <= + (const AD &left, const AD &right); + friend bool CppAD::operator > + (const AD &left, const AD &right); + friend bool CppAD::operator >= + (const AD &left, const AD &right); + // ====================================================================== + +// -------------------------------------------------------------------------- +private: + // ---------------------------------------------------------------------- + // private data + /*! + Unique identifier for this tape. It is always greater than + CPPAD_MAX_NUM_THREADS, and different for every tape (even ones that have + been deleted). In addition, id_ % CPPAD_MAX_NUM_THREADS is the thread + number for this tape. Set by Independent and effectively const + */ + tape_id_t id_; + /// Number of independent variables in this tapes reconding. + /// Set by Independent and effectively const + size_t size_independent_; + /// This is where the information is recorded. + local::recorder Rec_; + // ---------------------------------------------------------------------- + // private functions + // + // add a parameter to the tape + addr_t RecordParOp(const AD& y); + + // see CondExp.h + void RecordCondExp( + enum CompareOp cop , + AD &returnValue , + const AD &left , + const AD &right , + const AD &trueCase , + const AD &falseCase + ); + +public: + // public function only used by CppAD::Independent + template + void Independent( + ADBaseVector& x , + size_t abort_op_index , + bool record_compare , + ADBaseVector& dynamic + ); + +}; +// --------------------------------------------------------------------------- +// Private functions +// + +/*! +Place a parameter in the tape as a variable. + +On rare occations it is necessary to place a parameter in the tape; e.g., +when it is one of the dependent variabes. + +\param y +value of the parameter that we are placing in the tape as a variable. + +\return +variable index (for this recording) correpsonding to the parameter. + +\par 2DO +All these operates are preformed in Rec_, so we should +move this routine from ADTape to recorder. +*/ +template +addr_t ADTape::RecordParOp(const AD& y) +{ CPPAD_ASSERT_UNKNOWN( NumRes(ParOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( NumArg(ParOp) == 1 ); + addr_t z_taddr = Rec_.PutOp(ParOp); + if( Dynamic(y) ) + { addr_t ind = y.taddr_; + Rec_.PutArg(ind); + } + else + { addr_t ind = Rec_.put_con_par(y.value_); + Rec_.PutArg(ind); + } + return z_taddr; +} + +} } // END_CPPAD_LOCAL_NAMESPACE + +# endif diff --git a/build-config/cppad/include/cppad/local/add_op.hpp b/build-config/cppad/include/cppad/local/add_op.hpp new file mode 100644 index 00000000..6b193346 --- /dev/null +++ b/build-config/cppad/include/cppad/local/add_op.hpp @@ -0,0 +1,338 @@ +# ifndef CPPAD_LOCAL_ADD_OP_HPP +# define CPPAD_LOCAL_ADD_OP_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-18 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +namespace CppAD { namespace local { // BEGIN_CPPAD_LOCAL_NAMESPACE +/*! +\file add_op.hpp +Forward and reverse mode calculations for z = x + y. +*/ + +// --------------------------- Addvv ----------------------------------------- +/*! +Compute forward mode Taylor coefficients for result of op = AddvvOp. + +The C++ source code corresponding to this operation is +\verbatim + z = x + y +\endverbatim +In the documentation below, +this operations is for the case where both x and y are variables +and the argument parameter is not used. + +\copydetails CppAD::local::forward_binary_op +*/ + +template +void forward_addvv_op( + size_t p , + size_t q , + size_t i_z , + const addr_t* arg , + const Base* parameter , + size_t cap_order , + Base* taylor ) +{ + // check assumptions + CPPAD_ASSERT_UNKNOWN( NumArg(AddvvOp) == 2 ); + CPPAD_ASSERT_UNKNOWN( NumRes(AddvvOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( q < cap_order ); + CPPAD_ASSERT_UNKNOWN( p <= q ); + + // Taylor coefficients corresponding to arguments and result + Base* x = taylor + size_t(arg[0]) * cap_order; + Base* y = taylor + size_t(arg[1]) * cap_order; + Base* z = taylor + i_z * cap_order; + + for(size_t j = p; j <= q; j++) + z[j] = x[j] + y[j]; +} +/*! +Multiple directions forward mode Taylor coefficients for op = AddvvOp. + +The C++ source code corresponding to this operation is +\verbatim + z = x + y +\endverbatim +In the documentation below, +this operations is for the case where both x and y are variables +and the argument parameter is not used. + +\copydetails CppAD::local::forward_binary_op_dir +*/ + +template +void forward_addvv_op_dir( + size_t q , + size_t r , + size_t i_z , + const addr_t* arg , + const Base* parameter , + size_t cap_order , + Base* taylor ) +{ + // check assumptions + CPPAD_ASSERT_UNKNOWN( NumArg(AddvvOp) == 2 ); + CPPAD_ASSERT_UNKNOWN( NumRes(AddvvOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( q < cap_order ); + CPPAD_ASSERT_UNKNOWN( 0 < q ); + + // Taylor coefficients corresponding to arguments and result + size_t num_taylor_per_var = (cap_order-1) * r + 1; + Base* x = taylor + size_t(arg[0]) * num_taylor_per_var; + Base* y = taylor + size_t(arg[1]) * num_taylor_per_var; + Base* z = taylor + i_z * num_taylor_per_var; + + size_t m = (q-1)*r + 1 ; + for(size_t ell = 0; ell < r; ell++) + z[m+ell] = x[m+ell] + y[m+ell]; +} + +/*! +Compute zero order forward mode Taylor coefficients for result of op = AddvvOp. + +The C++ source code corresponding to this operation is +\verbatim + z = x + y +\endverbatim +In the documentation below, +this operations is for the case where both x and y are variables +and the argument parameter is not used. + +\copydetails CppAD::local::forward_binary_op_0 +*/ + +template +void forward_addvv_op_0( + size_t i_z , + const addr_t* arg , + const Base* parameter , + size_t cap_order , + Base* taylor ) +{ + // check assumptions + CPPAD_ASSERT_UNKNOWN( NumArg(AddvvOp) == 2 ); + CPPAD_ASSERT_UNKNOWN( NumRes(AddvvOp) == 1 ); + + // Taylor coefficients corresponding to arguments and result + Base* x = taylor + size_t(arg[0]) * cap_order; + Base* y = taylor + size_t(arg[1]) * cap_order; + Base* z = taylor + i_z * cap_order; + + z[0] = x[0] + y[0]; +} + +/*! +Compute reverse mode partial derivatives for result of op = AddvvOp. + +The C++ source code corresponding to this operation is +\verbatim + z = x + y +\endverbatim +In the documentation below, +this operations is for the case where both x and y are variables +and the argument parameter is not used. + +\copydetails CppAD::local::reverse_binary_op +*/ + +template +void reverse_addvv_op( + size_t d , + size_t i_z , + const addr_t* arg , + const Base* parameter , + size_t cap_order , + const Base* taylor , + size_t nc_partial , + Base* partial ) +{ + // check assumptions + CPPAD_ASSERT_UNKNOWN( NumArg(AddvvOp) == 2 ); + CPPAD_ASSERT_UNKNOWN( NumRes(AddvvOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( d < cap_order ); + CPPAD_ASSERT_UNKNOWN( d < nc_partial ); + + // Partial derivatives corresponding to arguments and result + Base* px = partial + size_t(arg[0]) * nc_partial; + Base* py = partial + size_t(arg[1]) * nc_partial; + Base* pz = partial + i_z * nc_partial; + + // number of indices to access + size_t i = d + 1; + while(i) + { --i; + px[i] += pz[i]; + py[i] += pz[i]; + } +} + +// --------------------------- Addpv ----------------------------------------- +/*! +Compute forward mode Taylor coefficients for result of op = AddpvOp. + +The C++ source code corresponding to this operation is +\verbatim + z = x + y +\endverbatim +In the documentation below, +this operations is for the case where x is a parameter and y is a variable. + +\copydetails CppAD::local::forward_binary_op +*/ +template +void forward_addpv_op( + size_t p , + size_t q , + size_t i_z , + const addr_t* arg , + const Base* parameter , + size_t cap_order , + Base* taylor ) +{ + // check assumptions + CPPAD_ASSERT_UNKNOWN( NumArg(AddpvOp) == 2 ); + CPPAD_ASSERT_UNKNOWN( NumRes(AddpvOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( q < cap_order ); + CPPAD_ASSERT_UNKNOWN( p <= q ); + + // Taylor coefficients corresponding to arguments and result + Base* y = taylor + size_t(arg[1]) * cap_order; + Base* z = taylor + i_z * cap_order; + + if( p == 0 ) + { // Paraemter value + Base x = parameter[ arg[0] ]; + z[0] = x + y[0]; + p++; + } + for(size_t j = p; j <= q; j++) + z[j] = y[j]; +} +/*! +Multiple directions forward mode Taylor coefficients for op = AddpvOp. + +The C++ source code corresponding to this operation is +\verbatim + z = x + y +\endverbatim +In the documentation below, +this operations is for the case where x is a parameter and y is a variable. + +\copydetails CppAD::local::forward_binary_op_dir +*/ +template +void forward_addpv_op_dir( + size_t q , + size_t r , + size_t i_z , + const addr_t* arg , + const Base* parameter , + size_t cap_order , + Base* taylor ) +{ + // check assumptions + CPPAD_ASSERT_UNKNOWN( NumArg(AddpvOp) == 2 ); + CPPAD_ASSERT_UNKNOWN( NumRes(AddpvOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( 0 < q ); + CPPAD_ASSERT_UNKNOWN( q < cap_order ); + + // Taylor coefficients corresponding to arguments and result + size_t num_taylor_per_var = (cap_order-1) * r + 1; + size_t m = (q-1) * r + 1; + Base* y = taylor + size_t(arg[1]) * num_taylor_per_var + m; + Base* z = taylor + i_z * num_taylor_per_var + m; + + for(size_t ell = 0; ell < r; ell++) + z[ell] = y[ell]; +} +/*! +Compute zero order forward mode Taylor coefficient for result of op = AddpvOp. + +The C++ source code corresponding to this operation is +\verbatim + z = x + y +\endverbatim +In the documentation below, +this operations is for the case where x is a parameter and y is a variable. + +\copydetails CppAD::local::forward_binary_op_0 +*/ + +template +void forward_addpv_op_0( + size_t i_z , + const addr_t* arg , + const Base* parameter , + size_t cap_order , + Base* taylor ) +{ + // check assumptions + CPPAD_ASSERT_UNKNOWN( NumArg(AddpvOp) == 2 ); + CPPAD_ASSERT_UNKNOWN( NumRes(AddpvOp) == 1 ); + + // Paraemter value + Base x = parameter[ arg[0] ]; + + // Taylor coefficients corresponding to arguments and result + Base* y = taylor + size_t(arg[1]) * cap_order; + Base* z = taylor + i_z * cap_order; + + z[0] = x + y[0]; +} + +/*! +Compute reverse mode partial derivative for result of op = AddpvOp. + +The C++ source code corresponding to this operation is +\verbatim + z = x + y +\endverbatim +In the documentation below, +this operations is for the case where x is a parameter and y is a variable. + +\copydetails CppAD::local::reverse_binary_op +*/ + +template +void reverse_addpv_op( + size_t d , + size_t i_z , + const addr_t* arg , + const Base* parameter , + size_t cap_order , + const Base* taylor , + size_t nc_partial , + Base* partial ) +{ + // check assumptions + CPPAD_ASSERT_UNKNOWN( NumArg(AddvvOp) == 2 ); + CPPAD_ASSERT_UNKNOWN( NumRes(AddvvOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( d < cap_order ); + CPPAD_ASSERT_UNKNOWN( d < nc_partial ); + + // Partial derivatives corresponding to arguments and result + Base* py = partial + size_t(arg[1]) * nc_partial; + Base* pz = partial + i_z * nc_partial; + + // number of indices to access + size_t i = d + 1; + while(i) + { --i; + py[i] += pz[i]; + } +} + + +} } // END_CPPAD_LOCAL_NAMESPACE +# endif diff --git a/build-config/cppad/include/cppad/local/asin_op.hpp b/build-config/cppad/include/cppad/local/asin_op.hpp new file mode 100644 index 00000000..5909aead --- /dev/null +++ b/build-config/cppad/include/cppad/local/asin_op.hpp @@ -0,0 +1,263 @@ +# ifndef CPPAD_LOCAL_ASIN_OP_HPP +# define CPPAD_LOCAL_ASIN_OP_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-17 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + + +namespace CppAD { namespace local { // BEGIN_CPPAD_LOCAL_NAMESPACE +/*! +\file asin_op.hpp +Forward and reverse mode calculations for z = asin(x). +*/ + + +/*! +Compute forward mode Taylor coefficient for result of op = AsinOp. + +The C++ source code corresponding to this operation is +\verbatim + z = asin(x) +\endverbatim +The auxillary result is +\verbatim + y = sqrt(1 - x * x) +\endverbatim +The value of y, and its derivatives, are computed along with the value +and derivatives of z. + +\copydetails CppAD::local::forward_unary2_op +*/ +template +void forward_asin_op( + size_t p , + size_t q , + size_t i_z , + size_t i_x , + size_t cap_order , + Base* taylor ) +{ + // check assumptions + CPPAD_ASSERT_UNKNOWN( NumArg(AsinOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( NumRes(AsinOp) == 2 ); + CPPAD_ASSERT_UNKNOWN( q < cap_order ); + CPPAD_ASSERT_UNKNOWN( p <= q ); + + // Taylor coefficients corresponding to argument and result + Base* x = taylor + i_x * cap_order; + Base* z = taylor + i_z * cap_order; + Base* b = z - cap_order; // called y in documentation + + size_t k; + Base uj; + if( p == 0 ) + { z[0] = asin( x[0] ); + uj = Base(1.0) - x[0] * x[0]; + b[0] = sqrt( uj ); + p++; + } + for(size_t j = p; j <= q; j++) + { uj = Base(0.0); + for(k = 0; k <= j; k++) + uj -= x[k] * x[j-k]; + b[j] = Base(0.0); + z[j] = Base(0.0); + for(k = 1; k < j; k++) + { b[j] -= Base(double(k)) * b[k] * b[j-k]; + z[j] -= Base(double(k)) * z[k] * b[j-k]; + } + b[j] /= Base(double(j)); + z[j] /= Base(double(j)); + // + b[j] += uj / Base(2.0); + z[j] += x[j]; + // + b[j] /= b[0]; + z[j] /= b[0]; + } +} +/*! +Multiple directions forward mode Taylor coefficient for op = AsinOp. + +The C++ source code corresponding to this operation is +\verbatim + z = asin(x) +\endverbatim +The auxillary result is +\verbatim + y = sqrt(1 - x * x) +\endverbatim +The value of y, and its derivatives, are computed along with the value +and derivatives of z. + +\copydetails CppAD::local::forward_unary2_op_dir +*/ +template +void forward_asin_op_dir( + size_t q , + size_t r , + size_t i_z , + size_t i_x , + size_t cap_order , + Base* taylor ) +{ + // check assumptions + CPPAD_ASSERT_UNKNOWN( NumArg(AcosOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( NumRes(AcosOp) == 2 ); + CPPAD_ASSERT_UNKNOWN( 0 < q ); + CPPAD_ASSERT_UNKNOWN( q < cap_order ); + + // Taylor coefficients corresponding to argument and result + size_t num_taylor_per_var = (cap_order-1) * r + 1; + Base* x = taylor + i_x * num_taylor_per_var; + Base* z = taylor + i_z * num_taylor_per_var; + Base* b = z - num_taylor_per_var; // called y in documentation + + size_t k, ell; + size_t m = (q-1) * r + 1; + for(ell = 0; ell < r; ell ++) + { Base uq = - 2.0 * x[m + ell] * x[0]; + for(k = 1; k < q; k++) + uq -= x[(k-1)*r+1+ell] * x[(q-k-1)*r+1+ell]; + b[m+ell] = Base(0.0); + z[m+ell] = Base(0.0); + for(k = 1; k < q; k++) + { b[m+ell] += Base(double(k)) * b[(k-1)*r+1+ell] * b[(q-k-1)*r+1+ell]; + z[m+ell] += Base(double(k)) * z[(k-1)*r+1+ell] * b[(q-k-1)*r+1+ell]; + } + b[m+ell] = ( uq / Base(2.0) - b[m+ell] / Base(double(q)) ) / b[0]; + z[m+ell] = ( x[m+ell] - z[m+ell] / Base(double(q)) ) / b[0]; + } +} + +/*! +Compute zero order forward mode Taylor coefficient for result of op = AsinOp. + +The C++ source code corresponding to this operation is +\verbatim + z = asin(x) +\endverbatim +The auxillary result is +\verbatim + y = sqrt( 1 - x * x ) +\endverbatim +The value of y is computed along with the value of z. + +\copydetails CppAD::local::forward_unary2_op_0 +*/ +template +void forward_asin_op_0( + size_t i_z , + size_t i_x , + size_t cap_order , + Base* taylor ) +{ + // check assumptions + CPPAD_ASSERT_UNKNOWN( NumArg(AsinOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( NumRes(AsinOp) == 2 ); + CPPAD_ASSERT_UNKNOWN( 0 < cap_order ); + + // Taylor coefficients corresponding to argument and result + Base* x = taylor + i_x * cap_order; + Base* z = taylor + i_z * cap_order; + Base* b = z - cap_order; // called y in documentation + + z[0] = asin( x[0] ); + b[0] = sqrt( Base(1.0) - x[0] * x[0] ); +} +/*! +Compute reverse mode partial derivatives for result of op = AsinOp. + +The C++ source code corresponding to this operation is +\verbatim + z = asin(x) +\endverbatim +The auxillary result is +\verbatim + y = sqrt( 1 - x * x ) +\endverbatim +The value of y is computed along with the value of z. + +\copydetails CppAD::local::reverse_unary2_op +*/ + +template +void reverse_asin_op( + size_t d , + size_t i_z , + size_t i_x , + size_t cap_order , + const Base* taylor , + size_t nc_partial , + Base* partial ) +{ + // check assumptions + CPPAD_ASSERT_UNKNOWN( NumArg(AsinOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( NumRes(AsinOp) == 2 ); + CPPAD_ASSERT_UNKNOWN( d < cap_order ); + CPPAD_ASSERT_UNKNOWN( d < nc_partial ); + + // Taylor coefficients and partials corresponding to argument + const Base* x = taylor + i_x * cap_order; + Base* px = partial + i_x * nc_partial; + + // Taylor coefficients and partials corresponding to first result + const Base* z = taylor + i_z * cap_order; + Base* pz = partial + i_z * nc_partial; + + // Taylor coefficients and partials corresponding to auxillary result + const Base* b = z - cap_order; // called y in documentation + Base* pb = pz - nc_partial; + + Base inv_b0 = Base(1.0) / b[0]; + + // number of indices to access + size_t j = d; + size_t k; + while(j) + { + // scale partials w.r.t b[j] by 1 / b[0] + pb[j] = azmul(pb[j], inv_b0); + + // scale partials w.r.t z[j] by 1 / b[0] + pz[j] = azmul(pz[j], inv_b0); + + // update partials w.r.t b^0 + pb[0] -= azmul(pz[j], z[j]) + azmul(pb[j], b[j]); + + // update partial w.r.t. x^0 + px[0] -= azmul(pb[j], x[j]); + + // update partial w.r.t. x^j + px[j] += pz[j] - azmul(pb[j], x[0]); + + // further scale partial w.r.t. z[j] by 1 / j + pz[j] /= Base(double(j)); + + for(k = 1; k < j; k++) + { // update partials w.r.t b^(j-k) + pb[j-k] -= Base(double(k)) * azmul(pz[j], z[k]) + azmul(pb[j], b[k]); + + // update partials w.r.t. x^k + px[k] -= azmul(pb[j], x[j-k]); + + // update partials w.r.t. z^k + pz[k] -= Base(double(k)) * azmul(pz[j], b[j-k]); + } + --j; + } + + // j == 0 case + px[0] += azmul(pz[0] - azmul(pb[0], x[0]), inv_b0); +} + +} } // END_CPPAD_LOCAL_NAMESPACE +# endif diff --git a/build-config/cppad/include/cppad/local/asinh_op.hpp b/build-config/cppad/include/cppad/local/asinh_op.hpp new file mode 100644 index 00000000..84b16b57 --- /dev/null +++ b/build-config/cppad/include/cppad/local/asinh_op.hpp @@ -0,0 +1,264 @@ +# ifndef CPPAD_LOCAL_ASINH_OP_HPP +# define CPPAD_LOCAL_ASINH_OP_HPP + +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + + +namespace CppAD { namespace local { // BEGIN_CPPAD_LOCAL_NAMESPACE +/*! +\file asinh_op.hpp +Forward and reverse mode calculations for z = asinh(x). +*/ + + +/*! +Compute forward mode Taylor coefficient for result of op = AsinhOp. + +The C++ source code corresponding to this operation is +\verbatim + z = asinh(x) +\endverbatim +The auxillary result is +\verbatim + y = sqrt(1 + x * x) +\endverbatim +The value of y, and its derivatives, are computed along with the value +and derivatives of z. + +\copydetails CppAD::local::forward_unary2_op +*/ +template +void forward_asinh_op( + size_t p , + size_t q , + size_t i_z , + size_t i_x , + size_t cap_order , + Base* taylor ) +{ + // check assumptions + CPPAD_ASSERT_UNKNOWN( NumArg(AsinhOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( NumRes(AsinhOp) == 2 ); + CPPAD_ASSERT_UNKNOWN( q < cap_order ); + CPPAD_ASSERT_UNKNOWN( p <= q ); + + // Taylor coefficients corresponding to argument and result + Base* x = taylor + i_x * cap_order; + Base* z = taylor + i_z * cap_order; + Base* b = z - cap_order; // called y in documentation + + size_t k; + Base uj; + if( p == 0 ) + { z[0] = asinh( x[0] ); + uj = Base(1.0) + x[0] * x[0]; + b[0] = sqrt( uj ); + p++; + } + for(size_t j = p; j <= q; j++) + { uj = Base(0.0); + for(k = 0; k <= j; k++) + uj += x[k] * x[j-k]; + b[j] = Base(0.0); + z[j] = Base(0.0); + for(k = 1; k < j; k++) + { b[j] -= Base(double(k)) * b[k] * b[j-k]; + z[j] -= Base(double(k)) * z[k] * b[j-k]; + } + b[j] /= Base(double(j)); + z[j] /= Base(double(j)); + // + b[j] += uj / Base(2.0); + z[j] += x[j]; + // + b[j] /= b[0]; + z[j] /= b[0]; + } +} +/*! +Multiple directions forward mode Taylor coefficient for op = AsinhOp. + +The C++ source code corresponding to this operation is +\verbatim + z = asinh(x) +\endverbatim +The auxillary result is +\verbatim + y = sqrt(1 + x * x) +\endverbatim +The value of y, and its derivatives, are computed along with the value +and derivatives of z. + +\copydetails CppAD::local::forward_unary2_op_dir +*/ +template +void forward_asinh_op_dir( + size_t q , + size_t r , + size_t i_z , + size_t i_x , + size_t cap_order , + Base* taylor ) +{ + // check assumptions + CPPAD_ASSERT_UNKNOWN( NumArg(AcosOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( NumRes(AcosOp) == 2 ); + CPPAD_ASSERT_UNKNOWN( 0 < q ); + CPPAD_ASSERT_UNKNOWN( q < cap_order ); + + // Taylor coefficients corresponding to argument and result + size_t num_taylor_per_var = (cap_order-1) * r + 1; + Base* x = taylor + i_x * num_taylor_per_var; + Base* z = taylor + i_z * num_taylor_per_var; + Base* b = z - num_taylor_per_var; // called y in documentation + + size_t k, ell; + size_t m = (q-1) * r + 1; + for(ell = 0; ell < r; ell ++) + { Base uq = 2.0 * x[m + ell] * x[0]; + for(k = 1; k < q; k++) + uq += x[(k-1)*r+1+ell] * x[(q-k-1)*r+1+ell]; + b[m+ell] = Base(0.0); + z[m+ell] = Base(0.0); + for(k = 1; k < q; k++) + { b[m+ell] += Base(double(k)) * b[(k-1)*r+1+ell] * b[(q-k-1)*r+1+ell]; + z[m+ell] += Base(double(k)) * z[(k-1)*r+1+ell] * b[(q-k-1)*r+1+ell]; + } + b[m+ell] = ( uq / Base(2.0) - b[m+ell] / Base(double(q)) ) / b[0]; + z[m+ell] = ( x[m+ell] - z[m+ell] / Base(double(q)) ) / b[0]; + } +} + +/*! +Compute zero order forward mode Taylor coefficient for result of op = AsinhOp. + +The C++ source code corresponding to this operation is +\verbatim + z = asinh(x) +\endverbatim +The auxillary result is +\verbatim + y = sqrt( 1 + x * x ) +\endverbatim +The value of y is computed along with the value of z. + +\copydetails CppAD::local::forward_unary2_op_0 +*/ +template +void forward_asinh_op_0( + size_t i_z , + size_t i_x , + size_t cap_order , + Base* taylor ) +{ + // check assumptions + CPPAD_ASSERT_UNKNOWN( NumArg(AsinhOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( NumRes(AsinhOp) == 2 ); + CPPAD_ASSERT_UNKNOWN( 0 < cap_order ); + + // Taylor coefficients corresponding to argument and result + Base* x = taylor + i_x * cap_order; + Base* z = taylor + i_z * cap_order; + Base* b = z - cap_order; // called y in documentation + + z[0] = asinh( x[0] ); + b[0] = sqrt( Base(1.0) + x[0] * x[0] ); +} +/*! +Compute reverse mode partial derivatives for result of op = AsinhOp. + +The C++ source code corresponding to this operation is +\verbatim + z = asinh(x) +\endverbatim +The auxillary result is +\verbatim + y = sqrt( 1 + x * x ) +\endverbatim +The value of y is computed along with the value of z. + +\copydetails CppAD::local::reverse_unary2_op +*/ + +template +void reverse_asinh_op( + size_t d , + size_t i_z , + size_t i_x , + size_t cap_order , + const Base* taylor , + size_t nc_partial , + Base* partial ) +{ + // check assumptions + CPPAD_ASSERT_UNKNOWN( NumArg(AsinhOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( NumRes(AsinhOp) == 2 ); + CPPAD_ASSERT_UNKNOWN( d < cap_order ); + CPPAD_ASSERT_UNKNOWN( d < nc_partial ); + + // Taylor coefficients and partials corresponding to argument + const Base* x = taylor + i_x * cap_order; + Base* px = partial + i_x * nc_partial; + + // Taylor coefficients and partials corresponding to first result + const Base* z = taylor + i_z * cap_order; + Base* pz = partial + i_z * nc_partial; + + // Taylor coefficients and partials corresponding to auxillary result + const Base* b = z - cap_order; // called y in documentation + Base* pb = pz - nc_partial; + + Base inv_b0 = Base(1.0) / b[0]; + + // number of indices to access + size_t j = d; + size_t k; + while(j) + { + // scale partials w.r.t b[j] by 1 / b[0] + pb[j] = azmul(pb[j], inv_b0); + + // scale partials w.r.t z[j] by 1 / b[0] + pz[j] = azmul(pz[j], inv_b0); + + // update partials w.r.t b^0 + pb[0] -= azmul(pz[j], z[j]) + azmul(pb[j], b[j]); + + // update partial w.r.t. x^0 + px[0] += azmul(pb[j], x[j]); + + // update partial w.r.t. x^j + px[j] += pz[j] + azmul(pb[j], x[0]); + + // further scale partial w.r.t. z[j] by 1 / j + pz[j] /= Base(double(j)); + + for(k = 1; k < j; k++) + { // update partials w.r.t b^(j-k) + pb[j-k] -= Base(double(k)) * azmul(pz[j], z[k]) + azmul(pb[j], b[k]); + + // update partials w.r.t. x^k + px[k] += azmul(pb[j], x[j-k]); + + // update partials w.r.t. z^k + pz[k] -= Base(double(k)) * azmul(pz[j], b[j-k]); + } + --j; + } + + // j == 0 case + px[0] += azmul(pz[0] + azmul(pb[0], x[0]), inv_b0); +} + +} } // END_CPPAD_LOCAL_NAMESPACE +# endif diff --git a/build-config/cppad/include/cppad/local/atan_op.hpp b/build-config/cppad/include/cppad/local/atan_op.hpp new file mode 100644 index 00000000..1dbd2c2f --- /dev/null +++ b/build-config/cppad/include/cppad/local/atan_op.hpp @@ -0,0 +1,235 @@ +# ifndef CPPAD_LOCAL_ATAN_OP_HPP +# define CPPAD_LOCAL_ATAN_OP_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-17 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + + +namespace CppAD { namespace local { // BEGIN_CPPAD_LOCAL_NAMESPACE +/*! +\file atan_op.hpp +Forward and reverse mode calculations for z = atan(x). +*/ + + +/*! +Forward mode Taylor coefficient for result of op = AtanOp. + +The C++ source code corresponding to this operation is +\verbatim + z = atan(x) +\endverbatim +The auxillary result is +\verbatim + y = 1 + x * x +\endverbatim +The value of y, and its derivatives, are computed along with the value +and derivatives of z. + +\copydetails CppAD::local::forward_unary2_op +*/ +template +void forward_atan_op( + size_t p , + size_t q , + size_t i_z , + size_t i_x , + size_t cap_order , + Base* taylor ) +{ + // check assumptions + CPPAD_ASSERT_UNKNOWN( NumArg(AtanOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( NumRes(AtanOp) == 2 ); + CPPAD_ASSERT_UNKNOWN( q < cap_order ); + CPPAD_ASSERT_UNKNOWN( p <= q ); + + // Taylor coefficients corresponding to argument and result + Base* x = taylor + i_x * cap_order; + Base* z = taylor + i_z * cap_order; + Base* b = z - cap_order; // called y in documentation + + size_t k; + if( p == 0 ) + { z[0] = atan( x[0] ); + b[0] = Base(1.0) + x[0] * x[0]; + p++; + } + for(size_t j = p; j <= q; j++) + { + b[j] = Base(2.0) * x[0] * x[j]; + z[j] = Base(0.0); + for(k = 1; k < j; k++) + { b[j] += x[k] * x[j-k]; + z[j] -= Base(double(k)) * z[k] * b[j-k]; + } + z[j] /= Base(double(j)); + z[j] += x[j]; + z[j] /= b[0]; + } +} + +/*! +Multiple direction Taylor coefficient for op = AtanOp. + +The C++ source code corresponding to this operation is +\verbatim + z = atan(x) +\endverbatim +The auxillary result is +\verbatim + y = 1 + x * x +\endverbatim +The value of y, and its derivatives, are computed along with the value +and derivatives of z. + +\copydetails CppAD::local::forward_unary2_op_dir +*/ +template +void forward_atan_op_dir( + size_t q , + size_t r , + size_t i_z , + size_t i_x , + size_t cap_order , + Base* taylor ) +{ + // check assumptions + CPPAD_ASSERT_UNKNOWN( NumArg(AtanOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( NumRes(AtanOp) == 2 ); + CPPAD_ASSERT_UNKNOWN( 0 < q ); + CPPAD_ASSERT_UNKNOWN( q < cap_order ); + + // Taylor coefficients corresponding to argument and result + size_t num_taylor_per_var = (cap_order-1) * r + 1; + Base* x = taylor + i_x * num_taylor_per_var; + Base* z = taylor + i_z * num_taylor_per_var; + Base* b = z - num_taylor_per_var; // called y in documentation + + size_t m = (q-1) * r + 1; + for(size_t ell = 0; ell < r; ell++) + { b[m+ell] = Base(2.0) * x[m+ell] * x[0]; + z[m+ell] = Base(double(q)) * x[m+ell]; + for(size_t k = 1; k < q; k++) + { b[m+ell] += x[(k-1)*r+1+ell] * x[(q-k-1)*r+1+ell]; + z[m+ell] -= Base(double(k)) * z[(k-1)*r+1+ell] * b[(q-k-1)*r+1+ell]; + } + z[m+ell] /= ( Base(double(q)) * b[0] ); + } +} + +/*! +Zero order forward mode Taylor coefficient for result of op = AtanOp. + +The C++ source code corresponding to this operation is +\verbatim + z = atan(x) +\endverbatim +The auxillary result is +\verbatim + y = 1 + x * x +\endverbatim +The value of y is computed along with the value of z. + +\copydetails CppAD::local::forward_unary2_op_0 +*/ +template +void forward_atan_op_0( + size_t i_z , + size_t i_x , + size_t cap_order , + Base* taylor ) +{ + // check assumptions + CPPAD_ASSERT_UNKNOWN( NumArg(AtanOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( NumRes(AtanOp) == 2 ); + CPPAD_ASSERT_UNKNOWN( 0 < cap_order ); + + // Taylor coefficients corresponding to argument and result + Base* x = taylor + i_x * cap_order; + Base* z = taylor + i_z * cap_order; + Base* b = z - cap_order; // called y in documentation + + z[0] = atan( x[0] ); + b[0] = Base(1.0) + x[0] * x[0]; +} +/*! +Reverse mode partial derivatives for result of op = AtanOp. + +The C++ source code corresponding to this operation is +\verbatim + z = atan(x) +\endverbatim +The auxillary result is +\verbatim + y = 1 + x * x +\endverbatim +The value of y is computed along with the value of z. + +\copydetails CppAD::local::reverse_unary2_op +*/ + +template +void reverse_atan_op( + size_t d , + size_t i_z , + size_t i_x , + size_t cap_order , + const Base* taylor , + size_t nc_partial , + Base* partial ) +{ + // check assumptions + CPPAD_ASSERT_UNKNOWN( NumArg(AtanOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( NumRes(AtanOp) == 2 ); + CPPAD_ASSERT_UNKNOWN( d < cap_order ); + CPPAD_ASSERT_UNKNOWN( d < nc_partial ); + + // Taylor coefficients and partials corresponding to argument + const Base* x = taylor + i_x * cap_order; + Base* px = partial + i_x * nc_partial; + + // Taylor coefficients and partials corresponding to first result + const Base* z = taylor + i_z * cap_order; + Base* pz = partial + i_z * nc_partial; + + // Taylor coefficients and partials corresponding to auxillary result + const Base* b = z - cap_order; // called y in documentation + Base* pb = pz - nc_partial; + + Base inv_b0 = Base(1.0) / b[0]; + + // number of indices to access + size_t j = d; + size_t k; + while(j) + { // scale partials w.r.t z[j] and b[j] + pz[j] = azmul(pz[j], inv_b0); + pb[j] *= Base(2.0); + + pb[0] -= azmul(pz[j], z[j]); + px[j] += pz[j] + azmul(pb[j], x[0]); + px[0] += azmul(pb[j], x[j]); + + // more scaling of partials w.r.t z[j] + pz[j] /= Base(double(j)); + + for(k = 1; k < j; k++) + { pb[j-k] -= Base(double(k)) * azmul(pz[j], z[k]); + pz[k] -= Base(double(k)) * azmul(pz[j], b[j-k]); + px[k] += azmul(pb[j], x[j-k]); + } + --j; + } + px[0] += azmul(pz[0], inv_b0) + Base(2.0) * azmul(pb[0], x[0]); +} + +} } // END_CPPAD_LOCAL_NAMESPACE +# endif diff --git a/build-config/cppad/include/cppad/local/atanh_op.hpp b/build-config/cppad/include/cppad/local/atanh_op.hpp new file mode 100644 index 00000000..a1adc6af --- /dev/null +++ b/build-config/cppad/include/cppad/local/atanh_op.hpp @@ -0,0 +1,236 @@ +# ifndef CPPAD_LOCAL_ATANH_OP_HPP +# define CPPAD_LOCAL_ATANH_OP_HPP + +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + + +namespace CppAD { namespace local { // BEGIN_CPPAD_LOCAL_NAMESPACE +/*! +\file atanh_op.hpp +Forward and reverse mode calculations for z = atanh(x). +*/ + + +/*! +Forward mode Taylor coefficient for result of op = AtanhOp. + +The C++ source code corresponding to this operation is +\verbatim + z = atanh(x) +\endverbatim +The auxillary result is +\verbatim + y = 1 - x * x +\endverbatim +The value of y, and its derivatives, are computed along with the value +and derivatives of z. + +\copydetails CppAD::local::forward_unary2_op +*/ +template +void forward_atanh_op( + size_t p , + size_t q , + size_t i_z , + size_t i_x , + size_t cap_order , + Base* taylor ) +{ + // check assumptions + CPPAD_ASSERT_UNKNOWN( NumArg(AtanhOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( NumRes(AtanhOp) == 2 ); + CPPAD_ASSERT_UNKNOWN( q < cap_order ); + CPPAD_ASSERT_UNKNOWN( p <= q ); + + // Taylor coefficients corresponding to argument and result + Base* x = taylor + i_x * cap_order; + Base* z = taylor + i_z * cap_order; + Base* b = z - cap_order; // called y in documentation + + size_t k; + if( p == 0 ) + { z[0] = atanh( x[0] ); + b[0] = Base(1.0) - x[0] * x[0]; + p++; + } + for(size_t j = p; j <= q; j++) + { + b[j] = - Base(2.0) * x[0] * x[j]; + z[j] = Base(0.0); + for(k = 1; k < j; k++) + { b[j] -= x[k] * x[j-k]; + z[j] -= Base(double(k)) * z[k] * b[j-k]; + } + z[j] /= Base(double(j)); + z[j] += x[j]; + z[j] /= b[0]; + } +} + +/*! +Multiple direction Taylor coefficient for op = AtanhOp. + +The C++ source code corresponding to this operation is +\verbatim + z = atanh(x) +\endverbatim +The auxillary result is +\verbatim + y = 1 - x * x +\endverbatim +The value of y, and its derivatives, are computed along with the value +and derivatives of z. + +\copydetails CppAD::local::forward_unary2_op_dir +*/ +template +void forward_atanh_op_dir( + size_t q , + size_t r , + size_t i_z , + size_t i_x , + size_t cap_order , + Base* taylor ) +{ + // check assumptions + CPPAD_ASSERT_UNKNOWN( NumArg(AtanhOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( NumRes(AtanhOp) == 2 ); + CPPAD_ASSERT_UNKNOWN( 0 < q ); + CPPAD_ASSERT_UNKNOWN( q < cap_order ); + + // Taylor coefficients corresponding to argument and result + size_t num_taylor_per_var = (cap_order-1) * r + 1; + Base* x = taylor + i_x * num_taylor_per_var; + Base* z = taylor + i_z * num_taylor_per_var; + Base* b = z - num_taylor_per_var; // called y in documentation + + size_t m = (q-1) * r + 1; + for(size_t ell = 0; ell < r; ell++) + { b[m+ell] = - Base(2.0) * x[m+ell] * x[0]; + z[m+ell] = Base(double(q)) * x[m+ell]; + for(size_t k = 1; k < q; k++) + { b[m+ell] -= x[(k-1)*r+1+ell] * x[(q-k-1)*r+1+ell]; + z[m+ell] -= Base(double(k)) * z[(k-1)*r+1+ell] * b[(q-k-1)*r+1+ell]; + } + z[m+ell] /= ( Base(double(q)) * b[0] ); + } +} + +/*! +Zero order forward mode Taylor coefficient for result of op = AtanhOp. + +The C++ source code corresponding to this operation is +\verbatim + z = atanh(x) +\endverbatim +The auxillary result is +\verbatim + y = 1 - x * x +\endverbatim +The value of y is computed along with the value of z. + +\copydetails CppAD::local::forward_unary2_op_0 +*/ +template +void forward_atanh_op_0( + size_t i_z , + size_t i_x , + size_t cap_order , + Base* taylor ) +{ + // check assumptions + CPPAD_ASSERT_UNKNOWN( NumArg(AtanhOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( NumRes(AtanhOp) == 2 ); + CPPAD_ASSERT_UNKNOWN( 0 < cap_order ); + + // Taylor coefficients corresponding to argument and result + Base* x = taylor + i_x * cap_order; + Base* z = taylor + i_z * cap_order; + Base* b = z - cap_order; // called y in documentation + + z[0] = atanh( x[0] ); + b[0] = Base(1.0) - x[0] * x[0]; +} +/*! +Reverse mode partial derivatives for result of op = AtanhOp. + +The C++ source code corresponding to this operation is +\verbatim + z = atanh(x) +\endverbatim +The auxillary result is +\verbatim + y = 1 - x * x +\endverbatim +The value of y is computed along with the value of z. + +\copydetails CppAD::local::reverse_unary2_op +*/ + +template +void reverse_atanh_op( + size_t d , + size_t i_z , + size_t i_x , + size_t cap_order , + const Base* taylor , + size_t nc_partial , + Base* partial ) +{ + // check assumptions + CPPAD_ASSERT_UNKNOWN( NumArg(AtanhOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( NumRes(AtanhOp) == 2 ); + CPPAD_ASSERT_UNKNOWN( d < cap_order ); + CPPAD_ASSERT_UNKNOWN( d < nc_partial ); + + // Taylor coefficients and partials corresponding to argument + const Base* x = taylor + i_x * cap_order; + Base* px = partial + i_x * nc_partial; + + // Taylor coefficients and partials corresponding to first result + const Base* z = taylor + i_z * cap_order; + Base* pz = partial + i_z * nc_partial; + + // Taylor coefficients and partials corresponding to auxillary result + const Base* b = z - cap_order; // called y in documentation + Base* pb = pz - nc_partial; + + Base inv_b0 = Base(1.0) / b[0]; + + // number of indices to access + size_t j = d; + size_t k; + while(j) + { // scale partials w.r.t z[j] and b[j] + pz[j] = azmul(pz[j], inv_b0); + pb[j] *= Base(2.0); + + pb[0] -= azmul(pz[j], z[j]); + px[j] += pz[j] - azmul(pb[j], x[0]); + px[0] -= azmul(pb[j], x[j]); + + // more scaling of partials w.r.t z[j] + pz[j] /= Base(double(j)); + + for(k = 1; k < j; k++) + { pb[j-k] -= Base(double(k)) * azmul(pz[j], z[k]); + pz[k] -= Base(double(k)) * azmul(pz[j], b[j-k]); + px[k] -= azmul(pb[j], x[j-k]); + } + --j; + } + px[0] += azmul(pz[0], inv_b0) - Base(2.0) * azmul(pb[0], x[0]); +} + +} } // END_CPPAD_LOCAL_NAMESPACE +# endif diff --git a/build-config/cppad/include/cppad/local/atom_state.hpp b/build-config/cppad/include/cppad/local/atom_state.hpp new file mode 100644 index 00000000..ab1c1ba6 --- /dev/null +++ b/build-config/cppad/include/cppad/local/atom_state.hpp @@ -0,0 +1,32 @@ +# ifndef CPPAD_LOCAL_ATOM_STATE_HPP +# define CPPAD_LOCAL_ATOM_STATE_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-16 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +namespace CppAD { namespace local { // BEGIN_CPPAD_LOCAL_NAMESPACE + +enum enum_atom_state { + /// next AFunOp marks beginning of a atomic function call + start_atom, + + /// next FunapOp (FunavOp) is a parameter (variable) argument + arg_atom, + + /// next FunrpOp (FunrvOp) is a parameter (variable) result + ret_atom, + + /// next AFunOp marks end of a atomic function call + end_atom +}; + +} } // END_CPPAD_LOCAL_NAMESPACE +# endif diff --git a/build-config/cppad/include/cppad/local/atomic_index.hpp b/build-config/cppad/include/cppad/local/atomic_index.hpp new file mode 100644 index 00000000..ce6e88ba --- /dev/null +++ b/build-config/cppad/include/cppad/local/atomic_index.hpp @@ -0,0 +1,161 @@ +# ifndef CPPAD_LOCAL_ATOMIC_INDEX_HPP +# define CPPAD_LOCAL_ATOMIC_INDEX_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ +/*! +$begin atomic_index$$ +$spell + ptr +$$ + +$section Store and Retrieve Atomic Function Information by Index$$ + +$head Syntax$$ +$icode%index_out% = local::atomic_index<%Base%>( + %set_null%, %index_in%, %type%, %name%, %ptr% +)%$$ + +$head Prototype$$ +$srcthisfile% + 0%// BEGIN_ATOMIC_INDEX%// END_PROTOTYPE%1 +%$$ + +$head Base$$ +Is the base type for the tape for the atomic functions +that we are using an index to identify. + +$head Special Case$$ +In the special case, +$icode set_null$$ is true and $icode index_in$$ is zero. +For this case, $icode index_out$$ is set to +the number of atomic functions stored in $codei%atomic_index<%Base%>%$$ +and no information is stored or changed. +In this case, the atomic functions correspond to $icode index_in$$ from +one to $icode index_out$$ inclusive. + +$head set_null$$ +If this is not the special case: +This value should only be true during a call to an atomic function destructor. +If it is true, the $icode ptr$$ corresponding to $icode index_in$$ +is set to null. + +$head index_in$$ +If this is not the special case: + +$subhead zero$$ +The value $icode index_in$$ should only be zero +during a call to an atomic function constructor. +In this case, a copy of the input value of +$icode type$$, $codei%*%name%$$, and $icode ptr$$ are stored. +The value $icode index_out$$ +is the $icode index_in$$ value corresponding to these input values. + +$subhead non-zero$$ +If $icode index_in$$ is non-zero, +the information corresponding to this index is returned. + +$head type$$ +If this is not the special case: +If $icode index_in$$ is zero, $icode type$$ is an input. +Otherwise it is set to the value corresponding to this index. +The type corresponding to an index +is intended to be $code 2$$ for $cref atomic_two$$ functions +and $code 3$$ for $cref atomic_three$$ functions. + +$head name$$ +If this is not the special case: +If $icode index_in$$ is zero, $code name$$ is an input and must not be null. +Otherwise, if $icode name$$ is not null, $codei%*%name%$$ +is set to the name corresponding to $icode index_in$$. +Allowing for $icode name$$ to be null avoids +a string copy when it is not needed. + +$head ptr$$ +If this is not the special case: +If $icode index_in$$ is zero, $icode ptr$$ is an input. +Otherwise it is set to the value corresponding to $icode index_in$$. +In the special case where $icode set_null$$ is true, +$icode ptr$$ is set to the null pointer and this is the $icode ptr$$ value +corresponding to $icode index_in$$ for future calls to $code atomic_index$$. + +$head index_out$$ +If this is not the special case: +If $icode index_in$$ is zero, +$icode index_out$$ is non-zero and is the index value +corresponding to the input values for +$icode type$$, $codei%*%name%$$, and $icode ptr$$. +Otherwise, $index_out$$ is zero. + +$end +*/ +# include +# include + +namespace CppAD { namespace local { // BEGIN_CPPAD_LOCAL_NAMESPACE + +struct atomic_index_info { + size_t type; + std::string name; + void* ptr; +}; + +// BEGIN_ATOMIC_INDEX +template +size_t atomic_index( + bool set_null , + const size_t& index_in , + size_t& type , + std::string* name , + void*& ptr ) +// END_PROTOTYPE +{ // + // information for each index + static std::vector vec; +# ifndef NDEBUG + if( index_in == 0 || set_null ) + { CPPAD_ASSERT_KNOWN( ! thread_alloc::in_parallel(), + "calling atomic function constructor or destructor in parallel mode" + ); + } +# endif + if( set_null & (index_in == 0) ) + return vec.size(); + // + // case were we are retreving informaiton for an atomic function + if( 0 < index_in ) + { CPPAD_ASSERT_UNKNOWN( index_in <= vec.size() ) + // + // case where we are setting the pointer to null + if( set_null ) + vec[index_in-1].ptr = nullptr; + // + atomic_index_info& entry = vec[index_in - 1]; + type = entry.type; + ptr = entry.ptr; + if( name != nullptr ) + *name = entry.name; + return 0; + } + // + // case where we are storing information for an atomic function + atomic_index_info entry; + entry.type = type; + entry.name = *name; + entry.ptr = ptr; + vec.push_back(entry); + // + return vec.size(); +} + +} } // END_CPPAD_LOCAL_NAMESPACE + +# endif diff --git a/build-config/cppad/include/cppad/local/color_general.hpp b/build-config/cppad/include/cppad/local/color_general.hpp new file mode 100644 index 00000000..5a4e876a --- /dev/null +++ b/build-config/cppad/include/cppad/local/color_general.hpp @@ -0,0 +1,275 @@ +# ifndef CPPAD_LOCAL_COLOR_GENERAL_HPP +# define CPPAD_LOCAL_COLOR_GENERAL_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +# include +# include + +namespace CppAD { namespace local { // BEGIN_CPPAD_LOCAL_NAMESPACE +/*! +\file color_general.hpp +Coloring algorithm for a general sparse matrix. +*/ +// -------------------------------------------------------------------------- +/*! +Determine which rows of a general sparse matrix can be computed together; +i.e., do not have non-zero entries with the same column index. + +\tparam SizeVector +is a simple vector class with elements of type size_t. + +\tparam SetVector +is vector_of_sets class. + +\param pattern [in] +Is a representation of the sparsity pattern for the matrix. + +\param row [in] +is a vector specifying which row indices to compute. + +\param col [in] +is a vector, with the same size as row, +that specifies which column indices to compute. +For each valid index k, the index pair +(row[k], col[k]) must be present in the sparsity pattern. +It may be that some entries in the sparsity pattern do not need to be computed; +i.e, do not appear in the set of +(row[k], col[k]) entries. + +\param color [out] +is a vector with size m. +The input value of its elements does not matter. +Upon return, it is a coloring for the rows of the sparse matrix. +\n +\n +If for some i, color[i] == m, then +the i-th row does not appear in the vector row. +Otherwise, color[i] < m. +\n +\n +Suppose two differen rows, i != r have the same color and +column index j is such that both of the pairs +(i, j) and (r, j) appear in the sparsity pattern. +It follows that neither of these pairs appear in the set of +(row[k], col[k]) entries. +\n +\n +This routine tries to minimize, with respect to the choice of colors, +the maximum, with respct to k, of color[ row[k] ] +(not counting the indices k for which row[k] == m). +*/ +template +void color_general_cppad( + const SetVector& pattern , + const SizeVector& row , + const SizeVector& col , + CppAD::vector& color ) +{ + size_t K = row.size(); + size_t m = pattern.n_set(); + size_t n = pattern.end(); + + CPPAD_ASSERT_UNKNOWN( size_t( col.size() ) == K ); + CPPAD_ASSERT_UNKNOWN( size_t( color.size() ) == m ); + + // We define the set of rows, columns, and pairs that appear + // by the set ( row[k], col[k] ) for k = 0, ... , K-1. + + // initialize rows that appear + CppAD::vector row_appear(m); + for(size_t i = 0; i < m; i++) + row_appear[i] = false; + + // rows and columns that appear + SetVector c2r_appear, r2c_appear; + c2r_appear.resize(n, m); + r2c_appear.resize(m, n); + for(size_t k = 0; k < K; k++) + { CPPAD_ASSERT_KNOWN( pattern.is_element(row[k], col[k]) , + "color_general_cppad: requesting value for a matrix element\n" + "that is not in the matrice's sparsity pattern.\n" + "Such a value must be zero." + ); + row_appear[ row[k] ] = true; + c2r_appear.post_element(col[k], row[k]); + r2c_appear.post_element(row[k], col[k]); + } + // process posts + for(size_t j = 0; j < n; ++j) + c2r_appear.process_post(j); + for(size_t i = 0; i < m; ++i) + r2c_appear.process_post(i); + + // for each column, which rows are non-zero and do not appear + SetVector not_appear; + not_appear.resize(n, m); + for(size_t i = 0; i < m; i++) + { typename SetVector::const_iterator pattern_itr(pattern, i); + size_t j = *pattern_itr; + while( j != pattern.end() ) + { if( ! c2r_appear.is_element(j , i) ) + not_appear.post_element(j, i); + j = *(++pattern_itr); + } + } + // process posts + for(size_t j = 0; j < n; ++j) + not_appear.process_post(j); + + // initial coloring + color.resize(m); + size_t ell = 0; + for(size_t i = 0; i < m; i++) + { if( row_appear[i] ) + color[i] = ell++; + else + color[i] = m; + } + /* + See GreedyPartialD2Coloring Algorithm Section 3.6.2 of + Graph Coloring in Optimization Revisited by + Assefaw Gebremedhin, Fredrik Maane, Alex Pothen + + The algorithm above was modified (by Brad Bell) to take advantage of the + fact that only the entries (subset of the sparsity pattern) specified by + row and col need to be computed. + */ + CppAD::vector forbidden(m); + for(size_t i = 1; i < m; i++) // for each row that appears + if( color[i] < m ) + { + // initial all colors as ok for this row + // (value of forbidden for ell > initial color[i] does not matter) + for(ell = 0; ell <= color[i]; ell++) + forbidden[ell] = false; + + // ----------------------------------------------------- + // Forbid colors for which this row would destroy results: + // + // for each column that is non-zero for this row + typename SetVector::const_iterator pattern_itr(pattern, i); + size_t j = *pattern_itr; + while( j != pattern.end() ) + { // for each row that appears with this column + typename SetVector::const_iterator c2r_itr(c2r_appear, j); + size_t r = *c2r_itr; + while( r != c2r_appear.end() ) + { // if this is not the same row, forbid its color + if( (r < i) & (color[r] < m) ) + forbidden[ color[r] ] = true; + r = *(++c2r_itr); + } + j = *(++pattern_itr); + } + + + // ----------------------------------------------------- + // Forbid colors that destroy results needed for this row. + // + // for each column that appears with this row + typename SetVector::const_iterator r2c_itr(r2c_appear, i); + j = *r2c_itr; + while( j != r2c_appear.end() ) + { // For each row that is non-zero for this column + // (the appear rows have already been checked above). + typename SetVector::const_iterator not_itr(not_appear, j); + size_t r = *not_itr; + while( r != not_appear.end() ) + { // if this is not the same row, forbid its color + if( (r < i) & (color[r] < m) ) + forbidden[ color[r] ] = true; + r = *(++not_itr); + } + j = *(++r2c_itr); + } + + // pick the color with smallest index + ell = 0; + while( forbidden[ell] ) + { ell++; + CPPAD_ASSERT_UNKNOWN( ell <= color[i] ); + } + color[i] = ell; + } + return; +} + +# if CPPAD_HAS_COLPACK +/*! +Colpack version of determining which rows of a sparse matrix +can be computed together. + +\copydetails color_general +*/ +template +void color_general_colpack( + const SetVector& pattern , + const SizeVector& row , + const SizeVector& col , + CppAD::vector& color ) +{ + size_t m = pattern.n_set(); + size_t n = pattern.end(); + + // Determine number of non-zero entries in each row + CppAD::vector n_nonzero(m); + size_t n_nonzero_total = 0; + for(size_t i = 0; i < m; i++) + { n_nonzero[i] = 0; + typename SetVector::const_iterator pattern_itr(pattern, i); + size_t j = *pattern_itr; + while( j != pattern.end() ) + { n_nonzero[i]++; + j = *(++pattern_itr); + } + n_nonzero_total += n_nonzero[i]; + } + + // Allocate memory and fill in Adolc sparsity pattern + CppAD::vector adolc_pattern(m); + CppAD::vector adolc_memory(m + n_nonzero_total); + size_t i_memory = 0; + for(size_t i = 0; i < m; i++) + { adolc_pattern[i] = adolc_memory.data() + i_memory; + CPPAD_ASSERT_KNOWN( + std::numeric_limits::max() >= n_nonzero[i], + "Matrix is too large for colpack" + ); + adolc_pattern[i][0] = static_cast( n_nonzero[i] ); + typename SetVector::const_iterator pattern_itr(pattern, i); + size_t j = *pattern_itr; + size_t k = 1; + while(j != pattern.end() ) + { + CPPAD_ASSERT_KNOWN( + std::numeric_limits::max() >= j, + "Matrix is too large for colpack" + ); + adolc_pattern[i][k++] = static_cast( j ); + j = *(++pattern_itr); + } + CPPAD_ASSERT_UNKNOWN( k == 1 + n_nonzero[i] ); + i_memory += k; + } + CPPAD_ASSERT_UNKNOWN( i_memory == m + n_nonzero_total ); + + // Must use an external routine for this part of the calculation because + // ColPack/ColPackHeaders.h has as 'using namespace std' at global level. + cppad_colpack_general(color, m, n, adolc_pattern); + + return; +} +# endif // CPPAD_HAS_COLPACK + +} } // END_CPPAD_LOCAL_NAMESPACE +# endif diff --git a/build-config/cppad/include/cppad/local/color_symmetric.hpp b/build-config/cppad/include/cppad/local/color_symmetric.hpp new file mode 100644 index 00000000..cb6119ed --- /dev/null +++ b/build-config/cppad/include/cppad/local/color_symmetric.hpp @@ -0,0 +1,309 @@ +# ifndef CPPAD_LOCAL_COLOR_SYMMETRIC_HPP +# define CPPAD_LOCAL_COLOR_SYMMETRIC_HPP +# include +# include + +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-17 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +namespace CppAD { namespace local { // BEGIN_CPPAD_LOCAL_NAMESPACE +/*! +\file color_symmetric.hpp +Coloring algorithm for a symmetric sparse matrix. +*/ +// -------------------------------------------------------------------------- +/*! +CppAD algorithm for determining which rows of a symmetric sparse matrix can be +computed together. + +\tparam SizeVector +is a simple vector class with elements of type size_t. + +\tparam SetVector +is a vector_of_sets class. + +\param pattern [in] +Is a representation of the sparsity pattern for the matrix. + +\param row [in/out] +is a vector specifying which row indices to compute. + +\param col [in/out] +is a vector, with the same size as row, +that specifies which column indices to compute. +\n +\n +Input: +For each valid index k, the index pair +(row[k], col[k]) must be present in the sparsity pattern. +It may be that some entries in the sparsity pattern do not need to be computed; +i.e, do not appear in the set of +(row[k], col[k]) entries. +\n +\n +Output: +On output, some of row and column indices may have been swapped +\code + std::swap( row[k], col[k] ) +\endcode +So the the the color for row[k] can be used to compute entry +(row[k], col[k]). + +\param color [out] +is a vector with size m. +The input value of its elements does not matter. +Upon return, it is a coloring for the rows of the sparse matrix. +Note that if color[i] == m, then there is no index k for which +row[k] == i (for the return value of row). +\n +\n +Fix any (i, j) in the sparsity pattern. +Suppose that there is a row index i1 with +i1 != i, color[i1] == color[i] and (i1, j) is in the sparsity pattern. +If follows that for all j1 with +j1 != j and color[j1] == color[j], +(j1, i ) is not in the sparsity pattern. +\n +\n +This routine tries to minimize, with respect to the choice of colors, +the maximum, with respect to k, of color[ row[k] ]. +*/ +template +void color_symmetric_cppad( + const SetVector& pattern , + CppAD::vector& row , + CppAD::vector& col , + CppAD::vector& color ) +{ + size_t K = row.size(); + size_t m = pattern.n_set(); + CPPAD_ASSERT_UNKNOWN( m == pattern.end() ); + CPPAD_ASSERT_UNKNOWN( color.size() == m ); + CPPAD_ASSERT_UNKNOWN( col.size() == K ); + + // row, column pairs that appear in ( row[k], col[k] ) + CppAD::vector< std::set > pair_needed(m); + std::set::iterator itr1, itr2; + for(size_t k1 = 0; k1 < K; k1++) + { CPPAD_ASSERT_UNKNOWN( pattern.is_element(row[k1], col[k1]) ); + pair_needed[ row[k1] ].insert( col[k1] ); + pair_needed[ col[k1] ].insert( row[k1] ); + } + + // order the rows decending by number of pairs needed + CppAD::vector key(m), order2row(m); + for(size_t i1 = 0; i1 < m; i1++) + { CPPAD_ASSERT_UNKNOWN( pair_needed[i1].size() <= m ); + key[i1] = m - pair_needed[i1].size(); + } + CppAD::index_sort(key, order2row); + + // mapping from order index to row index + CppAD::vector row2order(m); + for(size_t o1 = 0; o1 < m; o1++) + row2order[ order2row[o1] ] = o1; + + // initial coloring + color.resize(m); + size_t c1 = 0; + for(size_t o1 = 0; o1 < m; o1++) + { size_t i1 = order2row[o1]; + if( pair_needed[i1].empty() ) + color[i1] = m; + else + color[i1] = c1++; + } + + // which colors are forbidden for this row + CppAD::vector forbidden(m); + + // must start with row zero so that we remove results computed for it + for(size_t o1 = 0; o1 < m; o1++) // for each row that appears (in order) + if( color[ order2row[o1] ] < m ) + { size_t i1 = order2row[o1]; + c1 = color[i1]; + + // initial all colors as ok for this row + // (value of forbidden for c > c1 does not matter) + for(size_t c2 = 0; c2 <= c1; c2++) + forbidden[c2] = false; + + // ----------------------------------------------------- + // Forbid grouping with rows that would destroy results that are + // needed for this row. + itr1 = pair_needed[i1].begin(); + while( itr1 != pair_needed[i1].end() ) + { // entry (i1, j1) is needed for this row + size_t j1 = *itr1; + + // Forbid rows i2 != i1 that have non-zero sparsity at (i2, j1). + // Note that this is the same as non-zero sparsity at (j1, i2) + typename SetVector::const_iterator pattern_itr(pattern, j1); + size_t i2 = *pattern_itr; + while( i2 != pattern.end() ) + { size_t c2 = color[i2]; + if( c2 < c1 ) + forbidden[c2] = true; + i2 = *(++pattern_itr); + } + itr1++; + } + // ----------------------------------------------------- + // Forbid grouping with rows that this row would destroy results for + for(size_t o2 = 0; o2 < o1; o2++) + { size_t i2 = order2row[o2]; + size_t c2 = color[i2]; + itr2 = pair_needed[i2].begin(); + while( itr2 != pair_needed[i2].end() ) + { size_t j2 = *itr2; + // row i2 needs pair (i2, j2). + // Forbid grouping with i1 if (i1, j2) has non-zero sparsity + if( pattern.is_element(i1, j2) ) + forbidden[c2] = true; + itr2++; + } + } + + // pick the color with smallest index + size_t c2 = 0; + while( forbidden[c2] ) + { c2++; + CPPAD_ASSERT_UNKNOWN( c2 <= c1 ); + } + color[i1] = c2; + + // no longer need results that are computed by this row + itr1 = pair_needed[i1].begin(); + while( itr1 != pair_needed[i1].end() ) + { size_t j1 = *itr1; + if( row2order[j1] > o1 ) + { itr2 = pair_needed[j1].find(i1); + if( itr2 != pair_needed[j1].end() ) + { pair_needed[j1].erase(itr2); + if( pair_needed[j1].empty() ) + color[j1] = m; + } + } + itr1++; + } + } + + // determine which sparsity entries need to be reflected + for(size_t k1 = 0; k1 < row.size(); k1++) + { size_t i1 = row[k1]; + size_t j1 = col[k1]; + itr1 = pair_needed[i1].find(j1); + if( itr1 == pair_needed[i1].end() ) + { row[k1] = j1; + col[k1] = i1; +# ifndef NDEBUG + itr1 = pair_needed[j1].find(i1); + CPPAD_ASSERT_UNKNOWN( itr1 != pair_needed[j1].end() ); +# endif + } + } + return; +} + +// -------------------------------------------------------------------------- +/*! +Colpack algorithm for determining which rows of a symmetric sparse matrix +can be computed together. + +\copydetails CppAD::local::color_symmetric_cppad +*/ +template +void color_symmetric_colpack( + const SetVector& pattern , + CppAD::vector& row , + CppAD::vector& col , + CppAD::vector& color ) +{ +# if ! CPPAD_HAS_COLPACK + CPPAD_ASSERT_UNKNOWN(false); + return; +# else + size_t i, j, k; + size_t m = pattern.n_set(); + CPPAD_ASSERT_UNKNOWN( m == pattern.end() ); + CPPAD_ASSERT_UNKNOWN( row.size() == col.size() ); + + // Determine number of non-zero entries in each row + CppAD::vector n_nonzero(m); + size_t n_nonzero_total = 0; + for(i = 0; i < m; i++) + { n_nonzero[i] = 0; + typename SetVector::const_iterator pattern_itr(pattern, i); + j = *pattern_itr; + while( j != pattern.end() ) + { n_nonzero[i]++; + j = *(++pattern_itr); + } + n_nonzero_total += n_nonzero[i]; + } + + // Allocate memory and fill in Adolc sparsity pattern + CppAD::vector adolc_pattern(m); + CppAD::vector adolc_memory(m + n_nonzero_total); + size_t i_memory = 0; + for(i = 0; i < m; i++) + { adolc_pattern[i] = adolc_memory.data() + i_memory; + CPPAD_ASSERT_KNOWN( + std::numeric_limits::max() >= n_nonzero[i], + "Matrix is too large for colpack" + ); + adolc_pattern[i][0] = static_cast( n_nonzero[i] ); + typename SetVector::const_iterator pattern_itr(pattern, i); + j = *pattern_itr; + k = 1; + while(j != pattern.end() ) + { + CPPAD_ASSERT_KNOWN( + std::numeric_limits::max() >= j, + "Matrix is too large for colpack" + ); + adolc_pattern[i][k++] = static_cast( j ); + j = *(++pattern_itr); + } + CPPAD_ASSERT_UNKNOWN( k == 1 + n_nonzero[i] ); + i_memory += k; + } + CPPAD_ASSERT_UNKNOWN( i_memory == m + n_nonzero_total ); + + // Must use an external routine for this part of the calculation because + // ColPack/ColPackHeaders.h has as 'using namespace std' at global level. + cppad_colpack_symmetric(color, m, adolc_pattern); + + // determine which sparsity entries need to be reflected + for(size_t k1 = 0; k1 < row.size(); k1++) + { size_t i1 = row[k1]; + size_t j1 = col[k1]; + bool reflect = false; + for(size_t i2 = 0; i2 < m; i2++) + if( (i1 != i2) & (color[i1]==color[i2]) ) + { for(size_t k2 = 1; k2 <= adolc_pattern[i2][0]; k2++) + { size_t j2 = adolc_pattern[i2][k2]; + reflect |= (j1 == j2); + } + } + if( reflect ) + { row[k1] = j1; + col[k1] = i1; + } + } + return; +# endif // CPPAD_HAS_COLPACK +} + +} } // END_CPPAD_LOCAL_NAMESPACE + +# endif diff --git a/build-config/cppad/include/cppad/local/comp_op.hpp b/build-config/cppad/include/cppad/local/comp_op.hpp new file mode 100644 index 00000000..e9098da1 --- /dev/null +++ b/build-config/cppad/include/cppad/local/comp_op.hpp @@ -0,0 +1,420 @@ +# ifndef CPPAD_LOCAL_COMP_OP_HPP +# define CPPAD_LOCAL_COMP_OP_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-18 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + + +namespace CppAD { namespace local { // BEGIN_CPPAD_LOCAL_NAMESPACE +/*! +\file comp_op.hpp +Zero order forward mode check how many comparisons changed. +*/ + +// -------------------------------- <= ----------------------------------- +/*! +Zero order forward mode comparison check that left <= right + +\param count +It the condition is not true, ths counter is incremented by one. + +\param arg +parameter[ arg[0] ] is the left operand and +parameter[ arg[1] ] is the right operand. + +\param parameter +vector of parameter values. +*/ +template +void forward_lepp_op_0( + size_t& count , + const addr_t* arg , + const Base* parameter ) +{ + // check assumptions + CPPAD_ASSERT_UNKNOWN( NumArg(LeppOp) == 2 ); + CPPAD_ASSERT_UNKNOWN( NumRes(LeppOp) == 0 ); + + // Taylor coefficients corresponding to arguments and result + Base x = parameter[ arg[0] ]; + Base y = parameter[ arg[1] ]; + + count += size_t( GreaterThanZero(x - y) ); +} +/*! +Zero order forward mode comparison check that left <= right + +\param count +It the condition is not true, ths counter is incremented by one. + +\param arg +parameter[ arg[0] ] is the left operand and +taylor[ size_t(arg[1]) * cap_order + 0 ] is the zero order Taylor coefficient +for the right operand. + +\param parameter +vector of parameter values. + +\param cap_order +number of Taylor coefficients allocated for each variable + +\param taylor +vector of taylor coefficients. +*/ +template +void forward_lepv_op_0( + size_t& count , + const addr_t* arg , + const Base* parameter , + size_t cap_order , + Base* taylor ) +{ + // check assumptions + CPPAD_ASSERT_UNKNOWN( NumArg(LepvOp) == 2 ); + CPPAD_ASSERT_UNKNOWN( NumRes(LepvOp) == 0 ); + + // Taylor coefficients corresponding to arguments and result + Base x = parameter[ arg[0] ]; + Base* y = taylor + size_t(arg[1]) * cap_order; + + count += GreaterThanZero(x - y[0]); +} +/*! +Zero order forward mode comparison check that left <= right + +\param count +It the condition is not true, ths counter is incremented by one. + +\param arg +taylor[ size_t(arg[0]) * cap_order + 0 ] is the zero order Taylor coefficient +for the left operand and parameter[ arg[1] ] is the right operand + +\param parameter +vector of parameter values. + +\param cap_order +number of Taylor coefficients allocated for each variable + +\param taylor +vector of taylor coefficients. +*/ +template +void forward_levp_op_0( + size_t& count , + const addr_t* arg , + const Base* parameter , + size_t cap_order , + Base* taylor ) +{ + // check assumptions + CPPAD_ASSERT_UNKNOWN( NumArg(LevpOp) == 2 ); + CPPAD_ASSERT_UNKNOWN( NumRes(LevpOp) == 0 ); + + // Taylor coefficients corresponding to arguments and result + Base* x = taylor + size_t(arg[0]) * cap_order; + Base y = parameter[ arg[1] ]; + + count += GreaterThanZero(x[0] - y); +} +/*! +Zero order forward mode comparison check that left <= right + +\param count +It the condition is not true, ths counter is incremented by one. + +\param arg +taylor[ size_t(arg[0]) * cap_order + 0 ] is the zero order Taylor coefficient +for the left operand and +taylor[ size_t(arg[1]) * cap_order + 0 ] is the zero order Taylor coefficient +for the right operand. + +\param parameter +vector of parameter values. + +\param cap_order +number of Taylor coefficients allocated for each variable + +\param taylor +vector of taylor coefficients. +*/ +template +void forward_levv_op_0( + size_t& count , + const addr_t* arg , + const Base* parameter , + size_t cap_order , + Base* taylor ) +{ + // check assumptions + CPPAD_ASSERT_UNKNOWN( NumArg(LevvOp) == 2 ); + CPPAD_ASSERT_UNKNOWN( NumRes(LevvOp) == 0 ); + + // Taylor coefficients corresponding to arguments and result + Base* x = taylor + size_t(arg[0]) * cap_order; + Base* y = taylor + size_t(arg[1]) * cap_order; + + count += GreaterThanZero(x[0] - y[0]); +} +// ------------------------------- < ------------------------------------- +/*! +Zero order forward mode comparison check that left < right + +\param count +It the condition is not true, ths counter is incremented by one. + +\param arg +parameter[ arg[0] ] is the left operand and +parameter[ arg[1] ] is the right operand. + +\param parameter +vector of parameter values. +*/ +template +void forward_ltpp_op_0( + size_t& count , + const addr_t* arg , + const Base* parameter ) +{ + // check assumptions + CPPAD_ASSERT_UNKNOWN( NumArg(LtppOp) == 2 ); + CPPAD_ASSERT_UNKNOWN( NumRes(LtppOp) == 0 ); + + // Taylor coefficients corresponding to arguments and result + Base x = parameter[ arg[0] ]; + Base y = parameter[ arg[1] ]; + + count += GreaterThanOrZero(x - y); +} +/*! +Zero order forward mode comparison check that left < right + +\copydetails CppAD::local::forward_lepv_op_0 +*/ +template +void forward_ltpv_op_0( + size_t& count , + const addr_t* arg , + const Base* parameter , + size_t cap_order , + Base* taylor ) +{ + // check assumptions + CPPAD_ASSERT_UNKNOWN( NumArg(LtpvOp) == 2 ); + CPPAD_ASSERT_UNKNOWN( NumRes(LtpvOp) == 0 ); + + // Taylor coefficients corresponding to arguments and result + Base x = parameter[ arg[0] ]; + Base* y = taylor + size_t(arg[1]) * cap_order; + + count += GreaterThanOrZero(x - y[0]); +} +/*! +Zero order forward mode comparison check that left < right + +\copydetails CppAD::local::forward_levp_op_0 +*/ +template +void forward_ltvp_op_0( + size_t& count , + const addr_t* arg , + const Base* parameter , + size_t cap_order , + Base* taylor ) +{ + // check assumptions + CPPAD_ASSERT_UNKNOWN( NumArg(LtvpOp) == 2 ); + CPPAD_ASSERT_UNKNOWN( NumRes(LtvpOp) == 0 ); + + // Taylor coefficients corresponding to arguments and result + Base* x = taylor + size_t(arg[0]) * cap_order; + Base y = parameter[ arg[1] ]; + + count += GreaterThanOrZero(x[0] - y); +} +/*! +Zero order forward mode comparison check that left < right + +\copydetails CppAD::local::forward_levv_op_0 +*/ +template +void forward_ltvv_op_0( + size_t& count , + const addr_t* arg , + const Base* parameter , + size_t cap_order , + Base* taylor ) +{ + // check assumptions + CPPAD_ASSERT_UNKNOWN( NumArg(LtvvOp) == 2 ); + CPPAD_ASSERT_UNKNOWN( NumRes(LtvvOp) == 0 ); + + // Taylor coefficients corresponding to arguments and result + Base* x = taylor + size_t(arg[0]) * cap_order; + Base* y = taylor + size_t(arg[1]) * cap_order; + + count += GreaterThanOrZero(x[0] - y[0]); +} +// ------------------------------ == ------------------------------------- +/*! +Zero order forward mode comparison check that left == right + +\param count +It the condition is not true, ths counter is incremented by one. + +\param arg +parameter[ arg[0] ] is the left operand and +parameter[ arg[1] ] is the right operand. + +\param parameter +vector of parameter values. +*/ +template +void forward_eqpp_op_0( + size_t& count , + const addr_t* arg , + const Base* parameter ) +{ + // check assumptions + CPPAD_ASSERT_UNKNOWN( NumArg(EqppOp) == 2 ); + CPPAD_ASSERT_UNKNOWN( NumRes(EqppOp) == 0 ); + + // Taylor coefficients corresponding to arguments and result + Base x = parameter[ arg[0] ]; + Base y = parameter[ arg[1] ]; + + count += size_t(x != y); +} +/*! +Zero order forward mode comparison check that left == right + +\copydetails CppAD::local::forward_lepv_op_0 +*/ +template +void forward_eqpv_op_0( + size_t& count , + const addr_t* arg , + const Base* parameter , + size_t cap_order , + Base* taylor ) +{ + // check assumptions + CPPAD_ASSERT_UNKNOWN( NumArg(EqpvOp) == 2 ); + CPPAD_ASSERT_UNKNOWN( NumRes(EqpvOp) == 0 ); + + // Taylor coefficients corresponding to arguments and result + Base x = parameter[ arg[0] ]; + Base* y = taylor + size_t(arg[1]) * cap_order; + + count += size_t(x != y[0]); +} +/*! +Zero order forward mode comparison check that left == right + +\copydetails CppAD::local::forward_levv_op_0 +*/ +template +void forward_eqvv_op_0( + size_t& count , + const addr_t* arg , + const Base* parameter , + size_t cap_order , + Base* taylor ) +{ + // check assumptions + CPPAD_ASSERT_UNKNOWN( NumArg(EqvvOp) == 2 ); + CPPAD_ASSERT_UNKNOWN( NumRes(EqvvOp) == 0 ); + + // Taylor coefficients corresponding to arguments and result + Base* x = taylor + size_t(arg[0]) * cap_order; + Base* y = taylor + size_t(arg[1]) * cap_order; + + count += size_t(x[0] != y[0]); +} +// -------------------------------- != ----------------------------------- +/*! +Zero order forward mode comparison check that left != right + +\param count +It the condition is not true, ths counter is incremented by one. + +\param arg +parameter[ arg[0] ] is the left operand and +parameter[ arg[1] ] is the right operand. + +\param parameter +vector of parameter values. +*/ +template +void forward_nepp_op_0( + size_t& count , + const addr_t* arg , + const Base* parameter ) +{ + // check assumptions + CPPAD_ASSERT_UNKNOWN( NumArg(NeppOp) == 2 ); + CPPAD_ASSERT_UNKNOWN( NumRes(NeppOp) == 0 ); + + // Taylor coefficients corresponding to arguments and result + Base x = parameter[ arg[0] ]; + Base y = parameter[ arg[1] ]; + + count += size_t(x == y); +} +/*! +Zero order forward mode comparison check that left != right + +\copydetails CppAD::local::forward_lepv_op_0 +*/ +template +void forward_nepv_op_0( + size_t& count , + const addr_t* arg , + const Base* parameter , + size_t cap_order , + Base* taylor ) +{ + // check assumptions + CPPAD_ASSERT_UNKNOWN( NumArg(NepvOp) == 2 ); + CPPAD_ASSERT_UNKNOWN( NumRes(NepvOp) == 0 ); + + // Taylor coefficients corresponding to arguments and result + Base x = parameter[ arg[0] ]; + Base* y = taylor + size_t(arg[1]) * cap_order; + + count += size_t(x == y[0]); +} +/*! +Zero order forward mode comparison check that left != right + +\copydetails CppAD::local::forward_levv_op_0 +*/ +template +void forward_nevv_op_0( + size_t& count , + const addr_t* arg , + const Base* parameter , + size_t cap_order , + Base* taylor ) +{ + // check assumptions + CPPAD_ASSERT_UNKNOWN( NumArg(NevvOp) == 2 ); + CPPAD_ASSERT_UNKNOWN( NumRes(NevvOp) == 0 ); + + // Taylor coefficients corresponding to arguments and result + Base* x = taylor + size_t(arg[0]) * cap_order; + Base* y = taylor + size_t(arg[1]) * cap_order; + + count += size_t(x[0] == y[0]); +} + + +} } // END_CPPAD_LOCAL_NAMESPACE +# endif diff --git a/build-config/cppad/include/cppad/local/cond_op.hpp b/build-config/cppad/include/cppad/local/cond_op.hpp new file mode 100644 index 00000000..7cc1dd27 --- /dev/null +++ b/build-config/cppad/include/cppad/local/cond_op.hpp @@ -0,0 +1,1317 @@ +# ifndef CPPAD_LOCAL_COND_OP_HPP +# define CPPAD_LOCAL_COND_OP_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +namespace CppAD { namespace local { // BEGIN_CPPAD_LOCAL_NAMESPACE +/*! +\file cond_op.hpp +Forward, reverse, and sparse operations for conditional expressions. +*/ + +/*! +Shared documentation for conditional expressions (not called). + + +The C++ source code coresponding to this operation is +\verbatim + z = CondExpRel(y_0, y_1, y_2, y_3) +\endverbatim +where Rel is one of the following: Lt, Le, Eq, Ge, Gt. + +\tparam Base +base type for the operator; i.e., this operation was recorded +using AD< Base > and computations by this routine are done using type + Base. + +\param i_z +is the AD variable index corresponding to the variable z. + +\param arg +\n + arg[0] +is static cast to size_t from the enum type +\verbatim + enum CompareOp { + CompareLt, + CompareLe, + CompareEq, + CompareGe, + CompareGt, + CompareNe + } +\endverbatim +for this operation. +Note that arg[0] cannot be equal to CompareNe. +\n +\n + arg[1] & 1 +\n +If this is zero, y_0 is a parameter. Otherwise it is a variable. +\n +\n + arg[1] & 2 +\n +If this is zero, y_1 is a parameter. Otherwise it is a variable. +\n +\n + arg[1] & 4 +\n +If this is zero, y_2 is a parameter. Otherwise it is a variable. +\n +\n + arg[1] & 8 +\n +If this is zero, y_3 is a parameter. Otherwise it is a variable. +\n +\n + arg[2 + j ] for j = 0, 1, 2, 3 +\n +is the index corresponding to y_j. + +\param num_par +is the total number of values in the vector parameter. + +\param parameter +For j = 0, 1, 2, 3, +if y_j is a parameter, parameter [ arg[2 + j] ] is its value. + +\param cap_order +number of columns in the matrix containing the Taylor coefficients. + +\par Checked Assertions +\li NumArg(CExpOp) == 6 +\li NumRes(CExpOp) == 1 +\li arg[0] < static_cast ( CompareNe ) +\li arg[1] != 0; i.e., not all of y_0, y_1, y_2, y_3 are parameters. +\li For j = 0, 1, 2, 3 if y_j is a parameter, arg[2+j] < num_par. + +*/ +template +void conditional_exp_op( + size_t i_z , + const addr_t* arg , + size_t num_par , + const Base* parameter , + size_t cap_order ) +{ // This routine is only for documentation, it should never be used + CPPAD_ASSERT_UNKNOWN( false ); +} + +/*! +Shared documentation for conditional expression sparse operations (not called). + + +The C++ source code coresponding to this operation is +\verbatim + z = CondExpRel(y_0, y_1, y_2, y_3) +\endverbatim +where Rel is one of the following: Lt, Le, Eq, Ge, Gt. + +\tparam Vector_set +is the type used for vectors of sets. It can be either +sparse::pack_setvec or sparse::list_setvec. + +\param i_z +is the AD variable index corresponding to the variable z. + +\param arg +\n + arg[0] +is static cast to size_t from the enum type +\verbatim + enum CompareOp { + CompareLt, + CompareLe, + CompareEq, + CompareGe, + CompareGt, + CompareNe + } +\endverbatim +for this operation. +Note that arg[0] cannot be equal to CompareNe. +\n +\n + arg[1] & 1 +\n +If this is zero, y_0 is a parameter. Otherwise it is a variable. +\n +\n + arg[1] & 2 +\n +If this is zero, y_1 is a parameter. Otherwise it is a variable. +\n +\n + arg[1] & 4 +\n +If this is zero, y_2 is a parameter. Otherwise it is a variable. +\n +\n + arg[1] & 8 +\n +If this is zero, y_3 is a parameter. Otherwise it is a variable. +\n +\n + arg[2 + j ] for j = 0, 1, 2, 3 +\n +is the index corresponding to y_j. + +\param num_par +is the total number of values in the vector parameter. + +\par Checked Assertions +\li NumArg(CExpOp) == 6 +\li NumRes(CExpOp) == 1 +\li arg[0] < static_cast ( CompareNe ) +\li arg[1] != 0; i.e., not all of y_0, y_1, y_2, y_3 are parameters. +\li For j = 0, 1, 2, 3 if y_j is a parameter, arg[2+j] < num_par. + +*/ +template +void sparse_conditional_exp_op( + size_t i_z , + const addr_t* arg , + size_t num_par ) +{ // This routine is only for documentation, it should never be used + CPPAD_ASSERT_UNKNOWN( false ); +} + +/*! +Compute forward mode Taylor coefficients for op = CExpOp. + + +The C++ source code coresponding to this operation is +\verbatim + z = CondExpRel(y_0, y_1, y_2, y_3) +\endverbatim +where Rel is one of the following: Lt, Le, Eq, Ge, Gt. + +\tparam Base +base type for the operator; i.e., this operation was recorded +using AD< Base > and computations by this routine are done using type + Base. + +\param i_z +is the AD variable index corresponding to the variable z. + +\param arg +\n + arg[0] +is static cast to size_t from the enum type +\verbatim + enum CompareOp { + CompareLt, + CompareLe, + CompareEq, + CompareGe, + CompareGt, + CompareNe + } +\endverbatim +for this operation. +Note that arg[0] cannot be equal to CompareNe. +\n +\n + arg[1] & 1 +\n +If this is zero, y_0 is a parameter. Otherwise it is a variable. +\n +\n + arg[1] & 2 +\n +If this is zero, y_1 is a parameter. Otherwise it is a variable. +\n +\n + arg[1] & 4 +\n +If this is zero, y_2 is a parameter. Otherwise it is a variable. +\n +\n + arg[1] & 8 +\n +If this is zero, y_3 is a parameter. Otherwise it is a variable. +\n +\n + arg[2 + j ] for j = 0, 1, 2, 3 +\n +is the index corresponding to y_j. + +\param num_par +is the total number of values in the vector parameter. + +\param parameter +For j = 0, 1, 2, 3, +if y_j is a parameter, parameter [ arg[2 + j] ] is its value. + +\param cap_order +number of columns in the matrix containing the Taylor coefficients. + +\par Checked Assertions +\li NumArg(CExpOp) == 6 +\li NumRes(CExpOp) == 1 +\li arg[0] < static_cast ( CompareNe ) +\li arg[1] != 0; i.e., not all of y_0, y_1, y_2, y_3 are parameters. +\li For j = 0, 1, 2, 3 if y_j is a parameter, arg[2+j] < num_par. + + +\param p +is the lowest order of the Taylor coefficient of z that we are computing. + +\param q +is the highest order of the Taylor coefficient of z that we are computing. + +\param taylor +\b Input: +For j = 0, 1, 2, 3 and k = 0 , ... , q, +if y_j is a variable then +taylor [ arg[2+j] * cap_order + k ] +is the k-th order Taylor coefficient corresponding to y_j. +\n +\b Input: taylor [ i_z * cap_order + k ] +for k = 0 , ... , p-1, +is the k-th order Taylor coefficient corresponding to z. +\n +\b Output: taylor [ i_z * cap_order + k ] +for k = p , ... , q, +is the k-th order Taylor coefficient corresponding to z. + +*/ +template +void forward_cond_op( + size_t p , + size_t q , + size_t i_z , + const addr_t* arg , + size_t num_par , + const Base* parameter , + size_t cap_order , + Base* taylor ) +{ Base y_0, y_1, y_2, y_3; + Base zero(0); + Base* z = taylor + i_z * cap_order; + + CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) < static_cast (CompareNe) ); + CPPAD_ASSERT_UNKNOWN( NumArg(CExpOp) == 6 ); + CPPAD_ASSERT_UNKNOWN( NumRes(CExpOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( arg[1] != 0 ); + + if( arg[1] & 1 ) + { + y_0 = taylor[ size_t(arg[2]) * cap_order + 0 ]; + } + else + { CPPAD_ASSERT_UNKNOWN( size_t(arg[2]) < num_par ); + y_0 = parameter[ arg[2] ]; + } + if( arg[1] & 2 ) + { + y_1 = taylor[ size_t(arg[3]) * cap_order + 0 ]; + } + else + { CPPAD_ASSERT_UNKNOWN( size_t(arg[3]) < num_par ); + y_1 = parameter[ arg[3] ]; + } + if( p == 0 ) + { if( arg[1] & 4 ) + { + y_2 = taylor[ size_t(arg[4]) * cap_order + 0 ]; + } + else + { CPPAD_ASSERT_UNKNOWN( size_t(arg[4]) < num_par ); + y_2 = parameter[ arg[4] ]; + } + if( arg[1] & 8 ) + { + y_3 = taylor[ size_t(arg[5]) * cap_order + 0 ]; + } + else + { CPPAD_ASSERT_UNKNOWN( size_t(arg[5]) < num_par ); + y_3 = parameter[ arg[5] ]; + } + z[0] = CondExpOp( + CompareOp( arg[0] ), + y_0, + y_1, + y_2, + y_3 + ); + p++; + } + for(size_t d = p; d <= q; d++) + { if( arg[1] & 4 ) + { + y_2 = taylor[ size_t(arg[4]) * cap_order + d]; + } + else + y_2 = zero; + if( arg[1] & 8 ) + { + y_3 = taylor[ size_t(arg[5]) * cap_order + d]; + } + else + y_3 = zero; + z[d] = CondExpOp( + CompareOp( arg[0] ), + y_0, + y_1, + y_2, + y_3 + ); + } + return; +} + +/*! +Multiple directions forward mode Taylor coefficients for op = CExpOp. + + +The C++ source code coresponding to this operation is +\verbatim + z = CondExpRel(y_0, y_1, y_2, y_3) +\endverbatim +where Rel is one of the following: Lt, Le, Eq, Ge, Gt. + +\tparam Base +base type for the operator; i.e., this operation was recorded +using AD< Base > and computations by this routine are done using type + Base. + +\param i_z +is the AD variable index corresponding to the variable z. + +\param arg +\n + arg[0] +is static cast to size_t from the enum type +\verbatim + enum CompareOp { + CompareLt, + CompareLe, + CompareEq, + CompareGe, + CompareGt, + CompareNe + } +\endverbatim +for this operation. +Note that arg[0] cannot be equal to CompareNe. +\n +\n + arg[1] & 1 +\n +If this is zero, y_0 is a parameter. Otherwise it is a variable. +\n +\n + arg[1] & 2 +\n +If this is zero, y_1 is a parameter. Otherwise it is a variable. +\n +\n + arg[1] & 4 +\n +If this is zero, y_2 is a parameter. Otherwise it is a variable. +\n +\n + arg[1] & 8 +\n +If this is zero, y_3 is a parameter. Otherwise it is a variable. +\n +\n + arg[2 + j ] for j = 0, 1, 2, 3 +\n +is the index corresponding to y_j. + +\param num_par +is the total number of values in the vector parameter. + +\param parameter +For j = 0, 1, 2, 3, +if y_j is a parameter, parameter [ arg[2 + j] ] is its value. + +\param cap_order +number of columns in the matrix containing the Taylor coefficients. + +\par Checked Assertions +\li NumArg(CExpOp) == 6 +\li NumRes(CExpOp) == 1 +\li arg[0] < static_cast ( CompareNe ) +\li arg[1] != 0; i.e., not all of y_0, y_1, y_2, y_3 are parameters. +\li For j = 0, 1, 2, 3 if y_j is a parameter, arg[2+j] < num_par. + + +\param q +is order of the Taylor coefficient of z that we are computing. + +\param r +is the number of Taylor coefficient directions that we are computing. + +\par tpv +We use the notation +tpv = (cap_order-1) * r + 1 +which is the number of Taylor coefficients per variable + +\param taylor +\b Input: +For j = 0, 1, 2, 3, k = 1, ..., q, +if y_j is a variable then +taylor [ arg[2+j] * tpv + 0 ] +is the zero order Taylor coefficient corresponding to y_j and +taylor [ arg[2+j] * tpv + (k-1)*r+1+ell is its +k-th order Taylor coefficient in the ell-th direction. +\n +\b Input: +For j = 0, 1, 2, 3, k = 1, ..., q-1, +taylor [ i_z * tpv + 0 ] +is the zero order Taylor coefficient corresponding to z and +taylor [ i_z * tpv + (k-1)*r+1+ell is its +k-th order Taylor coefficient in the ell-th direction. +\n +\b Output: taylor [ i_z * tpv + (q-1)*r+1+ell ] +is the q-th order Taylor coefficient corresponding to z +in the ell-th direction. +*/ +template +void forward_cond_op_dir( + size_t q , + size_t r , + size_t i_z , + const addr_t* arg , + size_t num_par , + const Base* parameter , + size_t cap_order , + Base* taylor ) +{ Base y_0, y_1, y_2, y_3; + Base zero(0); + size_t num_taylor_per_var = (cap_order-1) * r + 1; + Base* z = taylor + i_z * num_taylor_per_var; + + CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) < static_cast (CompareNe) ); + CPPAD_ASSERT_UNKNOWN( NumArg(CExpOp) == 6 ); + CPPAD_ASSERT_UNKNOWN( NumRes(CExpOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( arg[1] != 0 ); + CPPAD_ASSERT_UNKNOWN( 0 < q ); + CPPAD_ASSERT_UNKNOWN( q < cap_order ); + + if( arg[1] & 1 ) + { + y_0 = taylor[ size_t(arg[2]) * num_taylor_per_var + 0 ]; + } + else + { CPPAD_ASSERT_UNKNOWN( size_t(arg[2]) < num_par ); + y_0 = parameter[ arg[2] ]; + } + if( arg[1] & 2 ) + { + y_1 = taylor[ size_t(arg[3]) * num_taylor_per_var + 0 ]; + } + else + { CPPAD_ASSERT_UNKNOWN( size_t(arg[3]) < num_par ); + y_1 = parameter[ arg[3] ]; + } + size_t m = (q-1) * r + 1; + for(size_t ell = 0; ell < r; ell++) + { if( arg[1] & 4 ) + { + y_2 = taylor[ size_t(arg[4]) * num_taylor_per_var + m + ell]; + } + else + y_2 = zero; + if( arg[1] & 8 ) + { + y_3 = taylor[ size_t(arg[5]) * num_taylor_per_var + m + ell]; + } + else + y_3 = zero; + z[m+ell] = CondExpOp( + CompareOp( arg[0] ), + y_0, + y_1, + y_2, + y_3 + ); + } + return; +} + +/*! +Compute zero order forward mode Taylor coefficients for op = CExpOp. + + +The C++ source code coresponding to this operation is +\verbatim + z = CondExpRel(y_0, y_1, y_2, y_3) +\endverbatim +where Rel is one of the following: Lt, Le, Eq, Ge, Gt. + +\tparam Base +base type for the operator; i.e., this operation was recorded +using AD< Base > and computations by this routine are done using type + Base. + +\param i_z +is the AD variable index corresponding to the variable z. + +\param arg +\n + arg[0] +is static cast to size_t from the enum type +\verbatim + enum CompareOp { + CompareLt, + CompareLe, + CompareEq, + CompareGe, + CompareGt, + CompareNe + } +\endverbatim +for this operation. +Note that arg[0] cannot be equal to CompareNe. +\n +\n + arg[1] & 1 +\n +If this is zero, y_0 is a parameter. Otherwise it is a variable. +\n +\n + arg[1] & 2 +\n +If this is zero, y_1 is a parameter. Otherwise it is a variable. +\n +\n + arg[1] & 4 +\n +If this is zero, y_2 is a parameter. Otherwise it is a variable. +\n +\n + arg[1] & 8 +\n +If this is zero, y_3 is a parameter. Otherwise it is a variable. +\n +\n + arg[2 + j ] for j = 0, 1, 2, 3 +\n +is the index corresponding to y_j. + +\param num_par +is the total number of values in the vector parameter. + +\param parameter +For j = 0, 1, 2, 3, +if y_j is a parameter, parameter [ arg[2 + j] ] is its value. + +\param cap_order +number of columns in the matrix containing the Taylor coefficients. + +\par Checked Assertions +\li NumArg(CExpOp) == 6 +\li NumRes(CExpOp) == 1 +\li arg[0] < static_cast ( CompareNe ) +\li arg[1] != 0; i.e., not all of y_0, y_1, y_2, y_3 are parameters. +\li For j = 0, 1, 2, 3 if y_j is a parameter, arg[2+j] < num_par. + + +\param taylor +\b Input: +For j = 0, 1, 2, 3, +if y_j is a variable then + taylor [ arg[2+j] * cap_order + 0 ] +is the zero order Taylor coefficient corresponding to y_j. +\n +\b Output: taylor [ i_z * cap_order + 0 ] +is the zero order Taylor coefficient corresponding to z. +*/ +template +void forward_cond_op_0( + size_t i_z , + const addr_t* arg , + size_t num_par , + const Base* parameter , + size_t cap_order , + Base* taylor ) +{ Base y_0, y_1, y_2, y_3; + Base* z; + + CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) < static_cast (CompareNe) ); + CPPAD_ASSERT_UNKNOWN( NumArg(CExpOp) == 6 ); + CPPAD_ASSERT_UNKNOWN( NumRes(CExpOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( arg[1] != 0 ); + + if( arg[1] & 1 ) + { + y_0 = taylor[ size_t(arg[2]) * cap_order + 0 ]; + } + else + { CPPAD_ASSERT_UNKNOWN( size_t(arg[2]) < num_par ); + y_0 = parameter[ arg[2] ]; + } + if( arg[1] & 2 ) + { + y_1 = taylor[ size_t(arg[3]) * cap_order + 0 ]; + } + else + { CPPAD_ASSERT_UNKNOWN( size_t(arg[3]) < num_par ); + y_1 = parameter[ arg[3] ]; + } + if( arg[1] & 4 ) + { + y_2 = taylor[ size_t(arg[4]) * cap_order + 0 ]; + } + else + { CPPAD_ASSERT_UNKNOWN( size_t(arg[4]) < num_par ); + y_2 = parameter[ arg[4] ]; + } + if( arg[1] & 8 ) + { + y_3 = taylor[ size_t(arg[5]) * cap_order + 0 ]; + } + else + { CPPAD_ASSERT_UNKNOWN( size_t(arg[5]) < num_par ); + y_3 = parameter[ arg[5] ]; + } + z = taylor + i_z * cap_order; + z[0] = CondExpOp( + CompareOp( arg[0] ), + y_0, + y_1, + y_2, + y_3 + ); + return; +} + +/*! +Compute reverse mode Taylor coefficients for op = CExpOp. + +This routine is given the partial derivatives of a function +G( z , y , x , w , ... ) +and it uses them to compute the partial derivatives of +\verbatim + H( y , x , w , u , ... ) = G[ z(y) , y , x , w , u , ... ] +\endverbatim +where y above represents y_0, y_1, y_2, y_3. + + +The C++ source code coresponding to this operation is +\verbatim + z = CondExpRel(y_0, y_1, y_2, y_3) +\endverbatim +where Rel is one of the following: Lt, Le, Eq, Ge, Gt. + +\tparam Base +base type for the operator; i.e., this operation was recorded +using AD< Base > and computations by this routine are done using type + Base. + +\param i_z +is the AD variable index corresponding to the variable z. + +\param arg +\n + arg[0] +is static cast to size_t from the enum type +\verbatim + enum CompareOp { + CompareLt, + CompareLe, + CompareEq, + CompareGe, + CompareGt, + CompareNe + } +\endverbatim +for this operation. +Note that arg[0] cannot be equal to CompareNe. +\n +\n + arg[1] & 1 +\n +If this is zero, y_0 is a parameter. Otherwise it is a variable. +\n +\n + arg[1] & 2 +\n +If this is zero, y_1 is a parameter. Otherwise it is a variable. +\n +\n + arg[1] & 4 +\n +If this is zero, y_2 is a parameter. Otherwise it is a variable. +\n +\n + arg[1] & 8 +\n +If this is zero, y_3 is a parameter. Otherwise it is a variable. +\n +\n + arg[2 + j ] for j = 0, 1, 2, 3 +\n +is the index corresponding to y_j. + +\param num_par +is the total number of values in the vector parameter. + +\param parameter +For j = 0, 1, 2, 3, +if y_j is a parameter, parameter [ arg[2 + j] ] is its value. + +\param cap_order +number of columns in the matrix containing the Taylor coefficients. + +\par Checked Assertions +\li NumArg(CExpOp) == 6 +\li NumRes(CExpOp) == 1 +\li arg[0] < static_cast ( CompareNe ) +\li arg[1] != 0; i.e., not all of y_0, y_1, y_2, y_3 are parameters. +\li For j = 0, 1, 2, 3 if y_j is a parameter, arg[2+j] < num_par. + + +\param d +is the order of the Taylor coefficient of z that we are computing. + +\param taylor +\b Input: +For j = 0, 1, 2, 3 and k = 0 , ... , d, +if y_j is a variable then + taylor [ arg[2+j] * cap_order + k ] +is the k-th order Taylor coefficient corresponding to y_j. +\n + taylor [ i_z * cap_order + k ] +for k = 0 , ... , d +is the k-th order Taylor coefficient corresponding to z. + +\param nc_partial +number of columns in the matrix containing the Taylor coefficients. + +\param partial +\b Input: +For j = 0, 1, 2, 3 and k = 0 , ... , d, +if y_j is a variable then + partial [ arg[2+j] * nc_partial + k ] +is the partial derivative of G( z , y , x , w , u , ... ) +with respect to the k-th order Taylor coefficient corresponding to y_j. +\n +\b Input: partial [ i_z * cap_order + k ] +for k = 0 , ... , d +is the partial derivative of G( z , y , x , w , u , ... ) +with respect to the k-th order Taylor coefficient corresponding to z. +\n +\b Output: +For j = 0, 1, 2, 3 and k = 0 , ... , d, +if y_j is a variable then + partial [ arg[2+j] * nc_partial + k ] +is the partial derivative of H( y , x , w , u , ... ) +with respect to the k-th order Taylor coefficient corresponding to y_j. + +*/ +template +void reverse_cond_op( + size_t d , + size_t i_z , + const addr_t* arg , + size_t num_par , + const Base* parameter , + size_t cap_order , + const Base* taylor , + size_t nc_partial , + Base* partial ) +{ Base y_0, y_1; + Base zero(0); + Base* pz; + Base* py_2; + Base* py_3; + + CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) < static_cast (CompareNe) ); + CPPAD_ASSERT_UNKNOWN( NumArg(CExpOp) == 6 ); + CPPAD_ASSERT_UNKNOWN( NumRes(CExpOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( arg[1] != 0 ); + + pz = partial + i_z * nc_partial + 0; + if( arg[1] & 1 ) + { + y_0 = taylor[ size_t(arg[2]) * cap_order + 0 ]; + } + else + { CPPAD_ASSERT_UNKNOWN( size_t(arg[2]) < num_par ); + y_0 = parameter[ arg[2] ]; + } + if( arg[1] & 2 ) + { + y_1 = taylor[ size_t(arg[3]) * cap_order + 0 ]; + } + else + { CPPAD_ASSERT_UNKNOWN( size_t(arg[3]) < num_par ); + y_1 = parameter[ arg[3] ]; + } + if( arg[1] & 4 ) + { + py_2 = partial + size_t(arg[4]) * nc_partial; + size_t j = d + 1; + while(j--) + { py_2[j] += CondExpOp( + CompareOp( arg[0] ), + y_0, + y_1, + pz[j], + zero + ); + } + } + if( arg[1] & 8 ) + { + py_3 = partial + size_t(arg[5]) * nc_partial; + size_t j = d + 1; + while(j--) + { py_3[j] += CondExpOp( + CompareOp( arg[0] ), + y_0, + y_1, + zero, + pz[j] + ); + } + } + return; +} + +/*! +Compute forward Jacobian sparsity patterns for op = CExpOp. + + +The C++ source code coresponding to this operation is +\verbatim + z = CondExpRel(y_0, y_1, y_2, y_3) +\endverbatim +where Rel is one of the following: Lt, Le, Eq, Ge, Gt. + +\tparam Vector_set +is the type used for vectors of sets. It can be either +sparse::pack_setvec or sparse::list_setvec. + +\param i_z +is the AD variable index corresponding to the variable z. + +\param arg +\n + arg[0] +is static cast to size_t from the enum type +\verbatim + enum CompareOp { + CompareLt, + CompareLe, + CompareEq, + CompareGe, + CompareGt, + CompareNe + } +\endverbatim +for this operation. +Note that arg[0] cannot be equal to CompareNe. +\n +\n + arg[1] & 1 +\n +If this is zero, y_0 is a parameter. Otherwise it is a variable. +\n +\n + arg[1] & 2 +\n +If this is zero, y_1 is a parameter. Otherwise it is a variable. +\n +\n + arg[1] & 4 +\n +If this is zero, y_2 is a parameter. Otherwise it is a variable. +\n +\n + arg[1] & 8 +\n +If this is zero, y_3 is a parameter. Otherwise it is a variable. +\n +\n + arg[2 + j ] for j = 0, 1, 2, 3 +\n +is the index corresponding to y_j. + +\param num_par +is the total number of values in the vector parameter. + +\par Checked Assertions +\li NumArg(CExpOp) == 6 +\li NumRes(CExpOp) == 1 +\li arg[0] < static_cast ( CompareNe ) +\li arg[1] != 0; i.e., not all of y_0, y_1, y_2, y_3 are parameters. +\li For j = 0, 1, 2, 3 if y_j is a parameter, arg[2+j] < num_par. + + +\param dependency +Are the derivatives with respect to left and right of the expression below +considered to be non-zero: +\code + CondExpRel(left, right, if_true, if_false) +\endcode +This is used by the optimizer to obtain the correct dependency relations. + +\param sparsity +\b Input: +if y_2 is a variable, the set with index t is +the sparsity pattern corresponding to y_2. +This identifies which of the independent variables the variable y_2 +depends on. +\n +\b Input: +if y_3 is a variable, the set with index t is +the sparsity pattern corresponding to y_3. +This identifies which of the independent variables the variable y_3 +depends on. +\n +\b Output: +The set with index T is +the sparsity pattern corresponding to z. +This identifies which of the independent variables the variable z +depends on. +*/ +template +void forward_sparse_jacobian_cond_op( + bool dependency , + size_t i_z , + const addr_t* arg , + size_t num_par , + Vector_set& sparsity ) +{ + CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) < static_cast (CompareNe) ); + CPPAD_ASSERT_UNKNOWN( NumArg(CExpOp) == 6 ); + CPPAD_ASSERT_UNKNOWN( NumRes(CExpOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( arg[1] != 0 ); +# ifndef NDEBUG + addr_t k = 1; + for( size_t j = 0; j < 4; j++) + { if( ! ( arg[1] & k ) ) + CPPAD_ASSERT_UNKNOWN( size_t(arg[2+j]) < num_par ); + k *= 2; + } +# endif + sparsity.clear(i_z); + if( dependency ) + { if( arg[1] & 1 ) + sparsity.binary_union(i_z, i_z, size_t(arg[2]), sparsity); + if( arg[1] & 2 ) + sparsity.binary_union(i_z, i_z, size_t(arg[3]), sparsity); + } + if( arg[1] & 4 ) + sparsity.binary_union(i_z, i_z, size_t(arg[4]), sparsity); + if( arg[1] & 8 ) + sparsity.binary_union(i_z, i_z, size_t(arg[5]), sparsity); + return; +} + +/*! +Compute reverse Jacobian sparsity patterns for op = CExpOp. + +This routine is given the sparsity patterns +for a function G(z, y, x, ... ) +and it uses them to compute the sparsity patterns for +\verbatim + H( y, x, w , u , ... ) = G[ z(x,y) , y , x , w , u , ... ] +\endverbatim +where y represents the combination of y_0, y_1, y_2, and y_3. + + +The C++ source code coresponding to this operation is +\verbatim + z = CondExpRel(y_0, y_1, y_2, y_3) +\endverbatim +where Rel is one of the following: Lt, Le, Eq, Ge, Gt. + +\tparam Vector_set +is the type used for vectors of sets. It can be either +sparse::pack_setvec or sparse::list_setvec. + +\param i_z +is the AD variable index corresponding to the variable z. + +\param arg +\n + arg[0] +is static cast to size_t from the enum type +\verbatim + enum CompareOp { + CompareLt, + CompareLe, + CompareEq, + CompareGe, + CompareGt, + CompareNe + } +\endverbatim +for this operation. +Note that arg[0] cannot be equal to CompareNe. +\n +\n + arg[1] & 1 +\n +If this is zero, y_0 is a parameter. Otherwise it is a variable. +\n +\n + arg[1] & 2 +\n +If this is zero, y_1 is a parameter. Otherwise it is a variable. +\n +\n + arg[1] & 4 +\n +If this is zero, y_2 is a parameter. Otherwise it is a variable. +\n +\n + arg[1] & 8 +\n +If this is zero, y_3 is a parameter. Otherwise it is a variable. +\n +\n + arg[2 + j ] for j = 0, 1, 2, 3 +\n +is the index corresponding to y_j. + +\param num_par +is the total number of values in the vector parameter. + +\par Checked Assertions +\li NumArg(CExpOp) == 6 +\li NumRes(CExpOp) == 1 +\li arg[0] < static_cast ( CompareNe ) +\li arg[1] != 0; i.e., not all of y_0, y_1, y_2, y_3 are parameters. +\li For j = 0, 1, 2, 3 if y_j is a parameter, arg[2+j] < num_par. + + +\param dependency +Are the derivatives with respect to left and right of the expression below +considered to be non-zero: +\code + CondExpRel(left, right, if_true, if_false) +\endcode +This is used by the optimizer to obtain the correct dependency relations. + + +\param sparsity +if y_2 is a variable, the set with index t is +the sparsity pattern corresponding to y_2. +This identifies which of the dependent variables depend on the variable y_2. +On input, this pattern corresponds to the function G. +On ouput, it corresponds to the function H. +\n +\n +if y_3 is a variable, the set with index t is +the sparsity pattern corresponding to y_3. +This identifies which of the dependent variables depeond on the variable y_3. +On input, this pattern corresponds to the function G. +On ouput, it corresponds to the function H. +\n +\b Output: +The set with index T is +the sparsity pattern corresponding to z. +This identifies which of the dependent variables depend on the variable z. +On input and output, this pattern corresponds to the function G. +*/ +template +void reverse_sparse_jacobian_cond_op( + bool dependency , + size_t i_z , + const addr_t* arg , + size_t num_par , + Vector_set& sparsity ) +{ + CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) < static_cast (CompareNe) ); + CPPAD_ASSERT_UNKNOWN( NumArg(CExpOp) == 6 ); + CPPAD_ASSERT_UNKNOWN( NumRes(CExpOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( arg[1] != 0 ); +# ifndef NDEBUG + addr_t k = 1; + for( size_t j = 0; j < 4; j++) + { if( ! ( arg[1] & k ) ) + CPPAD_ASSERT_UNKNOWN( size_t(arg[2+j]) < num_par ); + k *= 2; + } +# endif + if( dependency ) + { if( arg[1] & 1 ) + sparsity.binary_union( size_t(arg[2]), size_t(arg[2]), i_z, sparsity); + if( arg[1] & 2 ) + sparsity.binary_union( size_t(arg[3]), size_t(arg[3]), i_z, sparsity); + } + // -------------------------------------------------------------------- + if( arg[1] & 4 ) + sparsity.binary_union( size_t(arg[4]), size_t(arg[4]), i_z, sparsity); + if( arg[1] & 8 ) + sparsity.binary_union( size_t(arg[5]), size_t(arg[5]), i_z, sparsity); + return; +} + +/*! +Compute reverse Hessian sparsity patterns for op = CExpOp. + +This routine is given the sparsity patterns +for a function G(z, y, x, ... ) +and it uses them to compute the sparsity patterns for +\verbatim + H( y, x, w , u , ... ) = G[ z(x,y) , y , x , w , u , ... ] +\endverbatim +where y represents the combination of y_0, y_1, y_2, and y_3. + + +The C++ source code coresponding to this operation is +\verbatim + z = CondExpRel(y_0, y_1, y_2, y_3) +\endverbatim +where Rel is one of the following: Lt, Le, Eq, Ge, Gt. + +\tparam Vector_set +is the type used for vectors of sets. It can be either +sparse::pack_setvec or sparse::list_setvec. + +\param i_z +is the AD variable index corresponding to the variable z. + +\param arg +\n + arg[0] +is static cast to size_t from the enum type +\verbatim + enum CompareOp { + CompareLt, + CompareLe, + CompareEq, + CompareGe, + CompareGt, + CompareNe + } +\endverbatim +for this operation. +Note that arg[0] cannot be equal to CompareNe. +\n +\n + arg[1] & 1 +\n +If this is zero, y_0 is a parameter. Otherwise it is a variable. +\n +\n + arg[1] & 2 +\n +If this is zero, y_1 is a parameter. Otherwise it is a variable. +\n +\n + arg[1] & 4 +\n +If this is zero, y_2 is a parameter. Otherwise it is a variable. +\n +\n + arg[1] & 8 +\n +If this is zero, y_3 is a parameter. Otherwise it is a variable. +\n +\n + arg[2 + j ] for j = 0, 1, 2, 3 +\n +is the index corresponding to y_j. + +\param num_par +is the total number of values in the vector parameter. + +\par Checked Assertions +\li NumArg(CExpOp) == 6 +\li NumRes(CExpOp) == 1 +\li arg[0] < static_cast ( CompareNe ) +\li arg[1] != 0; i.e., not all of y_0, y_1, y_2, y_3 are parameters. +\li For j = 0, 1, 2, 3 if y_j is a parameter, arg[2+j] < num_par. + + + +\param jac_reverse + jac_reverse[i_z] +is false (true) if the Jacobian of G with respect to z is always zero +(may be non-zero). +\n +\n + jac_reverse[ arg[4] ] +If y_2 is a variable, + jac_reverse[ arg[4] ] +is false (true) if the Jacobian with respect to y_2 is always zero +(may be non-zero). +On input, it corresponds to the function G, +and on output it corresponds to the function H. +\n +\n + jac_reverse[ arg[5] ] +If y_3 is a variable, + jac_reverse[ arg[5] ] +is false (true) if the Jacobian with respect to y_3 is always zero +(may be non-zero). +On input, it corresponds to the function G, +and on output it corresponds to the function H. + +\param hes_sparsity +The set with index i_z in hes_sparsity +is the Hessian sparsity pattern for the function G +where one of the partials is with respect to z. +\n +\n +If y_2 is a variable, +the set with index arg[4] in hes_sparsity +is the Hessian sparsity pattern +where one of the partials is with respect to y_2. +On input, this pattern corresponds to the function G. +On output, this pattern corresponds to the function H. +\n +\n +If y_3 is a variable, +the set with index arg[5] in hes_sparsity +is the Hessian sparsity pattern +where one of the partials is with respect to y_3. +On input, this pattern corresponds to the function G. +On output, this pattern corresponds to the function H. +*/ +template +void reverse_sparse_hessian_cond_op( + size_t i_z , + const addr_t* arg , + size_t num_par , + bool* jac_reverse , + Vector_set& hes_sparsity ) +{ + + CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) < static_cast (CompareNe) ); + CPPAD_ASSERT_UNKNOWN( NumArg(CExpOp) == 6 ); + CPPAD_ASSERT_UNKNOWN( NumRes(CExpOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( arg[1] != 0 ); +# ifndef NDEBUG + addr_t k = 1; + for( size_t j = 0; j < 4; j++) + { if( ! ( arg[1] & k ) ) + CPPAD_ASSERT_UNKNOWN( size_t(arg[2+j]) < num_par ); + k *= 2; + } +# endif + if( arg[1] & 4 ) + { + hes_sparsity.binary_union( size_t(arg[4]), size_t(arg[4]), i_z, hes_sparsity); + jac_reverse[ arg[4] ] |= jac_reverse[i_z]; + } + if( arg[1] & 8 ) + { + hes_sparsity.binary_union( size_t(arg[5]), size_t(arg[5]), i_z, hes_sparsity); + jac_reverse[ arg[5] ] |= jac_reverse[i_z]; + } + return; +} + +} } // END_CPPAD_LOCAL_NAMESPACE +# endif diff --git a/build-config/cppad/include/cppad/local/cos_op.hpp b/build-config/cppad/include/cppad/local/cos_op.hpp new file mode 100644 index 00000000..f7d44e1b --- /dev/null +++ b/build-config/cppad/include/cppad/local/cos_op.hpp @@ -0,0 +1,238 @@ +# ifndef CPPAD_LOCAL_COS_OP_HPP +# define CPPAD_LOCAL_COS_OP_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-17 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + + +namespace CppAD { namespace local { // BEGIN_CPPAD_LOCAL_NAMESPACE +/*! +\file cos_op.hpp +Forward and reverse mode calculations for z = cos(x). +*/ + +/*! +Compute forward mode Taylor coefficient for result of op = CosOp. + +The C++ source code corresponding to this operation is +\verbatim + z = cos(x) +\endverbatim +The auxillary result is +\verbatim + y = sin(x) +\endverbatim +The value of y, and its derivatives, are computed along with the value +and derivatives of z. + +\copydetails CppAD::local::forward_unary2_op +*/ +template +void forward_cos_op( + size_t p , + size_t q , + size_t i_z , + size_t i_x , + size_t cap_order , + Base* taylor ) +{ + // check assumptions + CPPAD_ASSERT_UNKNOWN( NumArg(CosOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( NumRes(CosOp) == 2 ); + CPPAD_ASSERT_UNKNOWN( q < cap_order ); + CPPAD_ASSERT_UNKNOWN( p <= q ); + + // Taylor coefficients corresponding to argument and result + Base* x = taylor + i_x * cap_order; + Base* c = taylor + i_z * cap_order; + Base* s = c - cap_order; + + + // rest of this routine is identical for the following cases: + // forward_sin_op, forward_cos_op, forward_sinh_op, forward_cosh_op. + // (except that there is a sign difference for the hyperbolic case). + size_t k; + if( p == 0 ) + { s[0] = sin( x[0] ); + c[0] = cos( x[0] ); + p++; + } + for(size_t j = p; j <= q; j++) + { + s[j] = Base(0.0); + c[j] = Base(0.0); + for(k = 1; k <= j; k++) + { s[j] += Base(double(k)) * x[k] * c[j-k]; + c[j] -= Base(double(k)) * x[k] * s[j-k]; + } + s[j] /= Base(double(j)); + c[j] /= Base(double(j)); + } +} +/*! +Compute forward mode Taylor coefficient for result of op = CosOp. + +The C++ source code corresponding to this operation is +\verbatim + z = cos(x) +\endverbatim +The auxillary result is +\verbatim + y = sin(x) +\endverbatim +The value of y, and its derivatives, are computed along with the value +and derivatives of z. + +\copydetails CppAD::local::forward_unary2_op_dir +*/ +template +void forward_cos_op_dir( + size_t q , + size_t r , + size_t i_z , + size_t i_x , + size_t cap_order , + Base* taylor ) +{ + // check assumptions + CPPAD_ASSERT_UNKNOWN( NumArg(CosOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( NumRes(CosOp) == 2 ); + CPPAD_ASSERT_UNKNOWN( 0 < q ); + CPPAD_ASSERT_UNKNOWN( q < cap_order ); + + // Taylor coefficients corresponding to argument and result + size_t num_taylor_per_var = (cap_order-1) * r + 1; + Base* x = taylor + i_x * num_taylor_per_var; + Base* c = taylor + i_z * num_taylor_per_var; + Base* s = c - num_taylor_per_var; + + + // rest of this routine is identical for the following cases: + // forward_sin_op, forward_cos_op, forward_sinh_op, forward_cosh_op + // (except that there is a sign difference for the hyperbolic case). + size_t m = (q-1) * r + 1; + for(size_t ell = 0; ell < r; ell++) + { s[m+ell] = Base(double(q)) * x[m + ell] * c[0]; + c[m+ell] = - Base(double(q)) * x[m + ell] * s[0]; + for(size_t k = 1; k < q; k++) + { s[m+ell] += Base(double(k)) * x[(k-1)*r+1+ell] * c[(q-k-1)*r+1+ell]; + c[m+ell] -= Base(double(k)) * x[(k-1)*r+1+ell] * s[(q-k-1)*r+1+ell]; + } + s[m+ell] /= Base(double(q)); + c[m+ell] /= Base(double(q)); + } +} + +/*! +Compute zero order forward mode Taylor coefficient for result of op = CosOp. + +The C++ source code corresponding to this operation is +\verbatim + z = cos(x) +\endverbatim +The auxillary result is +\verbatim + y = sin(x) +\endverbatim +The value of y is computed along with the value of z. + +\copydetails CppAD::local::forward_unary2_op_0 +*/ +template +void forward_cos_op_0( + size_t i_z , + size_t i_x , + size_t cap_order , + Base* taylor ) +{ + // check assumptions + CPPAD_ASSERT_UNKNOWN( NumArg(CosOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( NumRes(CosOp) == 2 ); + CPPAD_ASSERT_UNKNOWN( 0 < cap_order ); + + // Taylor coefficients corresponding to argument and result + Base* x = taylor + i_x * cap_order; + Base* c = taylor + i_z * cap_order; // called z in documentation + Base* s = c - cap_order; // called y in documentation + + c[0] = cos( x[0] ); + s[0] = sin( x[0] ); +} +/*! +Compute reverse mode partial derivatives for result of op = CosOp. + +The C++ source code corresponding to this operation is +\verbatim + z = cos(x) +\endverbatim +The auxillary result is +\verbatim + y = sin(x) +\endverbatim +The value of y is computed along with the value of z. + +\copydetails CppAD::local::reverse_unary2_op +*/ + +template +void reverse_cos_op( + size_t d , + size_t i_z , + size_t i_x , + size_t cap_order , + const Base* taylor , + size_t nc_partial , + Base* partial ) +{ + // check assumptions + CPPAD_ASSERT_UNKNOWN( NumArg(CosOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( NumRes(CosOp) == 2 ); + CPPAD_ASSERT_UNKNOWN( d < cap_order ); + CPPAD_ASSERT_UNKNOWN( d < nc_partial ); + + // Taylor coefficients and partials corresponding to argument + const Base* x = taylor + i_x * cap_order; + Base* px = partial + i_x * nc_partial; + + // Taylor coefficients and partials corresponding to first result + const Base* c = taylor + i_z * cap_order; // called z in doc + Base* pc = partial + i_z * nc_partial; + + // Taylor coefficients and partials corresponding to auxillary result + const Base* s = c - cap_order; // called y in documentation + Base* ps = pc - nc_partial; + + + // rest of this routine is identical for the following cases: + // reverse_sin_op, reverse_cos_op, reverse_sinh_op, reverse_cosh_op. + size_t j = d; + size_t k; + while(j) + { + ps[j] /= Base(double(j)); + pc[j] /= Base(double(j)); + for(k = 1; k <= j; k++) + { + px[k] += Base(double(k)) * azmul(ps[j], c[j-k]); + px[k] -= Base(double(k)) * azmul(pc[j], s[j-k]); + + ps[j-k] -= Base(double(k)) * azmul(pc[j], x[k]); + pc[j-k] += Base(double(k)) * azmul(ps[j], x[k]); + + } + --j; + } + px[0] += azmul(ps[0], c[0]); + px[0] -= azmul(pc[0], s[0]); +} + +} } // END_CPPAD_LOCAL_NAMESPACE +# endif diff --git a/build-config/cppad/include/cppad/local/cosh_op.hpp b/build-config/cppad/include/cppad/local/cosh_op.hpp new file mode 100644 index 00000000..875200c0 --- /dev/null +++ b/build-config/cppad/include/cppad/local/cosh_op.hpp @@ -0,0 +1,238 @@ +# ifndef CPPAD_LOCAL_COSH_OP_HPP +# define CPPAD_LOCAL_COSH_OP_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-17 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + + +namespace CppAD { namespace local { // BEGIN_CPPAD_LOCAL_NAMESPACE +/*! +\file cosh_op.hpp +Forward and reverse mode calculations for z = cosh(x). +*/ + + +/*! +Compute forward mode Taylor coefficient for result of op = CoshOp. + +The C++ source code corresponding to this operation is +\verbatim + z = cosh(x) +\endverbatim +The auxillary result is +\verbatim + y = sinh(x) +\endverbatim +The value of y, and its derivatives, are computed along with the value +and derivatives of z. + +\copydetails CppAD::local::forward_unary2_op +*/ +template +void forward_cosh_op( + size_t p , + size_t q , + size_t i_z , + size_t i_x , + size_t cap_order , + Base* taylor ) +{ + // check assumptions + CPPAD_ASSERT_UNKNOWN( NumArg(CoshOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( NumRes(CoshOp) == 2 ); + CPPAD_ASSERT_UNKNOWN( q < cap_order ); + CPPAD_ASSERT_UNKNOWN( p <= q ); + + // Taylor coefficients corresponding to argument and result + Base* x = taylor + i_x * cap_order; + Base* c = taylor + i_z * cap_order; + Base* s = c - cap_order; + + // rest of this routine is identical for the following cases: + // forward_sin_op, forward_cos_op, forward_sinh_op, forward_cosh_op. + // (except that there is a sign difference for hyperbolic case). + size_t k; + if( p == 0 ) + { s[0] = sinh( x[0] ); + c[0] = cosh( x[0] ); + p++; + } + for(size_t j = p; j <= q; j++) + { + s[j] = Base(0.0); + c[j] = Base(0.0); + for(k = 1; k <= j; k++) + { s[j] += Base(double(k)) * x[k] * c[j-k]; + c[j] += Base(double(k)) * x[k] * s[j-k]; + } + s[j] /= Base(double(j)); + c[j] /= Base(double(j)); + } +} +/*! +Compute forward mode Taylor coefficient for result of op = CoshOp. + +The C++ source code corresponding to this operation is +\verbatim + z = cosh(x) +\endverbatim +The auxillary result is +\verbatim + y = sinh(x) +\endverbatim +The value of y, and its derivatives, are computed along with the value +and derivatives of z. + +\copydetails CppAD::local::forward_unary2_op_dir +*/ +template +void forward_cosh_op_dir( + size_t q , + size_t r , + size_t i_z , + size_t i_x , + size_t cap_order , + Base* taylor ) +{ + // check assumptions + CPPAD_ASSERT_UNKNOWN( NumArg(CoshOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( NumRes(CoshOp) == 2 ); + CPPAD_ASSERT_UNKNOWN( 0 < q ); + CPPAD_ASSERT_UNKNOWN( q < cap_order ); + + // Taylor coefficients corresponding to argument and result + size_t num_taylor_per_var = (cap_order-1) * r + 1; + Base* x = taylor + i_x * num_taylor_per_var; + Base* s = taylor + i_z * num_taylor_per_var; + Base* c = s - num_taylor_per_var; + + + // rest of this routine is identical for the following cases: + // forward_sin_op, forward_cos_op, forward_sinh_op, forward_cosh_op + // (except that there is a sign difference for the hyperbolic case). + size_t m = (q-1) * r + 1; + for(size_t ell = 0; ell < r; ell++) + { s[m+ell] = Base(double(q)) * x[m + ell] * c[0]; + c[m+ell] = Base(double(q)) * x[m + ell] * s[0]; + for(size_t k = 1; k < q; k++) + { s[m+ell] += Base(double(k)) * x[(k-1)*r+1+ell] * c[(q-k-1)*r+1+ell]; + c[m+ell] += Base(double(k)) * x[(k-1)*r+1+ell] * s[(q-k-1)*r+1+ell]; + } + s[m+ell] /= Base(double(q)); + c[m+ell] /= Base(double(q)); + } +} + +/*! +Compute zero order forward mode Taylor coefficient for result of op = CoshOp. + +The C++ source code corresponding to this operation is +\verbatim + z = cosh(x) +\endverbatim +The auxillary result is +\verbatim + y = sinh(x) +\endverbatim +The value of y is computed along with the value of z. + +\copydetails CppAD::local::forward_unary2_op_0 +*/ +template +void forward_cosh_op_0( + size_t i_z , + size_t i_x , + size_t cap_order , + Base* taylor ) +{ + // check assumptions + CPPAD_ASSERT_UNKNOWN( NumArg(CoshOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( NumRes(CoshOp) == 2 ); + CPPAD_ASSERT_UNKNOWN( 0 < cap_order ); + + // Taylor coefficients corresponding to argument and result + Base* x = taylor + i_x * cap_order; + Base* c = taylor + i_z * cap_order; // called z in documentation + Base* s = c - cap_order; // called y in documentation + + c[0] = cosh( x[0] ); + s[0] = sinh( x[0] ); +} +/*! +Compute reverse mode partial derivatives for result of op = CoshOp. + +The C++ source code corresponding to this operation is +\verbatim + z = cosh(x) +\endverbatim +The auxillary result is +\verbatim + y = sinh(x) +\endverbatim +The value of y is computed along with the value of z. + +\copydetails CppAD::local::reverse_unary2_op +*/ + +template +void reverse_cosh_op( + size_t d , + size_t i_z , + size_t i_x , + size_t cap_order , + const Base* taylor , + size_t nc_partial , + Base* partial ) +{ + // check assumptions + CPPAD_ASSERT_UNKNOWN( NumArg(CoshOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( NumRes(CoshOp) == 2 ); + CPPAD_ASSERT_UNKNOWN( d < cap_order ); + CPPAD_ASSERT_UNKNOWN( d < nc_partial ); + + // Taylor coefficients and partials corresponding to argument + const Base* x = taylor + i_x * cap_order; + Base* px = partial + i_x * nc_partial; + + // Taylor coefficients and partials corresponding to first result + const Base* c = taylor + i_z * cap_order; // called z in doc + Base* pc = partial + i_z * nc_partial; + + // Taylor coefficients and partials corresponding to auxillary result + const Base* s = c - cap_order; // called y in documentation + Base* ps = pc - nc_partial; + + + // rest of this routine is identical for the following cases: + // reverse_sin_op, reverse_cos_op, reverse_sinh_op, reverse_cosh_op. + size_t j = d; + size_t k; + while(j) + { + ps[j] /= Base(double(j)); + pc[j] /= Base(double(j)); + for(k = 1; k <= j; k++) + { + px[k] += Base(double(k)) * azmul(ps[j], c[j-k]); + px[k] += Base(double(k)) * azmul(pc[j], s[j-k]); + + ps[j-k] += Base(double(k)) * azmul(pc[j], x[k]); + pc[j-k] += Base(double(k)) * azmul(ps[j], x[k]); + + } + --j; + } + px[0] += azmul(ps[0], c[0]); + px[0] += azmul(pc[0], s[0]); +} + +} } // END_CPPAD_LOCAL_NAMESPACE +# endif diff --git a/build-config/cppad/include/cppad/local/cppad_colpack.hpp b/build-config/cppad/include/cppad/local/cppad_colpack.hpp new file mode 100644 index 00000000..ee96ab5f --- /dev/null +++ b/build-config/cppad/include/cppad/local/cppad_colpack.hpp @@ -0,0 +1,104 @@ +# ifndef CPPAD_LOCAL_CPPAD_COLPACK_HPP +# define CPPAD_LOCAL_CPPAD_COLPACK_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-16 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ +# if CPPAD_HAS_COLPACK + +namespace CppAD { namespace local { // BEGIN_CPPAD_LOCAL_NAMESPACE +/*! +\file cppad_colpack.hpp +External interface to Colpack routines used by cppad. +*/ +// --------------------------------------------------------------------------- +/*! +Link from CppAD to ColPack used for general sparse matrices. + +This CppAD library routine is necessary because +ColPack/ColPackHeaders.h has a +using namespace std at the global level. + +\param m [in] +is the number of rows in the sparse matrix + +\param n [in] +is the nubmer of columns in the sparse matrix. + +\param adolc_pattern [in] +This vector has size m, +adolc_pattern[i][0] is the number of non-zeros in row i. +For j = 1 , ... , adolc_sparsity[i], +adolc_pattern[i][j] is the column index (base zero) for the +non-zeros in row i. + +\param color [out] +is a vector with size m. +The input value of its elements does not matter. +Upon return, it is a coloring for the rows of the sparse matrix. +\n +\n +If for some i, color[i] == m, then +adolc_pattern[i][0] == 0. +Otherwise, color[i] < m. +\n +\n +Suppose two differen rows, i != r have the same color. +It follows that for all column indices j; +it is not the case that both +(i, j) and (r, j) appear in the sparsity pattern. +\n +\n +This routine tries to minimize, with respect to the choice of colors, +the number of colors. +*/ +extern void cppad_colpack_general( + CppAD::vector& color , + size_t m , + size_t n , + const CppAD::vector& adolc_pattern +); + +/*! +Link from CppAD to ColPack used for symmetric sparse matrices +(not yet used or tested). + +This CppAD library routine is necessary because +ColPack/ColPackHeaders.h has a +using namespace std at the global level. + +\param n [in] +is the nubmer of rows and columns in the symmetric sparse matrix. + +\param adolc_pattern [in] +This vector has size n, +adolc_pattern[i][0] is the number of non-zeros in row i. +For j = 1 , ... , adolc_sparsity[i], +adolc_pattern[i][j] is the column index (base zero) for the +non-zeros in row i. + +\param color [out] +The input value of its elements does not matter. +Upon return, it is a coloring for the rows of the sparse matrix. +The properties of this coloring have not yet been determined; see +Efficient Computation of Sparse Hessians Using Coloring +and Automatic Differentiation (pdf/ad/gebemedhin14.pdf) +*/ +extern void cppad_colpack_symmetric( + CppAD::vector& color , + size_t n , + const CppAD::vector& adolc_pattern +); + +} } // END_CPPAD_LOCAL_NAMESPACE + +# endif +# endif + diff --git a/build-config/cppad/include/cppad/local/cskip_op.hpp b/build-config/cppad/include/cppad/local/cskip_op.hpp new file mode 100644 index 00000000..f9250608 --- /dev/null +++ b/build-config/cppad/include/cppad/local/cskip_op.hpp @@ -0,0 +1,199 @@ +# ifndef CPPAD_LOCAL_CSKIP_OP_HPP +# define CPPAD_LOCAL_CSKIP_OP_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +namespace CppAD { namespace local { // BEGIN_CPPAD_LOCAL_NAMESPACE +/*! +\file cskip_op.hpp +Zero order forward mode set which operations to skip. +*/ + +/*! +Zero order forward mode execution of op = CSkipOp. + +\par Parameters and Variables +The terms parameter and variable depend on if we are referring to its +AD or Base value. +We use Base parameter and Base variable to refer to the +correspond Base value. +We use AD parameter and AD variable to refer to the +correspond AD value. + +\tparam Base +base type for the operator; i.e., this operation was recorded +using AD and computations by this routine are done using type Base. + +\param i_z +variable index corresponding to the result of the previous operation. +This is used for error checking. To be specific, +the left and right operands for the CExpOp operation must have indexes +less than or equal this value. + +\param arg [in] +\n + arg[0] +is static cast to size_t from the enum type +\verbatim + enum CompareOp { + CompareLt, + CompareLe, + CompareEq, + CompareGe, + CompareGt, + CompareNe + } +\endverbatim +for this operation. +Note that arg[0] cannot be equal to CompareNe. +\n +\n + arg[1] & 1 +\n +If this is zero, left is an AD parameter. +Otherwise it is an AD variable. +\n +\n + arg[1] & 2 +\n +If this is zero, right is an AD parameter. +Otherwise it is an AD variable. +\n + arg[2] +is the index corresponding to left in comparison. +\n + arg[3] +is the index corresponding to right in comparison. +\n + arg[4] +is the number of operations to skip if the comparison result is true. +\n + arg[5] +is the number of operations to skip if the comparison result is false. +\n +arg[5+i] +for i = 1 , ... , arg[4] are the operations to skip if the +comparison result is true and both left and right are +identically Base parameters. +\n +arg[5+arg[4]+i] +for i = 1 , ... , arg[5] are the operations to skip if the +comparison result is false and both left and right are +identically Base parameters. + +\param num_par [in] +is the total number of values in the vector parameter. + +\param parameter [in] +If left is an AD parameter, +parameter [ arg[2] ] is its value. +If right is an AD parameter, +parameter [ arg[3] ] is its value. + +\param cap_order [in] +number of columns in the matrix containing the Taylor coefficients. + +\param taylor [in] +If left is an AD variable, +taylor [ size_t(arg[2]) * cap_order + 0 ] +is the zeroth order Taylor coefficient corresponding to left. +If right is an AD variable, +taylor [ size_t(arg[3]) * cap_order + 0 ] +is the zeroth order Taylor coefficient corresponding to right. + +\param cskip_op [in,out] +is vector specifying which operations are at this point are know to be +unecessary and can be skipped. +This is both an input and an output. +*/ +template +void forward_cskip_op_0( + size_t i_z , + const addr_t* arg , + size_t num_par , + const Base* parameter , + size_t cap_order , + Base* taylor , + bool* cskip_op ) +{ + CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) < size_t(CompareNe) ); + CPPAD_ASSERT_UNKNOWN( arg[1] != 0 ); + + Base left, right; + if( arg[1] & 1 ) + { // If variable arg[2] <= i_z, it has already been computed, + // but it will be skipped for higher orders. + CPPAD_ASSERT_UNKNOWN( size_t(arg[2]) <= i_z ); + left = taylor[ size_t(arg[2]) * cap_order + 0 ]; + } + else + { CPPAD_ASSERT_UNKNOWN( size_t(arg[2]) < num_par ); + left = parameter[ arg[2] ]; + } + if( arg[1] & 2 ) + { // If variable arg[3] <= i_z, it has already been computed, + // but it will be skipped for higher orders. + CPPAD_ASSERT_UNKNOWN( size_t(arg[3]) <= i_z ); + right = taylor[ size_t(arg[3]) * cap_order + 0 ]; + } + else + { CPPAD_ASSERT_UNKNOWN( size_t(arg[3]) < num_par ); + right = parameter[ arg[3] ]; + } + bool ok_to_skip = IdenticalCon(left) & IdenticalCon(right); + if( ! ok_to_skip ) + return; + + // initialize to avoid compiler warning + bool true_case = false; + Base diff = left - right; + switch( CompareOp( arg[0] ) ) + { + case CompareLt: + true_case = LessThanZero(diff); + break; + + case CompareLe: + true_case = LessThanOrZero(diff); + break; + + case CompareEq: + true_case = IdenticalZero(diff); + break; + + case CompareGe: + true_case = GreaterThanOrZero(diff); + break; + + case CompareGt: + true_case = GreaterThanZero(diff); + break; + + case CompareNe: + true_case = ! IdenticalZero(diff); + break; + + default: + CPPAD_ASSERT_UNKNOWN(false); + } + if( true_case ) + { for(addr_t i = 0; i < arg[4]; i++) + cskip_op[ arg[6+i] ] = true; + } + else + { for(addr_t i = 0; i < arg[5]; i++) + cskip_op[ arg[6+arg[4]+i] ] = true; + } + return; +} +} } // END_CPPAD_LOCAL_NAMESPACE +# endif diff --git a/build-config/cppad/include/cppad/local/csum_op.hpp b/build-config/cppad/include/cppad/local/csum_op.hpp new file mode 100644 index 00000000..84eecde7 --- /dev/null +++ b/build-config/cppad/include/cppad/local/csum_op.hpp @@ -0,0 +1,612 @@ +# ifndef CPPAD_LOCAL_CSUM_OP_HPP +# define CPPAD_LOCAL_CSUM_OP_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +namespace CppAD { namespace local { // BEGIN_CPPAD_LOCAL_NAMESPACE +/*! +\file csum_op.hpp +Forward, reverse and sparsity calculations for cummulative summation. +*/ + +/*! +Compute forward mode Taylor coefficients for result of op = CsumOp. + +This operation is +\verbatim + z = s + x(0) + ... + x(n1-1) - y(0) - ... - y(n2-1) + + p(0) + ... + p(n3-1) - q(0) - ... - q(n4-1). +\endverbatim + +\tparam Base +base type for the operator; i.e., this operation was recorded +using AD< Base > and computations by this routine are done using type +Base. + +\param p +lowest order of the Taylor coefficient that we are computing. + +\param q +highest order of the Taylor coefficient that we are computing. + +\param i_z +variable index corresponding to the result for this operation; +i.e. the row index in taylor corresponding to z. + +\param arg +-- arg[0] +parameter[arg[0]] is the parameter value s in this cummunative summation. + +-- arg[1] +end in arg of addition variables in summation. +arg[5] , ... , arg[arg[1]-1] correspond to x(0), ... , x(n1-1) + +-- arg[2] +end in arg of subtraction variables in summation. +arg[arg[1]] , ... , arg[arg[2]-1] correspond to y(0), ... , y(n2-1) + +-- arg[3] +end in arg of addition dynamic parameters in summation. +arg[arg[2]] , ... , arg[arg[3]-1] correspond to p(0), ... , p(n3-1) + +-- arg[4] +end in arg of subtraction dynamic parameters in summation. +arg[arg[3]] , ... , arg[arg[4]-1] correspond to q(0), ... , q(n4-1) + +\param num_par +is the number of parameters in parameter. + +\param parameter +is the parameter vector for this operation sequence. + +\param cap_order +number of colums in the matrix containing all the Taylor coefficients. + +\param taylor +\b Input: taylor [ arg[5+i] * cap_order + k ] +for i = 0, ..., n1-1 +and k = 0 , ... , q +is the k-th order Taylor coefficient corresponding to x(i) +\n +\b Input: taylor [ arg[arg[1]+1] * cap_order + k ] +for i = 0, ..., n2-1 +and k = 0 , ... , q +is the k-th order Taylor coefficient corresponding to y(i) +\n +\b Input: taylor [ i_z * cap_order + k ] +for k = 0 , ... , p, +is the k-th order Taylor coefficient corresponding to z. +\n +\b Output: taylor [ i_z * cap_order + k ] +for k = p , ... , q, +is the k-th order Taylor coefficient corresponding to z. +*/ +template +void forward_csum_op( + size_t p , + size_t q , + size_t i_z , + const addr_t* arg , + size_t num_par , + const Base* parameter , + size_t cap_order , + Base* taylor ) +{ Base zero(0); + + // check assumptions + CPPAD_ASSERT_UNKNOWN( NumRes(CSumOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( q < cap_order ); + CPPAD_ASSERT_UNKNOWN( p <= q ); + CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) < num_par ); + CPPAD_ASSERT_UNKNOWN( + arg[arg[4]] == arg[4] + ); + + // Taylor coefficients corresponding to result + Base* z = taylor + i_z * cap_order; + for(size_t k = p; k <= q; k++) + z[k] = zero; + if( p == 0 ) + { // normal parameters in the sum + z[p] = parameter[ arg[0] ]; + // addition dynamic parameters + for(size_t i = size_t(arg[2]); i < size_t(arg[3]); ++i) + z[p] += parameter[ arg[i] ]; + // subtraction dynamic parameters + for(size_t i = size_t(arg[3]); i < size_t(arg[4]); ++i) + z[p] -= parameter[ arg[i] ]; + } + Base* x; + for(size_t i = 5; i < size_t(arg[1]); ++i) + { CPPAD_ASSERT_UNKNOWN( size_t(arg[i]) < i_z ); + x = taylor + size_t(arg[i]) * cap_order; + for(size_t k = p; k <= q; k++) + z[k] += x[k]; + } + for(size_t i = size_t(arg[1]); i < size_t(arg[2]); ++i) + { CPPAD_ASSERT_UNKNOWN( size_t(arg[i]) < i_z ); + x = taylor + size_t(arg[i]) * cap_order; + for(size_t k = p; k <= q; k++) + z[k] -= x[k]; + } +} + +/*! +Multiple direction forward mode Taylor coefficients for op = CsumOp. + +This operation is +\verbatim + z = s + x(0) + ... + x(m-1) - y(0) - ... - y(n-1). +\endverbatim + +\tparam Base +base type for the operator; i.e., this operation was recorded +using AD and computations by this routine are done using type +Base. + +\param q +order ot the Taylor coefficients that we are computing. + +\param r +number of directions for Taylor coefficients that we are computing. + +\param i_z +variable index corresponding to the result for this operation; +i.e. the row index in taylor corresponding to z. + +\param arg +-- arg[0] +parameter[arg[0]] is the parameter value s in this cummunative summation. + +-- arg[1] +end in arg of addition variables in summation. +arg[5] , ... , arg[arg[1]-1] correspond to x(0), ... , x(m-1) + +-- arg[2] +end in arg of subtraction variables in summation. +arg[arg[1]] , ... , arg[arg[2]-1] correspond to y(0), ... , y(n-1) + +-- arg[3] +end in arg of addition dynamic parameters in summation. + +-- arg[4] +end in arg of subtraction dynamic parameters in summation. + +\param num_par +is the number of parameters in parameter. + +\param parameter +is the parameter vector for this operation sequence. + +\param cap_order +number of colums in the matrix containing all the Taylor coefficients. + +\param taylor +\b Input: taylor [ arg[5+i]*((cap_order-1)*r + 1) + 0 ] +for i = 0, ..., m-1 +is the 0-th order Taylor coefficient corresponding to x(i) and +taylor [ arg[5+i]*((cap_order-1)*r + 1) + (q-1)*r + ell + 1 ] +for i = 0, ..., m-1, +ell = 0 , ... , r-1 +is the q-th order Taylor coefficient corresponding to x(i) +and direction ell. +\n +\b Input: taylor [ arg[arg[1]+1]*((cap_order-1)*r + 1) + 0 ] +for i = 0, ..., n-1 +is the 0-th order Taylor coefficient corresponding to y(i) and +taylor [ arg[arg[1]+1]*((cap_order-1)*r + 1) + (q-1)*r + ell + 1 ] +for i = 0, ..., n-1, +ell = 0 , ... , r-1 +is the q-th order Taylor coefficient corresponding to y(i) +and direction ell. +\n +\b Output: taylor [ i_z*((cap_order-1)*r+1) + (q-1)*r + ell + 1 ] +is the q-th order Taylor coefficient corresponding to z +for direction ell = 0 , ... , r-1. +*/ +template +void forward_csum_op_dir( + size_t q , + size_t r , + size_t i_z , + const addr_t* arg , + size_t num_par , + const Base* parameter , + size_t cap_order , + Base* taylor ) +{ Base zero(0); + + // check assumptions + CPPAD_ASSERT_UNKNOWN( NumRes(CSumOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( q < cap_order ); + CPPAD_ASSERT_UNKNOWN( 0 < q ); + CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) < num_par ); + CPPAD_ASSERT_UNKNOWN( + arg[arg[4]] == arg[4] + ); + + // Taylor coefficients corresponding to result + size_t num_taylor_per_var = (cap_order-1) * r + 1; + size_t m = (q-1)*r + 1; + Base* z = taylor + i_z * num_taylor_per_var + m; + for(size_t ell = 0; ell < r; ell++) + z[ell] = zero; + Base* x; + for(size_t i = 5; i < size_t(arg[1]); ++i) + { CPPAD_ASSERT_UNKNOWN( size_t(arg[i]) < i_z ); + x = taylor + size_t(arg[i]) * num_taylor_per_var + m; + for(size_t ell = 0; ell < r; ell++) + z[ell] += x[ell]; + } + for(size_t i = size_t(arg[1]); i < size_t(arg[2]); ++i) + { CPPAD_ASSERT_UNKNOWN( size_t(arg[i]) < i_z ); + x = taylor + size_t(arg[i]) * num_taylor_per_var + m; + for(size_t ell = 0; ell < r; ell++) + z[ell] -= x[ell]; + } +} + +/*! +Compute reverse mode Taylor coefficients for result of op = CsumOp. + +This operation is +\verbatim + z = q + x(0) + ... + x(m-1) - y(0) - ... - y(n-1). + H(y, x, w, ...) = G[ z(x, y), y, x, w, ... ] +\endverbatim + +\tparam Base +base type for the operator; i.e., this operation was recorded +using AD< Base > and computations by this routine are done using type +Base. + +\param d +order the highest order Taylor coefficient that we are computing +the partial derivatives with respect to. + +\param i_z +variable index corresponding to the result for this operation; +i.e. the row index in taylor corresponding to z. + +\param arg +-- arg[0] +parameter[arg[0]] is the parameter value s in this cummunative summation. + +-- arg[1] +end in arg of addition variables in summation. +arg[5] , ... , arg[arg[1]-1] correspond to x(0), ... , x(m-1) + +-- arg[2] +end in arg of subtraction variables in summation. +arg[arg[1]] , ... , arg[arg[2]-1] correspond to y(0), ... , y(n-1) + +-- arg[3] +end in arg of addition dynamic parameters in summation. + +-- arg[4] +end in arg of subtraction dynamic parameters in summation. + +\param nc_partial +number of colums in the matrix containing all the partial derivatives. + +\param partial +\b Input: partial [ arg[5+i] * nc_partial + k ] +for i = 0, ..., m-1 +and k = 0 , ... , d +is the partial derivative of G(z, y, x, w, ...) with respect to the +k-th order Taylor coefficient corresponding to x(i) +\n +\b Input: partial [ arg[arg[1]+1] * nc_partial + k ] +for i = 0, ..., n-1 +and k = 0 , ... , d +is the partial derivative of G(z, y, x, w, ...) with respect to the +k-th order Taylor coefficient corresponding to y(i) +\n +\b Input: partial [ i_z * nc_partial + k ] +for i = 0, ..., n-1 +and k = 0 , ... , d +is the partial derivative of G(z, y, x, w, ...) with respect to the +k-th order Taylor coefficient corresponding to z. +\n +\b Output: partial [ arg[5+i] * nc_partial + k ] +for i = 0, ..., m-1 +and k = 0 , ... , d +is the partial derivative of H(y, x, w, ...) with respect to the +k-th order Taylor coefficient corresponding to x(i) +\n +\b Output: partial [ arg[arg[1]+1] * nc_partial + k ] +for i = 0, ..., n-1 +and k = 0 , ... , d +is the partial derivative of H(y, x, w, ...) with respect to the +k-th order Taylor coefficient corresponding to y(i) +*/ + +template +void reverse_csum_op( + size_t d , + size_t i_z , + const addr_t* arg , + size_t nc_partial , + Base* partial ) +{ + // check assumptions + CPPAD_ASSERT_UNKNOWN( NumRes(CSumOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( d < nc_partial ); + + // Taylor coefficients and partial derivative corresponding to result + Base* pz = partial + i_z * nc_partial; + Base* px; + size_t d1 = d + 1; + for(size_t i = 5; i < size_t(arg[1]); ++i) + { CPPAD_ASSERT_UNKNOWN( size_t(arg[i]) < i_z ); + px = partial + size_t(arg[i]) * nc_partial; + size_t k = d1; + while(k--) + px[k] += pz[k]; + } + for(size_t i = size_t(arg[1]); i < size_t(arg[2]); ++i) + { CPPAD_ASSERT_UNKNOWN( size_t(arg[i]) < i_z ); + px = partial + size_t(arg[i]) * nc_partial; + size_t k = d1; + while(k--) + px[k] -= pz[k]; + } +} + + +/*! +Forward mode Jacobian sparsity pattern for CSumOp operator. + +This operation is +\verbatim + z = q + x(0) + ... + x(m-1) - y(0) - ... - y(n-1). +\endverbatim + +\tparam Vector_set +is the type used for vectors of sets. It can be either +sparse::pack_setvec or sparse::list_setvec. + +\param i_z +variable index corresponding to the result for this operation; +i.e. the index in sparsity corresponding to z. + +\param arg +-- arg[0] +parameter[arg[0]] is the parameter value s in this cummunative summation. + +-- arg[1] +end in arg of addition variables in summation. +arg[5] , ... , arg[arg[1]-1] correspond to x(0), ... , x(m-1) + +-- arg[2] +end in arg of subtraction variables in summation. +arg[arg[1]] , ... , arg[arg[2]-1] correspond to y(0), ... , y(n-1) + +-- arg[3] +end in arg of addition dynamic parameters in summation. + +-- arg[4] +end in arg of subtraction dynamic parameters in summation. + +\param sparsity +\b Input: +For i = 0, ..., m-1, +the set with index arg[5+i] in sparsity +is the sparsity bit pattern for x(i). +This identifies which of the independent variables the variable +x(i) depends on. +\n +\b Input: +For i = 0, ..., n-1, +the set with index arg[2+arg[0]+i] in sparsity +is the sparsity bit pattern for x(i). +This identifies which of the independent variables the variable +y(i) depends on. +\n +\b Output: +The set with index i_z in sparsity +is the sparsity bit pattern for z. +This identifies which of the independent variables the variable z +depends on. +*/ + +template +void forward_sparse_jacobian_csum_op( + size_t i_z , + const addr_t* arg , + Vector_set& sparsity ) +{ sparsity.clear(i_z); + + for(size_t i = 5; i < size_t(arg[2]); ++i) + { CPPAD_ASSERT_UNKNOWN( size_t(arg[i]) < i_z ); + sparsity.binary_union( + i_z , // index in sparsity for result + i_z , // index in sparsity for left operand + size_t(arg[i]), // index for right operand + sparsity // sparsity vector for right operand + ); + } +} + +/*! +Reverse mode Jacobian sparsity pattern for CSumOp operator. + +This operation is +\verbatim + z = q + x(0) + ... + x(m-1) - y(0) - ... - y(n-1). + H(y, x, w, ...) = G[ z(x, y), y, x, w, ... ] +\endverbatim + +\tparam Vector_set +is the type used for vectors of sets. It can be either +sparse::pack_setvec or sparse::list_setvec. + +\param i_z +variable index corresponding to the result for this operation; +i.e. the index in sparsity corresponding to z. + +\param arg +-- arg[0] +parameter[arg[0]] is the parameter value s in this cummunative summation. + +-- arg[1] +end in arg of addition variables in summation. +arg[5] , ... , arg[arg[1]-1] correspond to x(0), ... , x(m-1) + +-- arg[2] +end in arg of subtraction variables in summation. +arg[arg[1]] , ... , arg[arg[2]-1] correspond to y(0), ... , y(n-1) + +-- arg[3] +end in arg of addition dynamic parameters in summation. + +-- arg[4] +end in arg of subtraction dynamic parameters in summation. + +\param sparsity +For i = 0, ..., m-1, +the set with index arg[5+i] in sparsity +is the sparsity bit pattern for x(i). +This identifies which of the dependent variables depend on x(i). +On input, the sparsity patter corresponds to G, +and on ouput it corresponds to H. +\n +For i = 0, ..., m-1, +the set with index arg[2+arg[0]+i] in sparsity +is the sparsity bit pattern for y(i). +This identifies which of the dependent variables depend on y(i). +On input, the sparsity patter corresponds to G, +and on ouput it corresponds to H. +\n +\b Input: +The set with index i_z in sparsity +is the sparsity bit pattern for z. +On input it corresponds to G and on output it is undefined. +*/ + +template +void reverse_sparse_jacobian_csum_op( + size_t i_z , + const addr_t* arg , + Vector_set& sparsity ) +{ + for(size_t i = 5; i < size_t(arg[2]); ++i) + { + CPPAD_ASSERT_UNKNOWN( size_t(arg[i]) < i_z ); + sparsity.binary_union( + size_t(arg[i]), // index in sparsity for result + size_t(arg[i]), // index in sparsity for left operand + i_z , // index for right operand + sparsity // sparsity vector for right operand + ); + } +} +/*! +Reverse mode Hessian sparsity pattern for CSumOp operator. + +This operation is +\verbatim + z = q + x(0) + ... + x(m-1) - y(0) - ... - y(n-1). + H(y, x, w, ...) = G[ z(x, y), y, x, w, ... ] +\endverbatim + +\tparam Vector_set +is the type used for vectors of sets. It can be either +sparse::pack_setvec or sparse::list_setvec. + +\param i_z +variable index corresponding to the result for this operation; +i.e. the index in sparsity corresponding to z. + +\param arg +-- arg[0] +parameter[arg[0]] is the parameter value s in this cummunative summation. + +-- arg[1] +end in arg of addition variables in summation. +arg[5] , ... , arg[arg[1]-1] correspond to x(0), ... , x(m-1) + +-- arg[2] +end in arg of subtraction variables in summation. +arg[arg[1]] , ... , arg[arg[2]-1] correspond to y(0), ... , y(n-1) + +-- arg[3] +end in arg of addition dynamic parameters in summation. + +-- arg[4] +end in arg of subtraction dynamic parameters in summation. + +\param rev_jacobian +rev_jacobian[i_z] +is all false (true) if the Jabobian of G with respect to z must be zero +(may be non-zero). +\n +\n +For i = 0, ..., m-1 +rev_jacobian[ arg[5+i] ] +is all false (true) if the Jacobian with respect to x(i) +is zero (may be non-zero). +On input, it corresponds to the function G, +and on output it corresponds to the function H. +\n +\n +For i = 0, ..., n-1 +rev_jacobian[ arg[2+arg[0]+i] ] +is all false (true) if the Jacobian with respect to y(i) +is zero (may be non-zero). +On input, it corresponds to the function G, +and on output it corresponds to the function H. + +\param rev_hes_sparsity +The set with index i_z in in rev_hes_sparsity +is the Hessian sparsity pattern for the fucntion G +where one of the partials derivative is with respect to z. +\n +\n +For i = 0, ..., m-1 +The set with index arg[5+i] in rev_hes_sparsity +is the Hessian sparsity pattern +where one of the partials derivative is with respect to x(i). +On input, it corresponds to the function G, +and on output it corresponds to the function H. +\n +\n +For i = 0, ..., n-1 +The set with index arg[2+arg[0]+i] in rev_hes_sparsity +is the Hessian sparsity pattern +where one of the partials derivative is with respect to y(i). +On input, it corresponds to the function G, +and on output it corresponds to the function H. +*/ + +template +void reverse_sparse_hessian_csum_op( + size_t i_z , + const addr_t* arg , + bool* rev_jacobian , + Vector_set& rev_hes_sparsity ) +{ + for(size_t i = 5; i < size_t(arg[2]); ++i) + { + CPPAD_ASSERT_UNKNOWN( size_t(arg[i]) < i_z ); + rev_hes_sparsity.binary_union( + size_t(arg[i]), // index in sparsity for result + size_t(arg[i]), // index in sparsity for left operand + i_z , // index for right operand + rev_hes_sparsity // sparsity vector for right operand + ); + rev_jacobian[arg[i]] |= rev_jacobian[i_z]; + } +} + +} } // END_CPPAD_LOCAL_NAMESPACE +# endif diff --git a/build-config/cppad/include/cppad/local/declare_ad.hpp b/build-config/cppad/include/cppad/local/declare_ad.hpp new file mode 100644 index 00000000..1b75f8b6 --- /dev/null +++ b/build-config/cppad/include/cppad/local/declare_ad.hpp @@ -0,0 +1,183 @@ +# ifndef CPPAD_LOCAL_DECLARE_AD_HPP +# define CPPAD_LOCAL_DECLARE_AD_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +# include +# include + +/*! +\file declare_ad.hpp CppAD forward declarations; i.e., before definition +*/ + +namespace CppAD { namespace local { // BEGIN_CPPAD_LOCAL_NAMESPACE + +template class ADTape; +template class player; +template class recorder; + +} } // END_CPPAD_LOCAL_NAMESPACE + +namespace CppAD { + // The conditional expression operator enum type + enum CompareOp + { CompareLt, // less than + CompareLe, // less than or equal + CompareEq, // equal + CompareGe, // greater than or equal + CompareGt, // greater than + CompareNe // not equal + }; + + // simple typedefs + typedef CPPAD_TAPE_ADDR_TYPE addr_t; + typedef CPPAD_TAPE_ID_TYPE tape_id_t; + + // classes + class sparse_hes_work; + class sparse_jac_work; + class sparse_jacobian_work; + class sparse_hessian_work; + template class AD; + template class ADFun; + template class atomic_base; + template class atomic_three; + template class discrete; + template class VecAD; + template class VecAD_reference; + + // functions with one VecAD argument + template bool Constant (const VecAD &u); + template bool Dynamic (const VecAD &u); + template bool Parameter (const VecAD &u); + template bool Variable (const VecAD &u); + + // functions with one AD argument + template bool Constant (const AD &u); + template bool Dynamic (const AD &u); + template bool Parameter (const AD &u); + template bool Variable (const AD &u); + // + template int Integer (const AD &u); + template bool IdenticalZero (const AD &u); + template bool IdenticalOne (const AD &u); + template bool IdenticalCon (const AD &u); + template bool LessThanZero (const AD &u); + template bool LessThanOrZero (const AD &u); + template bool GreaterThanZero (const AD &u); + template bool GreaterThanOrZero (const AD &u); + template AD Var2Par (const AD &u); + template AD abs (const AD &u); + template AD acos (const AD &u); + template AD asin (const AD &u); + template AD atan (const AD &u); + template AD cos (const AD &u); + template AD cosh (const AD &u); + template AD exp (const AD &u); + template AD log (const AD &u); + template AD log10 (const AD &u); + template AD sin (const AD &u); + template AD sinh (const AD &u); + template AD sqrt (const AD &u); + template AD tan (const AD &u); + // + template unsigned short hash_code(const AD& u); + + // arithematic operators + template AD operator + ( + const AD &left, const AD &right); + template AD operator - ( + const AD &left, const AD &right); + template AD operator * ( + const AD &left, const AD &right); + template AD operator / ( + const AD &left, const AD &right); + + // comparison operators + template bool operator < ( + const AD &left, const AD &right); + template bool operator <= ( + const AD &left, const AD &right); + template bool operator > ( + const AD &left, const AD &right); + template bool operator >= ( + const AD &left, const AD &right); + template bool operator == ( + const AD &left, const AD &right); + template bool operator != ( + const AD &left, const AD &right); + + // pow + template AD pow ( + const AD &x, const AD &y); + + // azmul + template AD azmul ( + const AD &x, const AD &y); + + // NearEqual + template bool NearEqual( + const AD &x, const AD &y, const Base &r, const Base &a); + + template bool NearEqual( + const Base &x, const AD &y, const Base &r, const Base &a); + + template bool NearEqual( + const AD &x, const Base &y, const Base &r, const Base &a); + + // CondExpOp + template AD CondExpOp ( + enum CompareOp cop , + const AD &left , + const AD &right , + const AD &trueCase , + const AD &falseCase + ); + + // IdenticalEqualCon + template + bool IdenticalEqualCon (const AD &u, const AD &v); + + // EqualOpSeq + template + bool EqualOpSeq (const AD &u, const AD &v); + + // PrintFor + template + void PrintFor( + const AD& flag , + const char* before , + const AD& var , + const char* after + ); + + // Value + template Base Value(const AD &x); + + // Pow function + template AD pow + (const AD &x, const AD &y); + + // input operator + template std::istream& + operator >> (std::istream &is, AD &x); + + // output operator + template std::ostream& + operator << (std::ostream &os, const AD &x); + template std::ostream& + operator << (std::ostream &os, const VecAD_reference &e); + template std::ostream& + operator << (std::ostream &os, const VecAD &vec); +} + +# endif diff --git a/build-config/cppad/include/cppad/local/define.hpp b/build-config/cppad/include/cppad/local/define.hpp new file mode 100644 index 00000000..8c52b377 --- /dev/null +++ b/build-config/cppad/include/cppad/local/define.hpp @@ -0,0 +1,321 @@ +# ifndef CPPAD_LOCAL_DEFINE_HPP +# define CPPAD_LOCAL_DEFINE_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +/*! +\file define.hpp +Define processor symbols and macros that are used by CppAD. +*/ + +/*! +\def CPPAD_VEC_ENUM_TYPE +Is the type used to store vectors of enum values when the vector +may be large and we want to conserve memory. The following must hold for +any enum_value that is stored using the type CPPAD_VEC_ENUM_TYPE: + + size_t(enum_value) <= std::numeric_limits::max() + && is_pod + +*/ +# define CPPAD_VEC_ENUM_TYPE unsigned char + +// ---------------------------------------------------------------------------- +/*! +\def CPPAD_INLINE_FRIEND_TEMPLATE_FUNCTION +A version of the inline command that works with MC compiler. + +Microsoft Visual C++ version 9.0 generates a warning if a template +function is declared as a friend +(this was not a problem for version 7.0). +The warning identifier is +\verbatim + warning C4396 +\endverbatim +and it contains the text +\verbatim + the inline specifier cannot be used when a friend declaration refers + to a specialization of a function template +\endverbatim +This happens even if the function is not a specialization. +This macro is defined as empty for Microsoft compilers. +*/ +# ifdef _MSC_VER +# define CPPAD_INLINE_FRIEND_TEMPLATE_FUNCTION +# else +# define CPPAD_INLINE_FRIEND_TEMPLATE_FUNCTION inline +# endif + +// ---------------------------------------------------------------------------- +/*! +\def CPPAD_LIB_EXPORT +Special macro for exporting windows DLL symbols; see +https://gitlab.kitware.com/cmake/community/wikis/doc/tutorials/BuildingWinDLL +*/ +# ifdef _MSC_VER +# ifdef cppad_lib_EXPORTS +# define CPPAD_LIB_EXPORT __declspec(dllexport) +# else +# define CPPAD_LIB_EXPORT __declspec(dllimport) +# endif // cppad_lib_EXPORTS +# else // _MSC_VER +# define CPPAD_LIB_EXPORT +# endif + + +// ============================================================================ +/*! +\def CPPAD_FOLD_ASSIGNMENT_OPERATOR(Op) +Declares automatic coercion for certain AD assignment operations. + +This macro assumes that the operator +\verbatim + left Op right +\endverbatim +is defined for the case where left and right have type AD. +It uses this case to define the cases where +left has type AD and right has type +VecAD_reference, +Base, or +double. +The argument right is const and call by reference. +This macro converts the operands to AD and then +uses the definition of the same operation for that case. +*/ + +# define CPPAD_FOLD_ASSIGNMENT_OPERATOR(Op) \ +/* ----------------------------------------------------------------*/ \ +template \ +AD& operator Op \ +(AD &left, double right) \ +{ return left Op AD(right); } \ + \ +template \ +AD& operator Op \ +(AD &left, const Base &right) \ +{ return left Op AD(right); } \ + \ +inline AD& operator Op \ +(AD &left, const double &right) \ +{ return left Op AD(right); } \ + \ +template \ +AD& operator Op \ +(AD &left, const VecAD_reference &right) \ +{ return left Op right.ADBase(); } + +// ===================================================================== +/*! +\def CPPAD_FOLD_AD_VALUED_BINARY_OPERATOR(Op) +Declares automatic coercion for certain binary operations with AD result. + +This macro assumes that the operator +\verbatim + left Op right +\endverbatim +is defined for the case where left and right +and the result of the operation all +have type AD. +It uses this case to define the cases either left +or right has type VecAD_reference or AD +and the type of the other operand is one of the following: +VecAD_reference, AD, Base, double. +All of the arguments are const and call by reference. +This macro converts the operands to AD and then +uses the definition of the same operation for that case. +*/ +# define CPPAD_FOLD_AD_VALUED_BINARY_OPERATOR(Op) \ +/* ----------------------------------------------------------------*/ \ +/* Operations with VecAD_reference and AD only*/ \ + \ +template \ +AD operator Op \ +(const AD &left, const VecAD_reference &right) \ +{ return left Op right.ADBase(); } \ + \ +template \ +AD operator Op \ +(const VecAD_reference &left, const VecAD_reference &right)\ +{ return left.ADBase() Op right.ADBase(); } \ + \ +template \ +AD operator Op \ + (const VecAD_reference &left, const AD &right) \ +{ return left.ADBase() Op right; } \ +/* ----------------------------------------------------------------*/ \ +/* Operations Base */ \ + \ +template \ +AD operator Op \ + (const Base &left, const AD &right) \ +{ return AD(left) Op right; } \ + \ +template \ +AD operator Op \ + (const Base &left, const VecAD_reference &right) \ +{ return AD(left) Op right.ADBase(); } \ + \ +template \ +AD operator Op \ + (const AD &left, const Base &right) \ +{ return left Op AD(right); } \ + \ +template \ +AD operator Op \ + (const VecAD_reference &left, const Base &right) \ +{ return left.ADBase() Op AD(right); } \ + \ +/* ----------------------------------------------------------------*/ \ +/* Operations double */ \ + \ +template \ +AD operator Op \ + (const double &left, const AD &right) \ +{ return AD(left) Op right; } \ + \ +template \ +AD operator Op \ + (const double &left, const VecAD_reference &right) \ +{ return AD(left) Op right.ADBase(); } \ + \ +template \ +AD operator Op \ + (const AD &left, const double &right) \ +{ return left Op AD(right); } \ + \ +template \ +AD operator Op \ + (const VecAD_reference &left, const double &right) \ +{ return left.ADBase() Op AD(right); } \ +/* ----------------------------------------------------------------*/ \ +/* Special case to avoid ambuigity when Base is double */ \ + \ +inline AD operator Op \ + (const double &left, const AD &right) \ +{ return AD(left) Op right; } \ + \ +inline AD operator Op \ + (const double &left, const VecAD_reference &right) \ +{ return AD(left) Op right.ADBase(); } \ + \ +inline AD operator Op \ + (const AD &left, const double &right) \ +{ return left Op AD(right); } \ + \ +inline AD operator Op \ + (const VecAD_reference &left, const double &right) \ +{ return left.ADBase() Op AD(right); } + +// ======================================================================= + +/*! +\def CPPAD_FOLD_BOOL_VALUED_BINARY_OPERATOR(Op) +Declares automatic coercion for certain binary operations with bool result. + +This macro assumes that the operator +\verbatim + left Op right +\endverbatim +is defined for the case where left and right +have type AD and the result has type bool. +It uses this case to define the cases either left +or right has type +VecAD_reference or AD +and the type of the other operand is one of the following: +VecAD_reference, AD, Base, double. +All of the arguments are const and call by reference. +This macro converts the operands to AD and then +uses the definition of the same operation for that case. +*/ +# define CPPAD_FOLD_BOOL_VALUED_BINARY_OPERATOR(Op) \ +/* ----------------------------------------------------------------*/ \ +/* Operations with VecAD_reference and AD only*/ \ + \ +template \ +bool operator Op \ +(const AD &left, const VecAD_reference &right) \ +{ return left Op right.ADBase(); } \ + \ +template \ +bool operator Op \ +(const VecAD_reference &left, const VecAD_reference &right)\ +{ return left.ADBase() Op right.ADBase(); } \ + \ +template \ +bool operator Op \ + (const VecAD_reference &left, const AD &right) \ +{ return left.ADBase() Op right; } \ +/* ----------------------------------------------------------------*/ \ +/* Operations Base */ \ + \ +template \ +bool operator Op \ + (const Base &left, const AD &right) \ +{ return AD(left) Op right; } \ + \ +template \ +bool operator Op \ + (const Base &left, const VecAD_reference &right) \ +{ return AD(left) Op right.ADBase(); } \ + \ +template \ +bool operator Op \ + (const AD &left, const Base &right) \ +{ return left Op AD(right); } \ + \ +template \ +bool operator Op \ + (const VecAD_reference &left, const Base &right) \ +{ return left.ADBase() Op AD(right); } \ + \ +/* ----------------------------------------------------------------*/ \ +/* Operations double */ \ + \ +template \ +bool operator Op \ + (const double &left, const AD &right) \ +{ return AD(left) Op right; } \ + \ +template \ +bool operator Op \ + (const double &left, const VecAD_reference &right) \ +{ return AD(left) Op right.ADBase(); } \ + \ +template \ +bool operator Op \ + (const AD &left, const double &right) \ +{ return left Op AD(right); } \ + \ +template \ +bool operator Op \ + (const VecAD_reference &left, const double &right) \ +{ return left.ADBase() Op AD(right); } \ +/* ----------------------------------------------------------------*/ \ +/* Special case to avoid ambuigity when Base is double */ \ + \ +inline bool operator Op \ + (const double &left, const AD &right) \ +{ return AD(left) Op right; } \ + \ +inline bool operator Op \ + (const double &left, const VecAD_reference &right) \ +{ return AD(left) Op right.ADBase(); } \ + \ +inline bool operator Op \ + (const AD &left, const double &right) \ +{ return left Op AD(right); } \ + \ +inline bool operator Op \ + (const VecAD_reference &left, const double &right) \ +{ return left.ADBase() Op AD(right); } + +# endif diff --git a/build-config/cppad/include/cppad/local/discrete_op.hpp b/build-config/cppad/include/cppad/local/discrete_op.hpp new file mode 100644 index 00000000..e3fa0809 --- /dev/null +++ b/build-config/cppad/include/cppad/local/discrete_op.hpp @@ -0,0 +1,121 @@ +# ifndef CPPAD_LOCAL_DISCRETE_OP_HPP +# define CPPAD_LOCAL_DISCRETE_OP_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-18 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + + +namespace CppAD { namespace local { // BEGIN_CPPAD_LOCAL_NAMESPACE +/*! +\file discrete_op.hpp +Forward mode for z = f(x) where f is piecewise constant. +*/ + + +/*! +forward mode Taylor coefficient for result of op = DisOp. + +The C++ source code corresponding to this operation is +\verbatim + z = f(x) +\endverbatim +where f is a piecewise constant function (and it's derivative is always +calculated as zero). + +\tparam Base +base type for the operator; i.e., this operation was recorded +using AD< Base > and computations by this routine are done using type + Base . + +\param p +is the lowest order Taylor coefficient that will be calculated. + +\param q +is the highest order Taylor coefficient that will be calculated. + +\param r +is the number of directions, for each order, +that will be calculated (except for order zero wich only has one direction). + +\param i_z +variable index corresponding to the result for this operation; +i.e. the row index in taylor corresponding to z. + +\param arg + arg[0] +\n +is the index, in the order of the discrete functions defined by the user, +for this discrete function. +\n +\n + arg[1] +variable index corresponding to the argument for this operator; +i.e. the row index in taylor corresponding to x. + +\param cap_order +maximum number of orders that will fit in the taylor array. + +\par tpv +We use the notation +tpv = (cap_order-1) * r + 1 +which is the number of Taylor coefficients per variable + +\param taylor +\b Input: taylor [ arg[1] * tpv + 0 ] +is the zero order Taylor coefficient corresponding to x. +\n +\b Output: if p == 0 +taylor [ i_z * tpv + 0 ] +is the zero order Taylor coefficient corresponding to z. +For k = max(p, 1), ... , q, +taylor [ i_z * tpv + (k-1)*r + 1 + ell ] +is the k-th order Taylor coefficient corresponding to z +(which is zero). + +\par Checked Assertions where op is the unary operator with one result: +\li NumArg(op) == 2 +\li NumRes(op) == 1 +\li q < cap_order +\li 0 < r +*/ +template +void forward_dis_op( + size_t p , + size_t q , + size_t r , + size_t i_z , + const addr_t* arg , + size_t cap_order , + Base* taylor ) +{ + // check assumptions + CPPAD_ASSERT_UNKNOWN( NumArg(DisOp) == 2 ); + CPPAD_ASSERT_UNKNOWN( NumRes(DisOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( q < cap_order ); + CPPAD_ASSERT_UNKNOWN( 0 < r ); + + // Taylor coefficients corresponding to argument and result + size_t num_taylor_per_var = (cap_order-1) * r + 1; + Base* x = taylor + size_t(arg[1]) * num_taylor_per_var; + Base* z = taylor + i_z * num_taylor_per_var; + + if( p == 0 ) + { z[0] = discrete::eval(size_t(arg[0]), x[0]); + p++; + } + for(size_t ell = 0; ell < r; ell++) + for(size_t k = p; k <= q; k++) + z[ (k-1) * r + 1 + ell ] = Base(0.0); +} + + +} } // END_CPPAD_LOCAL_NAMESPACE +# endif diff --git a/build-config/cppad/include/cppad/local/div_op.hpp b/build-config/cppad/include/cppad/local/div_op.hpp new file mode 100644 index 00000000..9fcb196a --- /dev/null +++ b/build-config/cppad/include/cppad/local/div_op.hpp @@ -0,0 +1,574 @@ +# ifndef CPPAD_LOCAL_DIV_OP_HPP +# define CPPAD_LOCAL_DIV_OP_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-18 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +namespace CppAD { namespace local { // BEGIN_CPPAD_LOCAL_NAMESPACE +/*! +\file div_op.hpp +Forward and reverse mode calculations for z = x / y. +*/ + +// --------------------------- Divvv ----------------------------------------- +/*! +Compute forward mode Taylor coefficients for result of op = DivvvOp. + +The C++ source code corresponding to this operation is +\verbatim + z = x / y +\endverbatim +In the documentation below, +this operations is for the case where both x and y are variables +and the argument parameter is not used. + +\copydetails CppAD::local::forward_binary_op +*/ + +template +void forward_divvv_op( + size_t p , + size_t q , + size_t i_z , + const addr_t* arg , + const Base* parameter , + size_t cap_order , + Base* taylor ) +{ + // check assumptions + CPPAD_ASSERT_UNKNOWN( NumArg(DivvvOp) == 2 ); + CPPAD_ASSERT_UNKNOWN( NumRes(DivvvOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( q < cap_order ); + CPPAD_ASSERT_UNKNOWN( p <= q ); + + // Taylor coefficients corresponding to arguments and result + Base* x = taylor + size_t(arg[0]) * cap_order; + Base* y = taylor + size_t(arg[1]) * cap_order; + Base* z = taylor + i_z * cap_order; + + + // Using CondExp, it can make sense to divide by zero, + // so do not make it an error. + size_t k; + for(size_t d = p; d <= q; d++) + { z[d] = x[d]; + for(k = 1; k <= d; k++) + z[d] -= z[d-k] * y[k]; + z[d] /= y[0]; + } +} +/*! +Multiple directions forward mode Taylor coefficients for op = DivvvOp. + +The C++ source code corresponding to this operation is +\verbatim + z = x / y +\endverbatim +In the documentation below, +this operations is for the case where both x and y are variables +and the argument parameter is not used. + +\copydetails CppAD::local::forward_binary_op_dir +*/ + +template +void forward_divvv_op_dir( + size_t q , + size_t r , + size_t i_z , + const addr_t* arg , + const Base* parameter , + size_t cap_order , + Base* taylor ) +{ + // check assumptions + CPPAD_ASSERT_UNKNOWN( NumArg(DivvvOp) == 2 ); + CPPAD_ASSERT_UNKNOWN( NumRes(DivvvOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( 0 < q ); + CPPAD_ASSERT_UNKNOWN( q < cap_order ); + + // Taylor coefficients corresponding to arguments and result + size_t num_taylor_per_var = (cap_order-1) * r + 1; + Base* x = taylor + size_t(arg[0]) * num_taylor_per_var; + Base* y = taylor + size_t(arg[1]) * num_taylor_per_var; + Base* z = taylor + i_z * num_taylor_per_var; + + + // Using CondExp, it can make sense to divide by zero, + // so do not make it an error. + size_t m = (q-1) * r + 1; + for(size_t ell = 0; ell < r; ell++) + { z[m+ell] = x[m+ell] - z[0] * y[m+ell]; + for(size_t k = 1; k < q; k++) + z[m+ell] -= z[(q-k-1)*r+1+ell] * y[(k-1)*r+1+ell]; + z[m+ell] /= y[0]; + } +} + + +/*! +Compute zero order forward mode Taylor coefficients for result of op = DivvvOp. + +The C++ source code corresponding to this operation is +\verbatim + z = x / y +\endverbatim +In the documentation below, +this operations is for the case where both x and y are variables +and the argument parameter is not used. + +\copydetails CppAD::local::forward_binary_op_0 +*/ + +template +void forward_divvv_op_0( + size_t i_z , + const addr_t* arg , + const Base* parameter , + size_t cap_order , + Base* taylor ) +{ + // check assumptions + CPPAD_ASSERT_UNKNOWN( NumArg(DivvvOp) == 2 ); + CPPAD_ASSERT_UNKNOWN( NumRes(DivvvOp) == 1 ); + + // Taylor coefficients corresponding to arguments and result + Base* x = taylor + size_t(arg[0]) * cap_order; + Base* y = taylor + size_t(arg[1]) * cap_order; + Base* z = taylor + i_z * cap_order; + + z[0] = x[0] / y[0]; +} + +/*! +Compute reverse mode partial derivatives for result of op = DivvvOp. + +The C++ source code corresponding to this operation is +\verbatim + z = x / y +\endverbatim +In the documentation below, +this operations is for the case where both x and y are variables +and the argument parameter is not used. + +\copydetails CppAD::local::reverse_binary_op +*/ + +template +void reverse_divvv_op( + size_t d , + size_t i_z , + const addr_t* arg , + const Base* parameter , + size_t cap_order , + const Base* taylor , + size_t nc_partial , + Base* partial ) +{ + // check assumptions + CPPAD_ASSERT_UNKNOWN( NumArg(DivvvOp) == 2 ); + CPPAD_ASSERT_UNKNOWN( NumRes(DivvvOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( d < cap_order ); + CPPAD_ASSERT_UNKNOWN( d < nc_partial ); + + // Arguments + const Base* y = taylor + size_t(arg[1]) * cap_order; + const Base* z = taylor + i_z * cap_order; + + // Partial derivatives corresponding to arguments and result + Base* px = partial + size_t(arg[0]) * nc_partial; + Base* py = partial + size_t(arg[1]) * nc_partial; + Base* pz = partial + i_z * nc_partial; + + // Using CondExp, it can make sense to divide by zero + // so do not make it an error. + Base inv_y0 = Base(1.0) / y[0]; + + size_t k; + // number of indices to access + size_t j = d + 1; + while(j) + { --j; + // scale partial w.r.t. z[j] + pz[j] = azmul(pz[j], inv_y0); + + px[j] += pz[j]; + for(k = 1; k <= j; k++) + { pz[j-k] -= azmul(pz[j], y[k] ); + py[k] -= azmul(pz[j], z[j-k]); + } + py[0] -= azmul(pz[j], z[j]); + } +} + +// --------------------------- Divpv ----------------------------------------- +/*! +Compute forward mode Taylor coefficients for result of op = DivpvOp. + +The C++ source code corresponding to this operation is +\verbatim + z = x / y +\endverbatim +In the documentation below, +this operations is for the case where x is a parameter and y is a variable. + +\copydetails CppAD::local::forward_binary_op +*/ + +template +void forward_divpv_op( + size_t p , + size_t q , + size_t i_z , + const addr_t* arg , + const Base* parameter , + size_t cap_order , + Base* taylor ) +{ + // check assumptions + CPPAD_ASSERT_UNKNOWN( NumArg(DivpvOp) == 2 ); + CPPAD_ASSERT_UNKNOWN( NumRes(DivpvOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( q < cap_order ); + CPPAD_ASSERT_UNKNOWN( p <= q ); + + // Taylor coefficients corresponding to arguments and result + Base* y = taylor + size_t(arg[1]) * cap_order; + Base* z = taylor + i_z * cap_order; + + // Paraemter value + Base x = parameter[ arg[0] ]; + + // Using CondExp, it can make sense to divide by zero, + // so do not make it an error. + size_t k; + if( p == 0 ) + { z[0] = x / y[0]; + p++; + } + for(size_t d = p; d <= q; d++) + { z[d] = Base(0.0); + for(k = 1; k <= d; k++) + z[d] -= z[d-k] * y[k]; + z[d] /= y[0]; + } +} +/*! +Multiple directions forward mode Taylor coefficients for op = DivpvOp. + +The C++ source code corresponding to this operation is +\verbatim + z = x / y +\endverbatim +In the documentation below, +this operations is for the case where x is a parameter and y is a variable. + +\copydetails CppAD::local::forward_binary_op_dir +*/ + +template +void forward_divpv_op_dir( + size_t q , + size_t r , + size_t i_z , + const addr_t* arg , + const Base* parameter , + size_t cap_order , + Base* taylor ) +{ + // check assumptions + CPPAD_ASSERT_UNKNOWN( NumArg(DivpvOp) == 2 ); + CPPAD_ASSERT_UNKNOWN( NumRes(DivpvOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( 0 < q ); + CPPAD_ASSERT_UNKNOWN( q < cap_order ); + + // Taylor coefficients corresponding to arguments and result + size_t num_taylor_per_var = (cap_order-1) * r + 1; + Base* y = taylor + size_t(arg[1]) * num_taylor_per_var; + Base* z = taylor + i_z * num_taylor_per_var; + + // Using CondExp, it can make sense to divide by zero, + // so do not make it an error. + size_t m = (q-1) * r + 1; + for(size_t ell = 0; ell < r; ell++) + { z[m+ell] = - z[0] * y[m+ell]; + for(size_t k = 1; k < q; k++) + z[m+ell] -= z[(q-k-1)*r+1+ell] * y[(k-1)*r+1+ell]; + z[m+ell] /= y[0]; + } +} + +/*! +Compute zero order forward mode Taylor coefficient for result of op = DivpvOp. + +The C++ source code corresponding to this operation is +\verbatim + z = x / y +\endverbatim +In the documentation below, +this operations is for the case where x is a parameter and y is a variable. + +\copydetails CppAD::local::forward_binary_op_0 +*/ + +template +void forward_divpv_op_0( + size_t i_z , + const addr_t* arg , + const Base* parameter , + size_t cap_order , + Base* taylor ) +{ + // check assumptions + CPPAD_ASSERT_UNKNOWN( NumArg(DivpvOp) == 2 ); + CPPAD_ASSERT_UNKNOWN( NumRes(DivpvOp) == 1 ); + + // Paraemter value + Base x = parameter[ arg[0] ]; + + // Taylor coefficients corresponding to arguments and result + Base* y = taylor + size_t(arg[1]) * cap_order; + Base* z = taylor + i_z * cap_order; + + z[0] = x / y[0]; +} + +/*! +Compute reverse mode partial derivative for result of op = DivpvOp. + +The C++ source code corresponding to this operation is +\verbatim + z = x / y +\endverbatim +In the documentation below, +this operations is for the case where x is a parameter and y is a variable. + +\copydetails CppAD::local::reverse_binary_op +*/ + +template +void reverse_divpv_op( + size_t d , + size_t i_z , + const addr_t* arg , + const Base* parameter , + size_t cap_order , + const Base* taylor , + size_t nc_partial , + Base* partial ) +{ + // check assumptions + CPPAD_ASSERT_UNKNOWN( NumArg(DivvvOp) == 2 ); + CPPAD_ASSERT_UNKNOWN( NumRes(DivvvOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( d < cap_order ); + CPPAD_ASSERT_UNKNOWN( d < nc_partial ); + + // Arguments + const Base* y = taylor + size_t(arg[1]) * cap_order; + const Base* z = taylor + i_z * cap_order; + + // Partial derivatives corresponding to arguments and result + Base* py = partial + size_t(arg[1]) * nc_partial; + Base* pz = partial + i_z * nc_partial; + + // Using CondExp, it can make sense to divide by zero so do not + // make it an error. + Base inv_y0 = Base(1.0) / y[0]; + + size_t k; + // number of indices to access + size_t j = d + 1; + while(j) + { --j; + // scale partial w.r.t z[j] + pz[j] = azmul(pz[j], inv_y0); + + for(k = 1; k <= j; k++) + { pz[j-k] -= azmul(pz[j], y[k] ); + py[k] -= azmul(pz[j], z[j-k] ); + } + py[0] -= azmul(pz[j], z[j]); + } +} + + +// --------------------------- Divvp ----------------------------------------- +/*! +Compute forward mode Taylor coefficients for result of op = DivvvOp. + +The C++ source code corresponding to this operation is +\verbatim + z = x / y +\endverbatim +In the documentation below, +this operations is for the case where x is a variable and y is a parameter. + +\copydetails CppAD::local::forward_binary_op +*/ + +template +void forward_divvp_op( + size_t p , + size_t q , + size_t i_z , + const addr_t* arg , + const Base* parameter , + size_t cap_order , + Base* taylor ) +{ + // check assumptions + CPPAD_ASSERT_UNKNOWN( NumArg(DivvpOp) == 2 ); + CPPAD_ASSERT_UNKNOWN( NumRes(DivvpOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( q < cap_order ); + CPPAD_ASSERT_UNKNOWN( p <= q ); + + // Taylor coefficients corresponding to arguments and result + Base* x = taylor + size_t(arg[0]) * cap_order; + Base* z = taylor + i_z * cap_order; + + // Parameter value + Base y = parameter[ arg[1] ]; + + // Using CondExp and multiple levels of AD, it can make sense + // to divide by zero so do not make it an error. + for(size_t d = p; d <= q; d++) + z[d] = x[d] / y; +} +/*! +Multiple direction forward mode Taylor coefficients for op = DivvvOp. + +The C++ source code corresponding to this operation is +\verbatim + z = x / y +\endverbatim +In the documentation below, +this operations is for the case where x is a variable and y is a parameter. + +\copydetails CppAD::local::forward_binary_op_dir +*/ + +template +void forward_divvp_op_dir( + size_t q , + size_t r , + size_t i_z , + const addr_t* arg , + const Base* parameter , + size_t cap_order , + Base* taylor ) +{ + // check assumptions + CPPAD_ASSERT_UNKNOWN( NumArg(DivvpOp) == 2 ); + CPPAD_ASSERT_UNKNOWN( NumRes(DivvpOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( q < cap_order ); + CPPAD_ASSERT_UNKNOWN( 0 < q ); + + // Taylor coefficients corresponding to arguments and result + size_t num_taylor_per_var = (cap_order-1) * r + 1; + Base* x = taylor + size_t(arg[0]) * num_taylor_per_var; + Base* z = taylor + i_z * num_taylor_per_var; + + // Parameter value + Base y = parameter[ arg[1] ]; + + // Using CondExp and multiple levels of AD, it can make sense + // to divide by zero so do not make it an error. + size_t m = (q-1)*r + 1; + for(size_t ell = 0; ell < r; ell++) + z[m + ell] = x[m + ell] / y; +} + + +/*! +Compute zero order forward mode Taylor coefficients for result of op = DivvvOp. + +The C++ source code corresponding to this operation is +\verbatim + z = x / y +\endverbatim +In the documentation below, +this operations is for the case where x is a variable and y is a parameter. + +\copydetails CppAD::local::forward_binary_op_0 +*/ + +template +void forward_divvp_op_0( + size_t i_z , + const addr_t* arg , + const Base* parameter , + size_t cap_order , + Base* taylor ) +{ + // check assumptions + CPPAD_ASSERT_UNKNOWN( NumArg(DivvpOp) == 2 ); + CPPAD_ASSERT_UNKNOWN( NumRes(DivvpOp) == 1 ); + + // Parameter value + Base y = parameter[ arg[1] ]; + + // Taylor coefficients corresponding to arguments and result + Base* x = taylor + size_t(arg[0]) * cap_order; + Base* z = taylor + i_z * cap_order; + + z[0] = x[0] / y; +} + +/*! +Compute reverse mode partial derivative for result of op = DivvpOp. + +The C++ source code corresponding to this operation is +\verbatim + z = x / y +\endverbatim +In the documentation below, +this operations is for the case where x is a variable and y is a parameter. + +\copydetails CppAD::local::reverse_binary_op +*/ + +template +void reverse_divvp_op( + size_t d , + size_t i_z , + const addr_t* arg , + const Base* parameter , + size_t cap_order , + const Base* taylor , + size_t nc_partial , + Base* partial ) +{ + // check assumptions + CPPAD_ASSERT_UNKNOWN( NumArg(DivvpOp) == 2 ); + CPPAD_ASSERT_UNKNOWN( NumRes(DivvpOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( d < cap_order ); + CPPAD_ASSERT_UNKNOWN( d < nc_partial ); + + // Argument values + Base y = parameter[ arg[1] ]; + + // Partial derivatives corresponding to arguments and result + Base* px = partial + size_t(arg[0]) * nc_partial; + Base* pz = partial + i_z * nc_partial; + + // Using CondExp, it can make sense to divide by zero + // so do not make it an error. + Base inv_y = Base(1.0) / y; + + // number of indices to access + size_t j = d + 1; + while(j) + { --j; + px[j] += azmul(pz[j], inv_y); + } +} + +} } // END_CPPAD_LOCAL_NAMESPACE +# endif diff --git a/build-config/cppad/include/cppad/local/erf_op.hpp b/build-config/cppad/include/cppad/local/erf_op.hpp new file mode 100644 index 00000000..937c8197 --- /dev/null +++ b/build-config/cppad/include/cppad/local/erf_op.hpp @@ -0,0 +1,598 @@ +# ifndef CPPAD_LOCAL_ERF_OP_HPP +# define CPPAD_LOCAL_ERF_OP_HPP + +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +# include +# include +# include + + +namespace CppAD { namespace local { // BEGIN_CPPAD_LOCAL_NAMESPACE +/*! +\file erf_op.hpp +Forward and reverse mode calculations for z = erf(x) or erfc(x). +*/ + +/*! +Forward mode Taylor coefficient for result of op = ErfOp or ErfcOp. + +The C++ source code corresponding to this operation is one of +\verbatim + z = erf(x) + z = erfc(x) +\endverbatim + +\tparam Base +base type for the operator; i.e., this operation was recorded +using AD< Base > and computations by this routine are done using type Base. + +\param op +must be either ErfOp or ErfcOp and indicates if this is +z = erf(x) or z = erfc(x). + +\param p +lowest order of the Taylor coefficients that we are computing. + +\param q +highest order of the Taylor coefficients that we are computing. + +\param i_z +variable index corresponding to the last (primary) result for this operation; +i.e. the row index in taylor corresponding to z. +The auxillary results are called y_j have index i_z - j. + +\param arg +arg[0]: is the variable index corresponding to x. +\n +arg[1]: is the parameter index corresponding to the value zero. +\n +arg[2]: is the parameter index correspodning to the value 2 / sqrt(pi). + +\param parameter +parameter[ arg[1] ] is the value zero, +and parameter[ arg[2] ] is the value 2 / sqrt(pi). + +\param cap_order +maximum number of orders that will fit in the taylor array. + +\param taylor +\b Input: +taylor [ size_t(arg[0]) * cap_order + k ] +for k = 0 , ... , q, +is the k-th order Taylor coefficient corresponding to x. +\n +\b Input: +taylor [ i_z * cap_order + k ] +for k = 0 , ... , p - 1, +is the k-th order Taylor coefficient corresponding to z. +\n +\b Input: +taylor [ ( i_z - j) * cap_order + k ] +for k = 0 , ... , p-1, +and j = 0 , ... , 4, +is the k-th order Taylor coefficient corresponding to the j-th result for z. +\n +\b Output: +taylor [ (i_z-j) * cap_order + k ], +for k = p , ... , q, +and j = 0 , ... , 4, +is the k-th order Taylor coefficient corresponding to the j-th result for z. + +*/ +template +void forward_erf_op( + OpCode op , + size_t p , + size_t q , + size_t i_z , + const addr_t* arg , + const Base* parameter , + size_t cap_order , + Base* taylor ) +{ + // check assumptions + CPPAD_ASSERT_UNKNOWN( op == ErfOp || op == ErfcOp ); + CPPAD_ASSERT_UNKNOWN( NumArg(op) == 3 ); + CPPAD_ASSERT_UNKNOWN( NumRes(op) == 5 ); + CPPAD_ASSERT_UNKNOWN( q < cap_order ); + CPPAD_ASSERT_UNKNOWN( p <= q ); + CPPAD_ASSERT_UNKNOWN( + size_t( std::numeric_limits::max() ) >= i_z + 2 + ); + + // array used to pass parameter values for sub-operations + addr_t addr[2]; + + // convert from final result to first result + i_z -= 4; // 4 = NumRes(ErfOp) - 1; + + // z_0 = x * x + addr[0] = arg[0]; // x + addr[1] = arg[0]; // x + forward_mulvv_op(p, q, i_z+0, addr, parameter, cap_order, taylor); + + // z_1 = - x * x + addr[0] = arg[1]; // zero + addr[1] = addr_t( i_z ); // z_0 + forward_subpv_op(p, q, i_z+1, addr, parameter, cap_order, taylor); + + // z_2 = exp( - x * x ) + forward_exp_op(p, q, i_z+2, i_z+1, cap_order, taylor); + + // z_3 = (2 / sqrt(pi)) * exp( - x * x ) + addr[0] = arg[2]; // 2 / sqrt(pi) + addr[1] = addr_t( i_z + 2 ); // z_2 + forward_mulpv_op(p, q, i_z+3, addr, parameter, cap_order, taylor); + + // pointers to taylor coefficients for x , z_3, and z_4 + Base* x = taylor + size_t(arg[0]) * cap_order; + Base* z_3 = taylor + (i_z+3) * cap_order; + Base* z_4 = taylor + (i_z+4) * cap_order; + + // calculte z_4 coefficients + if( p == 0 ) + { // z4 (t) = erf[x(t)] + if( op == ErfOp ) + z_4[0] = erf(x[0]); + else + z_4[0] = erfc(x[0]); + p++; + } + // sign + Base sign(1.0); + if( op == ErfcOp ) + sign = Base(-1.0); + // + for(size_t j = p; j <= q; j++) + { // erf: z_4' (t) = erf'[x(t)] * x'(t) = z3(t) * x'(t) + // erfc: z_4' (t) = - erf'[x(t)] * x'(t) = - z3(t) * x'(t) + // z_4[1] + 2 * z_4[2] * t + ... = + // sign * (z_3[0] + z_3[1] * t + ...) * (x[1] + 2 * x[2] * t + ...) + Base base_j = static_cast(double(j)); + z_4[j] = static_cast(0); + for(size_t k = 1; k <= j; k++) + z_4[j] += sign * (Base(double(k)) / base_j) * x[k] * z_3[j-k]; + } +} + +/*! +Zero order Forward mode Taylor coefficient for result of op = ErfOp or ErfcOp. + +The C++ source code corresponding to this operation one of +\verbatim + z = erf(x) + z = erfc(x) +\endverbatim + +\tparam Base +base type for the operator; i.e., this operation was recorded +using AD< Base > and computations by this routine are done using type Base. + +\param op +must be either ErfOp or ErfcOp and indicates if this is +z = erf(x) or z = erfc(x). + +\param i_z +variable index corresponding to the last (primary) result for this operation; +i.e. the row index in taylor corresponding to z. +The auxillary results are called y_j have index i_z - j. + +\param arg +arg[0]: is the variable index corresponding to x. +\n +arg[1]: is the parameter index corresponding to the value zero. +\n +arg[2]: is the parameter index correspodning to the value 2 / sqrt(pi). + +\param parameter +parameter[ arg[1] ] is the value zero, +and parameter[ arg[2] ] is the value 2 / sqrt(pi). + +\param cap_order +maximum number of orders that will fit in the taylor array. + +\param taylor +\b Input: +taylor [ size_t(arg[0]) * cap_order + 0 ] +is the zero order Taylor coefficient corresponding to x. +\n +\b Input: +taylor [ i_z * cap_order + 0 ] +is the zero order Taylor coefficient corresponding to z. +\n +\b Output: +taylor [ (i_z-j) * cap_order + 0 ], +for j = 0 , ... , 4, +is the zero order Taylor coefficient for j-th result corresponding to z. + +*/ +template +void forward_erf_op_0( + OpCode op , + size_t i_z , + const addr_t* arg , + const Base* parameter , + size_t cap_order , + Base* taylor ) +{ + // check assumptions + CPPAD_ASSERT_UNKNOWN( op == ErfOp || op == ErfcOp ); + CPPAD_ASSERT_UNKNOWN( NumArg(op) == 3 ); + CPPAD_ASSERT_UNKNOWN( NumRes(op) == 5 ); + CPPAD_ASSERT_UNKNOWN( 0 < cap_order ); + CPPAD_ASSERT_UNKNOWN( + size_t( std::numeric_limits::max() ) >= i_z + 2 + ); + + // array used to pass parameter values for sub-operations + addr_t addr[2]; + + // convert from final result to first result + i_z -= 4; // 4 = NumRes(ErfOp) - 1; + + // z_0 = x * x + addr[0] = arg[0]; // x + addr[1] = arg[0]; // x + forward_mulvv_op_0(i_z+0, addr, parameter, cap_order, taylor); + + // z_1 = - x * x + addr[0] = arg[1]; // zero + addr[1] = addr_t(i_z); // z_0 + forward_subpv_op_0(i_z+1, addr, parameter, cap_order, taylor); + + // z_2 = exp( - x * x ) + forward_exp_op_0(i_z+2, i_z+1, cap_order, taylor); + + // z_3 = (2 / sqrt(pi)) * exp( - x * x ) + addr[0] = arg[2]; // 2 / sqrt(pi) + addr[1] = addr_t(i_z + 2); // z_2 + forward_mulpv_op_0(i_z+3, addr, parameter, cap_order, taylor); + + // zero order Taylor coefficient for z_4 + Base* x = taylor + size_t(arg[0]) * cap_order; + Base* z_4 = taylor + (i_z + 4) * cap_order; + if( op == ErfOp ) + z_4[0] = erf(x[0]); + else + z_4[0] = erfc(x[0]); +} +/*! +Forward mode Taylor coefficient for result of op = ErfOp or ErfcOp. + +The C++ source code corresponding to this operation is one of +\verbatim + z = erf(x) + z = erfc(x) +\endverbatim + +\tparam Base +base type for the operator; i.e., this operation was recorded +using AD< Base > and computations by this routine are done using type Base. + +\param op +must be either ErfOp or ErfcOp and indicates if this is +z = erf(x) or z = erfc(x). + +\param q +order of the Taylor coefficients that we are computing. + +\param r +number of directions for the Taylor coefficients that we afre computing. + +\param i_z +variable index corresponding to the last (primary) result for this operation; +i.e. the row index in taylor corresponding to z. +The auxillary results have index i_z - j for j = 0 , ... , 4 +(and include z). + +\param arg +arg[0]: is the variable index corresponding to x. +\n +arg[1]: is the parameter index corresponding to the value zero. +\n +arg[2]: is the parameter index correspodning to the value 2 / sqrt(pi). + +\param parameter +parameter[ arg[1] ] is the value zero, +and parameter[ arg[2] ] is the value 2 / sqrt(pi). + +\param cap_order +maximum number of orders that will fit in the taylor array. + +\par tpv +We use the notation +tpv = (cap_order-1) * r + 1 +which is the number of Taylor coefficients per variable + +\param taylor +\b Input: If x is a variable, +taylor [ arg[0] * tpv + 0 ], +is the zero order Taylor coefficient for all directions and +taylor [ arg[0] * tpv + (k-1)*r + ell + 1 ], +for k = 1 , ... , q, +ell = 0, ..., r-1, +is the k-th order Taylor coefficient +corresponding to x and the ell-th direction. +\n +\b Input: +taylor [ (i_z - j) * tpv + 0 ] +is the zero order Taylor coefficient for all directions and the +j-th result for z. +for k = 1 , ... , q-1, +ell = 0, ... , r-1, + +taylor[ (i_z - j) * tpv + (k-1)*r + ell + 1] + +is the Taylor coefficient for the k-th order, ell-th direction, +and j-th auzillary result. +\n +\b Output: +taylor [ (i_z-j) * tpv + (q-1)*r + ell + 1 ], +for ell = 0 , ... , r-1, +is the Taylor coefficient for the q-th order, ell-th direction, +and j-th auzillary result. + +*/ +template +void forward_erf_op_dir( + OpCode op , + size_t q , + size_t r , + size_t i_z , + const addr_t* arg , + const Base* parameter , + size_t cap_order , + Base* taylor ) +{ + // check assumptions + CPPAD_ASSERT_UNKNOWN( op == ErfOp || op == ErfcOp ); + CPPAD_ASSERT_UNKNOWN( NumArg(op) == 3 ); + CPPAD_ASSERT_UNKNOWN( NumRes(op) == 5 ); + CPPAD_ASSERT_UNKNOWN( q < cap_order ); + CPPAD_ASSERT_UNKNOWN( 0 < q ); + CPPAD_ASSERT_UNKNOWN( + size_t( std::numeric_limits::max() ) >= i_z + 2 + ); + + // array used to pass parameter values for sub-operations + addr_t addr[2]; + + // convert from final result to first result + i_z -= 4; // 4 = NumRes(ErfOp) - 1; + + // z_0 = x * x + addr[0] = arg[0]; // x + addr[1] = arg[0]; // x + forward_mulvv_op_dir(q, r, i_z+0, addr, parameter, cap_order, taylor); + + // z_1 = - x * x + addr[0] = arg[1]; // zero + addr[1] = addr_t( i_z ); // z_0 + forward_subpv_op_dir(q, r, i_z+1, addr, parameter, cap_order, taylor); + + // z_2 = exp( - x * x ) + forward_exp_op_dir(q, r, i_z+2, i_z+1, cap_order, taylor); + + // z_3 = (2 / sqrt(pi)) * exp( - x * x ) + addr[0] = arg[2]; // 2 / sqrt(pi) + addr[1] = addr_t( i_z + 2 ); // z_2 + forward_mulpv_op_dir(q, r, i_z+3, addr, parameter, cap_order, taylor); + + // pointers to taylor coefficients for x , z_3, and z_4 + size_t num_taylor_per_var = (cap_order - 1) * r + 1; + Base* x = taylor + size_t(arg[0]) * num_taylor_per_var; + Base* z_3 = taylor + (i_z+3) * num_taylor_per_var; + Base* z_4 = taylor + (i_z+4) * num_taylor_per_var; + + // sign + Base sign(1.0); + if( op == ErfcOp ) + sign = Base(-1.0); + + // erf: z_4' (t) = erf'[x(t)] * x'(t) = z3(t) * x'(t) + // erfc: z_4' (t) = - erf'[x(t)] * x'(t) = z3(t) * x'(t) + // z_4[1] + 2 * z_4[2] * t + ... = + // sign * (z_3[0] + z_3[1] * t + ...) * (x[1] + 2 * x[2] * t + ...) + Base base_q = static_cast(double(q)); + for(size_t ell = 0; ell < r; ell++) + { // index in z_4 and x for q-th order term + size_t m = (q-1)*r + ell + 1; + // initialize q-th order term summation + z_4[m] = sign * z_3[0] * x[m]; + for(size_t k = 1; k < q; k++) + { size_t x_index = (k-1)*r + ell + 1; + size_t z3_index = (q-k-1)*r + ell + 1; + Base bk = Base(double(k)); + z_4[m] += sign * (bk / base_q) * x[x_index] * z_3[z3_index]; + } + } +} + +/*! +Compute reverse mode partial derivatives for result of op = ErfOp or ErfcOp. + +The C++ source code corresponding to this operation is one of +\verbatim + z = erf(x) + z = erfc(x) +\endverbatim + +\tparam Base +base type for the operator; i.e., this operation was recorded +using AD< Base > and computations by this routine are done using type Base. + +\param op +must be either ErfOp or ErfcOp and indicates if this is +z = erf(x) or z = erfc(x). + +\param d +highest order Taylor of the Taylor coefficients that we are computing +the partial derivatives with respect to. + +\param i_z +variable index corresponding to the last (primary) result for this operation; +i.e. the row index in taylor corresponding to z. +The auxillary results are called y_j have index i_z - j. + +\param arg +arg[0]: is the variable index corresponding to x. +\n +arg[1]: is the parameter index corresponding to the value zero. +\n +arg[2]: is the parameter index correspodning to the value 2 / sqrt(pi). + +\param parameter +parameter[ arg[1] ] is the value zero, +and parameter[ arg[2] ] is the value 2 / sqrt(pi). + +\param cap_order +maximum number of orders that will fit in the taylor array. + +\param taylor +\b Input: +taylor [ size_t(arg[0]) * cap_order + k ] +for k = 0 , ... , d, +is the k-th order Taylor coefficient corresponding to x. +\n +taylor [ (i_z - j) * cap_order + k ] +for k = 0 , ... , d, +and for j = 0 , ... , 4, +is the k-th order Taylor coefficient corresponding to the j-th result +for this operation. + +\param nc_partial +number of columns in the matrix containing all the partial derivatives + +\param partial +\b Input: +partial [ size_t(arg[0]) * nc_partial + k ] +for k = 0 , ... , d, +is the partial derivative of G( z , x , w , u , ... ) with respect to +the k-th order Taylor coefficient for x. +\n +\b Input: +partial [ (i_z - j) * nc_partial + k ] +for k = 0 , ... , d, +and for j = 0 , ... , 4, +is the partial derivative of G( z , x , w , u , ... ) with respect to +the k-th order Taylor coefficient for the j-th result of this operation. +\n +\b Output: +partial [ size_t(arg[0]) * nc_partial + k ] +for k = 0 , ... , d, +is the partial derivative of H( x , w , u , ... ) with respect to +the k-th order Taylor coefficient for x. +\n +\b Output: +partial [ (i_z-j) * nc_partial + k ] +for k = 0 , ... , d, +and for j = 0 , ... , 4, +may be used as work space; i.e., may change in an unspecified manner. + +*/ +template +void reverse_erf_op( + OpCode op , + size_t d , + size_t i_z , + const addr_t* arg , + const Base* parameter , + size_t cap_order , + const Base* taylor , + size_t nc_partial , + Base* partial ) +{ + // check assumptions + CPPAD_ASSERT_UNKNOWN( op == ErfOp || op == ErfcOp ); + CPPAD_ASSERT_UNKNOWN( NumArg(op) == 3 ); + CPPAD_ASSERT_UNKNOWN( NumRes(op) == 5 ); + CPPAD_ASSERT_UNKNOWN( d < cap_order ); + CPPAD_ASSERT_UNKNOWN( + size_t( std::numeric_limits::max() ) >= i_z + 2 + ); + + // array used to pass parameter values for sub-operations + addr_t addr[2]; + + // If pz is zero, make sure this operation has no effect + // (zero times infinity or nan would be non-zero). + Base* pz = partial + i_z * nc_partial; + bool skip(true); + for(size_t i_d = 0; i_d <= d; i_d++) + skip &= IdenticalZero(pz[i_d]); + if( skip ) + return; + + // convert from final result to first result + i_z -= 4; // 4 = NumRes(ErfOp) - 1; + + // Taylor coefficients and partials corresponding to x + const Base* x = taylor + size_t(arg[0]) * cap_order; + Base* px = partial + size_t(arg[0]) * nc_partial; + + // Taylor coefficients and partials corresponding to z_3 + const Base* z_3 = taylor + (i_z+3) * cap_order; + Base* pz_3 = partial + (i_z+3) * nc_partial; + + // Taylor coefficients and partials corresponding to z_4 + Base* pz_4 = partial + (i_z+4) * nc_partial; + + // sign + Base sign(1.0); + if( op == ErfcOp ) + sign = Base(-1.0); + + // Reverse z_4 + size_t j = d; + while(j) + { pz_4[j] /= Base(double(j)); + for(size_t k = 1; k <= j; k++) + { px[k] += sign * azmul(pz_4[j], z_3[j-k]) * Base(double(k)); + pz_3[j-k] += sign * azmul(pz_4[j], x[k]) * Base(double(k)); + } + j--; + } + px[0] += sign * azmul(pz_4[0], z_3[0]); + + // z_3 = (2 / sqrt(pi)) * exp( - x * x ) + addr[0] = arg[2]; // 2 / sqrt(pi) + addr[1] = addr_t( i_z + 2 ); // z_2 + reverse_mulpv_op( + d, i_z+3, addr, parameter, cap_order, taylor, nc_partial, partial + ); + + // z_2 = exp( - x * x ) + reverse_exp_op( + d, i_z+2, i_z+1, cap_order, taylor, nc_partial, partial + ); + + // z_1 = - x * x + addr[0] = arg[1]; // zero + addr[1] = addr_t( i_z ); // z_0 + reverse_subpv_op( + d, i_z+1, addr, parameter, cap_order, taylor, nc_partial, partial + ); + + // z_0 = x * x + addr[0] = arg[0]; // x + addr[1] = arg[0]; // x + reverse_mulvv_op( + d, i_z+0, addr, parameter, cap_order, taylor, nc_partial, partial + ); + +} + + +} } // END_CPPAD_LOCAL_NAMESPACE +# endif // CPPAD_ERF_OP_INCLUDED diff --git a/build-config/cppad/include/cppad/local/exp_op.hpp b/build-config/cppad/include/cppad/local/exp_op.hpp new file mode 100644 index 00000000..a5fca7ae --- /dev/null +++ b/build-config/cppad/include/cppad/local/exp_op.hpp @@ -0,0 +1,194 @@ +# ifndef CPPAD_LOCAL_EXP_OP_HPP +# define CPPAD_LOCAL_EXP_OP_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-17 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + + +namespace CppAD { namespace local { // BEGIN_CPPAD_LOCAL_NAMESPACE +/*! +\file exp_op.hpp +Forward and reverse mode calculations for z = exp(x). +*/ + + +/*! +Forward mode Taylor coefficient for result of op = ExpOp. + +The C++ source code corresponding to this operation is +\verbatim + z = exp(x) +\endverbatim + +\copydetails CppAD::local::forward_unary1_op +*/ +template +void forward_exp_op( + size_t p , + size_t q , + size_t i_z , + size_t i_x , + size_t cap_order , + Base* taylor ) +{ + // check assumptions + CPPAD_ASSERT_UNKNOWN( NumArg(ExpOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( NumRes(ExpOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( q < cap_order ); + CPPAD_ASSERT_UNKNOWN( p <= q ); + + // Taylor coefficients corresponding to argument and result + Base* x = taylor + i_x * cap_order; + Base* z = taylor + i_z * cap_order; + + size_t k; + if( p == 0 ) + { z[0] = exp( x[0] ); + p++; + } + for(size_t j = p; j <= q; j++) + { + z[j] = x[1] * z[j-1]; + for(k = 2; k <= j; k++) + z[j] += Base(double(k)) * x[k] * z[j-k]; + z[j] /= Base(double(j)); + } +} + + +/*! +Multiple direction forward mode Taylor coefficient for op = ExpOp. + +The C++ source code corresponding to this operation is +\verbatim + z = exp(x) +\endverbatim + +\copydetails CppAD::local::forward_unary1_op_dir +*/ +template +void forward_exp_op_dir( + size_t q , + size_t r , + size_t i_z , + size_t i_x , + size_t cap_order , + Base* taylor ) +{ + // check assumptions + CPPAD_ASSERT_UNKNOWN( NumArg(ExpOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( NumRes(ExpOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( q < cap_order ); + CPPAD_ASSERT_UNKNOWN( 0 < q ); + + // Taylor coefficients corresponding to argument and result + size_t num_taylor_per_var = (cap_order-1) * r + 1; + Base* x = taylor + i_x * num_taylor_per_var; + Base* z = taylor + i_z * num_taylor_per_var; + + size_t m = (q-1)*r + 1; + for(size_t ell = 0; ell < r; ell++) + { z[m+ell] = Base(double(q)) * x[m+ell] * z[0]; + for(size_t k = 1; k < q; k++) + z[m+ell] += Base(double(k)) * x[(k-1)*r+ell+1] * z[(q-k-1)*r+ell+1]; + z[m+ell] /= Base(double(q)); + } +} + +/*! +Zero order forward mode Taylor coefficient for result of op = ExpOp. + +The C++ source code corresponding to this operation is +\verbatim + z = exp(x) +\endverbatim + +\copydetails CppAD::local::forward_unary1_op_0 +*/ +template +void forward_exp_op_0( + size_t i_z , + size_t i_x , + size_t cap_order , + Base* taylor ) +{ + // check assumptions + CPPAD_ASSERT_UNKNOWN( NumArg(ExpOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( NumRes(ExpOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( 0 < cap_order ); + + // Taylor coefficients corresponding to argument and result + Base* x = taylor + i_x * cap_order; + Base* z = taylor + i_z * cap_order; + + z[0] = exp( x[0] ); +} +/*! +Reverse mode partial derivatives for result of op = ExpOp. + +The C++ source code corresponding to this operation is +\verbatim + z = exp(x) +\endverbatim + +\copydetails CppAD::local::reverse_unary1_op +*/ + +template +void reverse_exp_op( + size_t d , + size_t i_z , + size_t i_x , + size_t cap_order , + const Base* taylor , + size_t nc_partial , + Base* partial ) +{ + // check assumptions + CPPAD_ASSERT_UNKNOWN( NumArg(ExpOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( NumRes(ExpOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( d < cap_order ); + CPPAD_ASSERT_UNKNOWN( d < nc_partial ); + + // Taylor coefficients and partials corresponding to argument + const Base* x = taylor + i_x * cap_order; + Base* px = partial + i_x * nc_partial; + + // Taylor coefficients and partials corresponding to result + const Base* z = taylor + i_z * cap_order; + Base* pz = partial + i_z * nc_partial; + + // If pz is zero, make sure this operation has no effect + // (zero times infinity or nan would be non-zero). + bool skip(true); + for(size_t i_d = 0; i_d <= d; i_d++) + skip &= IdenticalZero(pz[i_d]); + if( skip ) + return; + + // loop through orders in reverse + size_t j, k; + j = d; + while(j) + { // scale partial w.r.t z[j] + pz[j] /= Base(double(j)); + + for(k = 1; k <= j; k++) + { px[k] += Base(double(k)) * azmul(pz[j], z[j-k]); + pz[j-k] += Base(double(k)) * azmul(pz[j], x[k]); + } + --j; + } + px[0] += azmul(pz[0], z[0]); +} + +} } // END_CPPAD_LOCAL_NAMESPACE +# endif diff --git a/build-config/cppad/include/cppad/local/expm1_op.hpp b/build-config/cppad/include/cppad/local/expm1_op.hpp new file mode 100644 index 00000000..ea80fc96 --- /dev/null +++ b/build-config/cppad/include/cppad/local/expm1_op.hpp @@ -0,0 +1,199 @@ +# ifndef CPPAD_LOCAL_EXPM1_OP_HPP +# define CPPAD_LOCAL_EXPM1_OP_HPP + +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + + +namespace CppAD { namespace local { // BEGIN_CPPAD_LOCAL_NAMESPACE +/*! +\file expm1_op.hpp +Forward and reverse mode calculations for z = expm1(x). +*/ + + +/*! +Forward mode Taylor coefficient for result of op = Expm1Op. + +The C++ source code corresponding to this operation is +\verbatim + z = expm1(x) +\endverbatim + +\copydetails CppAD::local::forward_unary1_op +*/ +template +void forward_expm1_op( + size_t p , + size_t q , + size_t i_z , + size_t i_x , + size_t cap_order , + Base* taylor ) +{ + // check assumptions + CPPAD_ASSERT_UNKNOWN( NumArg(Expm1Op) == 1 ); + CPPAD_ASSERT_UNKNOWN( NumRes(Expm1Op) == 1 ); + CPPAD_ASSERT_UNKNOWN( q < cap_order ); + CPPAD_ASSERT_UNKNOWN( p <= q ); + + // Taylor coefficients corresponding to argument and result + Base* x = taylor + i_x * cap_order; + Base* z = taylor + i_z * cap_order; + + size_t k; + if( p == 0 ) + { z[0] = expm1( x[0] ); + p++; + } + for(size_t j = p; j <= q; j++) + { + z[j] = x[1] * z[j-1]; + for(k = 2; k <= j; k++) + z[j] += Base(double(k)) * x[k] * z[j-k]; + z[j] /= Base(double(j)); + z[j] += x[j]; + } +} + + +/*! +Multiple direction forward mode Taylor coefficient for op = Expm1Op. + +The C++ source code corresponding to this operation is +\verbatim + z = expm1(x) +\endverbatim + +\copydetails CppAD::local::forward_unary1_op_dir +*/ +template +void forward_expm1_op_dir( + size_t q , + size_t r , + size_t i_z , + size_t i_x , + size_t cap_order , + Base* taylor ) +{ + // check assumptions + CPPAD_ASSERT_UNKNOWN( NumArg(Expm1Op) == 1 ); + CPPAD_ASSERT_UNKNOWN( NumRes(Expm1Op) == 1 ); + CPPAD_ASSERT_UNKNOWN( q < cap_order ); + CPPAD_ASSERT_UNKNOWN( 0 < q ); + + // Taylor coefficients corresponding to argument and result + size_t num_taylor_per_var = (cap_order-1) * r + 1; + Base* x = taylor + i_x * num_taylor_per_var; + Base* z = taylor + i_z * num_taylor_per_var; + + size_t m = (q-1)*r + 1; + for(size_t ell = 0; ell < r; ell++) + { z[m+ell] = Base(double(q)) * x[m+ell] * z[0]; + for(size_t k = 1; k < q; k++) + z[m+ell] += Base(double(k)) * x[(k-1)*r+ell+1] * z[(q-k-1)*r+ell+1]; + z[m+ell] /= Base(double(q)); + z[m+ell] += x[m+ell]; + } +} + +/*! +Zero order forward mode Taylor coefficient for result of op = Expm1Op. + +The C++ source code corresponding to this operation is +\verbatim + z = expm1(x) +\endverbatim + +\copydetails CppAD::local::forward_unary1_op_0 +*/ +template +void forward_expm1_op_0( + size_t i_z , + size_t i_x , + size_t cap_order , + Base* taylor ) +{ + // check assumptions + CPPAD_ASSERT_UNKNOWN( NumArg(Expm1Op) == 1 ); + CPPAD_ASSERT_UNKNOWN( NumRes(Expm1Op) == 1 ); + CPPAD_ASSERT_UNKNOWN( 0 < cap_order ); + + // Taylor coefficients corresponding to argument and result + Base* x = taylor + i_x * cap_order; + Base* z = taylor + i_z * cap_order; + + z[0] = expm1( x[0] ); +} +/*! +Reverse mode partial derivatives for result of op = Expm1Op. + +The C++ source code corresponding to this operation is +\verbatim + z = expm1(x) +\endverbatim + +\copydetails CppAD::local::reverse_unary1_op +*/ + +template +void reverse_expm1_op( + size_t d , + size_t i_z , + size_t i_x , + size_t cap_order , + const Base* taylor , + size_t nc_partial , + Base* partial ) +{ + // check assumptions + CPPAD_ASSERT_UNKNOWN( NumArg(Expm1Op) == 1 ); + CPPAD_ASSERT_UNKNOWN( NumRes(Expm1Op) == 1 ); + CPPAD_ASSERT_UNKNOWN( d < cap_order ); + CPPAD_ASSERT_UNKNOWN( d < nc_partial ); + + // Taylor coefficients and partials corresponding to argument + const Base* x = taylor + i_x * cap_order; + Base* px = partial + i_x * nc_partial; + + // Taylor coefficients and partials corresponding to result + const Base* z = taylor + i_z * cap_order; + Base* pz = partial + i_z * nc_partial; + + // If pz is zero, make sure this operation has no effect + // (zero times infinity or nan would be non-zero). + bool skip(true); + for(size_t i_d = 0; i_d <= d; i_d++) + skip &= IdenticalZero(pz[i_d]); + if( skip ) + return; + + // loop through orders in reverse + size_t j, k; + j = d; + while(j) + { px[j] += pz[j]; + + // scale partial w.r.t z[j] + pz[j] /= Base(double(j)); + + for(k = 1; k <= j; k++) + { px[k] += Base(double(k)) * azmul(pz[j], z[j-k]); + pz[j-k] += Base(double(k)) * azmul(pz[j], x[k]); + } + --j; + } + px[0] += pz[0] + azmul(pz[0], z[0]); +} + +} } // END_CPPAD_LOCAL_NAMESPACE +# endif diff --git a/build-config/cppad/include/cppad/local/graph/cpp_graph_itr.hpp b/build-config/cppad/include/cppad/local/graph/cpp_graph_itr.hpp new file mode 100644 index 00000000..deb5ebdf --- /dev/null +++ b/build-config/cppad/include/cppad/local/graph/cpp_graph_itr.hpp @@ -0,0 +1,386 @@ +# ifndef CPPAD_LOCAL_GRAPH_CPP_GRAPH_ITR_HPP +# define CPPAD_LOCAL_GRAPH_CPP_GRAPH_ITR_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ +# include +# include + +// BEGIN_CPPAD_LOCAL_GRAPH_NAMESPACE +namespace CppAD { namespace local { namespace graph { + +class cpp_graph_itr { +/* +$begin cpp_graph_itr_data$$ +$spell + Iterator +$$ + +$section C++ AD Graph Iterator Private Member Data$$ +$srccode%hpp% */ +private: + // valuse set by constructor + const vector* operator_vec_; + const vector* operator_arg_; + // + // set by constructor and ++ + size_t op_index_; + size_t first_arg_; + // + // set by get_value + size_t first_node_; + graph_op_enum op_enum_; + vector str_index_; + size_t n_result_; + vector arg_node_; +/* %$$ +$end +------------------------------------------------------------------------------ +$begin cpp_graph_itr_get_value$$ +$spell + obj + op + arg + vec + enum + Iterator + itr + str +$$ + +$section C++ AD Graph Iterator get_value()$$ + +$head Syntax$$ +$icode%itr%.get_value()%$$ + +$head op_index_$$ +This input is the operator index for the value we are retrieving. + +$head first_arg_$$ +This input is the first argument index for the value we are retrieving. + +$head first_node_$$ +The input value of this argument does not matter. +It is set to the index in $code operator_arg_$$ +of the first node argument for this operator. + +$head op_enum_$$ +The input value of this argument does not matter. +It is set to the $cref graph_op_enum$$ for the operator + +$head str_index_$$ +The input value of this argument does not matter. +Upon return its size is zero except for the special cases +listed below: + +$subhead atom_graph_op$$ +If $icode op_enum_$$ is $code atom_graph_op$$, +$code str_index_.size() == 1$$ and +$code str_index_[0]$$ is the index in +$cref/atomic_name_vec/cpp_ad_graph/atomic_name_vec/$$ +for the function called by this operator. + +$subhead discrete_graph_op$$ +If $icode op_enum_$$ is $code discrete_graph_op$$, +$code str_index_.size() == 1$$ and +$code str_index_[0]$$ is the index in +$cref/discrete_name_vec/cpp_ad_graph/discrete_name_vec/$$ +for the function called by this operator. + +$subhead print_graph_op$$ +If $icode op_enum_$$ is $code print_graph_op$$, +$code str_index_.size() == 2$$ and +$code str_index_[0]$$ ( $code str_index_[1]$$ ) +is the index in +$cref/print_text_vec/cpp_ad_graph/print_text_vec/$$ for the +$cref/before/PrintFor/before/$$ ($cref/after/PrintFor/after/$$) text. + +$head n_result_$$ +The input value of this argument does not matter. +This is set to the number of result nodes for this operator. + +$head arg_node_$$ +The input value of this argument does not matter. +Upon return, its size is the number of arguments, +that are node indices, for this operator usage. +The value of the elements are the node indices. + +$head Prototype$$ +$srccode%hpp% */ + void get_value(void) +/* %$$ +$end +*/ +{ // initialize output values + size_t invalid_index = std::numeric_limits::max(); + size_t n_arg = invalid_index; + first_node_ = invalid_index; + n_result_ = invalid_index; + str_index_.resize(0); + arg_node_.resize(0); + // + // op_enum + op_enum_ = (*operator_vec_)[op_index_]; + // + // n_result_, n_arg, str_index_ + switch( op_enum_ ) + { + // unary operators + case abs_graph_op: + case acos_graph_op: + case acosh_graph_op: + case asin_graph_op: + case asinh_graph_op: + case atan_graph_op: + case atanh_graph_op: + case cos_graph_op: + case cosh_graph_op: + case erf_graph_op: + case erfc_graph_op: + case exp_graph_op: + case expm1_graph_op: + case log1p_graph_op: + case log_graph_op: + case sign_graph_op: + case sin_graph_op: + case sinh_graph_op: + case sqrt_graph_op: + case tan_graph_op: + case tanh_graph_op: + first_node_ = first_arg_; + n_result_ = 1; + n_arg = 1; + break; + + // binary operators + case add_graph_op: + case azmul_graph_op: + case div_graph_op: + case mul_graph_op: + case pow_graph_op: + case sub_graph_op: + first_node_ = first_arg_; + n_result_ = 1; + n_arg = 2; + break; + + // discrete_graph_op + case discrete_graph_op: + first_node_ = first_arg_ + 1; + str_index_.push_back( (*operator_arg_)[first_node_ - 1] ); + n_result_ = 1; + n_arg = 1; + break; + + + // atom_graph_op + case atom_graph_op: + first_node_ = first_arg_ + 3; + str_index_.push_back( (*operator_arg_)[first_node_ - 3] ); + n_result_ = (*operator_arg_)[first_node_ - 2]; + n_arg = (*operator_arg_)[first_node_ - 1]; + break; + + // print_graph_op + case print_graph_op: + first_node_ = first_arg_ + 2; + str_index_.push_back( (*operator_arg_)[first_node_ - 2] ); + str_index_.push_back( (*operator_arg_)[first_node_ - 1] ); + n_result_ = 0; + n_arg = 2; + break; + + + // conditional expressions + case cexp_eq_graph_op: + case cexp_le_graph_op: + case cexp_lt_graph_op: + first_node_ = first_arg_; + n_result_ = 1; + n_arg = 4; + break; + + // comparison operators + case comp_eq_graph_op: + case comp_le_graph_op: + case comp_lt_graph_op: + case comp_ne_graph_op: + first_node_ = first_arg_; + n_result_ = 0; + n_arg = 2; + break; + + // sum_graph_op + case sum_graph_op: + first_node_ = first_arg_ + 1; + n_result_ = 1; + n_arg = (*operator_arg_)[first_node_ - 1]; + break; + + default: + CPPAD_ASSERT_UNKNOWN(false); + break; + } + // set arg_node + arg_node_.resize(n_arg); + for(size_t i = 0; i < n_arg; i++) + arg_node_[i] = (*operator_arg_)[first_node_ + i]; + + return; +} +/* %$$ +$end +------------------------------------------------------------------------------- +$begin cpp_graph_itr_types$$ +$spell + Iterator +$$ + +$section C++ AD Graph Iterator Types$$ + +$srccode%hpp% */ +public: + typedef struct { + graph_op_enum op_enum; + const vector* str_index_ptr; + size_t n_result; + const vector* arg_node_ptr; + } value_type; + typedef std::input_iterator_tag iterator_category; +/* %$$ +$end +------------------------------------------------------------------------------ +$begin cpp_graph_itr_ctor$$ +$spell + Iterator + itr + vec + arg + op + cpp +$$ + +$section C++ AD Graph Iterator Constructors$$ + +$head Syntax$$ +$codei%cpp_graph_itr %default% +%$$ +$codei%cpp_graph_itr %itr%(%operator_vec%, %operator_arg%, %op_index% +%$$ + +$head Prototype$$ +$srcthisfile% + 0%// BEGIN_CTOR%// END_CTOR%1 +%$$ + +$head default$$ +The result of the default constructor can only be used as a target +for the assignment operator. + +$head operator_vec$$ +Is the $cref/operator_vec/cpp_ad_graph/operator_vec/$$ +for the $code cpp_graph$$ container that this iterator refers to. + +$head operator_arg$$ +Is the $cref/operator_arg/cpp_ad_graph/operator_vec/$$ +for the $code cpp_graph$$ container that this iterator refers to. + +$head op_index$$ +This must be either zero (the $code begin()$$ for the container) +or equal to the size of $icode operator_vec$$ +(the $code end()$$ for the container). + +$end +*/ + cpp_graph_itr(void) + : operator_vec_(nullptr), operator_arg_(nullptr) + { } + // BEGIN_CTOR + cpp_graph_itr( + const vector& operator_vec , + const vector& operator_arg , + size_t op_index ) + // END_CTOR + : + operator_vec_(&operator_vec) , + operator_arg_(&operator_arg) , + op_index_(op_index) + { // end constructor + if( op_index == operator_vec.size() ) + return; + // + // begin constructor + CPPAD_ASSERT_KNOWN( op_index == 0, + "cpp_graph_itr: constructor op_index not 0 or operator_vec.size()" + ); + // start at the beginning of operator_vec + first_arg_ = 0; + // + // get the value, and first_node_, for this operator + get_value(); + } +/* %$$ +------------------------------------------------------------------------------ +$begin cpp_graph_itr_input$$ +$spell + Iterator +$$ + +$section C++ AD Graph Iterator Input Operations$$ + +$srccode%hpp% */ + // itr == other + bool operator==(const cpp_graph_itr& other) const + { return op_index_ == other.op_index_; + } + // itr != other + bool operator!=(const cpp_graph_itr& other) const + { return op_index_ != other.op_index_; + } + // *itr + value_type operator*(void) + { CPPAD_ASSERT_KNOWN( operator_vec_ != nullptr, + "cpp_graph_itr: attempt to dereference default iterator" + ); + CPPAD_ASSERT_KNOWN( op_index_ < operator_vec_->size(), + "cpp_graph_itr: attempt to dereference past last element in graph" + ); + value_type ret; + ret.op_enum = op_enum_; + ret.str_index_ptr = &str_index_; + ret.n_result = n_result_; + ret.arg_node_ptr = &arg_node_; + return ret; + } + // ++itr + cpp_graph_itr& operator++(void) + { ++op_index_; + first_arg_ = first_node_ + arg_node_.size(); + get_value(); + return *this; + } + // itr++ + cpp_graph_itr operator++(int) + { cpp_graph_itr ret(*this); + ++op_index_; + first_arg_ = first_node_ + arg_node_.size(); + get_value(); + return ret; + } +/* %$$ +$end +*/ + +}; + +} } } // END_CPPAD_LOCAL_GRAPH_NAMESPACE + +# endif diff --git a/build-config/cppad/include/cppad/local/graph/cpp_graph_itr.omh b/build-config/cppad/include/cppad/local/graph/cpp_graph_itr.omh new file mode 100644 index 00000000..ec6b64b6 --- /dev/null +++ b/build-config/cppad/include/cppad/local/graph/cpp_graph_itr.omh @@ -0,0 +1,23 @@ +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 Bradley M. Bell + + CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + + This Source Code may also be made available under the following + Secondary License when the conditions for such availability set forth + in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +-------------------------------------------------------------------------- */ +$begin cpp_graph_itr$$ +$spell + Iterator +$$ + +$section C++ AD Graph Iterator Class$$ + +$childtable% + include/cppad/local/graph/cpp_graph_itr.hpp +%$$ + +$end diff --git a/build-config/cppad/include/cppad/local/graph/cpp_graph_op.hpp b/build-config/cppad/include/cppad/local/graph/cpp_graph_op.hpp new file mode 100644 index 00000000..0f278ed1 --- /dev/null +++ b/build-config/cppad/include/cppad/local/graph/cpp_graph_op.hpp @@ -0,0 +1,94 @@ +# ifndef CPPAD_LOCAL_GRAPH_CPP_GRAPH_OP_HPP +# define CPPAD_LOCAL_GRAPH_CPP_GRAPH_OP_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 Bradley M. Bell + + CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + + This Source Code may also be made available under the following + Secondary License when the conditions for such availability set forth + in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +-------------------------------------------------------------------------- */ + +# include +# include +# include + +# include +# include +# include + +namespace CppAD { namespace local { namespace graph { +/* +$begin cpp_graph_op$$ +$spell + vec + asinh + acosh + atanh + erf + erfc + expm + namespace + enum + struct + op + arg + CppAD + addr_t +$$ + +$section C++ AD Graph Operators$$ + +$head Namespace$$ +All of these definitions +are in the $code CppAD::local::graph$$ namespace. + +$head CppAD::graph$$ +$srccode%hpp% */ + using namespace CppAD::graph; +/* %$$ + +$head addr_t$$ +$srccode%hpp% */ + typedef CPPAD_TAPE_ADDR_TYPE addr_t; +/* %$$ + +$head op_name2enum$$ +This is a mapping from the operator name to its enum value. +The name is the operator enum without the $code _operator$$ at the end. +$srccode%hpp% */ + extern std::map< std::string, graph_op_enum > op_name2enum; +/* %$$ + +$head op_enum2fixed_n_arg$$ +This is the number of arguments for the operators that have +a fixed number of arguments and one result. +For other operators, this value is zero. +$srccode%hpp% */ + extern size_t op_enum2fixed_n_arg[]; +/* %$$ + +$head op_enum2name$$ +This is mapping from operator enum value to its name. +In the $code local::graph$$ namespace: +$srccode%hpp% */ + extern const char* op_enum2name[]; +/* %$$ + +$head set_operator_info$$ +This routine sets the values in +$code op_enum2fixed_n_arg$$, +$code op_enum2name$$, and +$code op_name2enum$$. +$srccode%hpp% */ + extern void set_operator_info(void); +/* %$$ +$end +*/ + +} } } // END_CPPAD_LOCAL_GRAPH_NAMESPACE + +# endif diff --git a/build-config/cppad/include/cppad/local/graph/dev_graph.omh b/build-config/cppad/include/cppad/local/graph/dev_graph.omh new file mode 100644 index 00000000..db7f8c77 --- /dev/null +++ b/build-config/cppad/include/cppad/local/graph/dev_graph.omh @@ -0,0 +1,28 @@ +----------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 Bradley M. Bell + + CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + + This Source Code may also be made available under the following + Secondary License when the conditions for such availability set forth + in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +----------------------------------------------------------------------------- +$begin dev_graph$$ +$spell + Json +$$ + +$section Developer AD Graph Documentation$$ + +$childtable% + include/cppad/local/graph/cpp_graph_itr.omh% + include/cppad/local/graph/cpp_graph_op.hpp% + include/cppad/local/graph/json_lexer.omh% + include/cppad/local/graph/json_parser.hpp% + include/cppad/local/graph/json_writer.hpp +%$$ + + +$end diff --git a/build-config/cppad/include/cppad/local/graph/json_lexer.hpp b/build-config/cppad/include/cppad/local/graph/json_lexer.hpp new file mode 100644 index 00000000..11873ce5 --- /dev/null +++ b/build-config/cppad/include/cppad/local/graph/json_lexer.hpp @@ -0,0 +1,389 @@ +# ifndef CPPAD_LOCAL_GRAPH_JSON_LEXER_HPP +# define CPPAD_LOCAL_GRAPH_JSON_LEXER_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 Bradley M. Bell + + CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + + This Source Code may also be made available under the following + Secondary License when the conditions for such availability set forth + in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +-------------------------------------------------------------------------- */ + +# include +# include + +// BEGIN_NAMESPACE_CPPAD_LOCAL_GRAPH +namespace CppAD { namespace local { namespace graph { + +// =========================================================================== +class json_lexer { +// =========================================================================== + +/* +------------------------------------------------------------------------------- +$begin json_lexer_member_data$$ +$spell + json + lexer +$$ + +$section json lexer: Private Data$$ + +$head graph_$$ +The $cref json_ad_graph$$. + +$head index_$$ +is the index in the graph for the current character. +If a token is returned, this corresponds to the last character +it the token. + +$head line_number_$$ +line number in the graph for the current character + +$head char_number_$$ +character number in the graph for the current character + +$head token_$$ +used to return tokens. + +$head function_name_$$ +is the function name for this graph. +This is initialized as empty, +should be set as soon as it is parsed, +and is used for error reporting. + +$head token$$ +returns current value of $code token_$$. + +$head line_number$$ +returns current value of $code line_number_$$ +(which corresponds to last character in the token). + +$head char_number$$ +returns current value of $code char_number_$$. +(which corresponds to last character in the token). + +$head set_function_name$$ +sets the value of $code function_name_$$. + +$head Source Code$$ +$srccode%hpp% */ +private: + const std::string& json_; + size_t index_; + size_t line_number_; + size_t char_number_; + std::string token_; + std::string function_name_; +public: + const std::string& token(void) const; + size_t line_number(void) const; + size_t char_number(void) const; + void set_function_name(const std::string& function_name); +/* %$$ +$end +------------------------------------------------------------------------------- +$begin json_lexer_report_error$$ +$spell + json + lexer + CppAD +$$ + +$section json lexer: Report an Error$$ + +$head Syntax$$ +$codei% + %json_lexer%.report_error(%expected%, %found%) +%$$ + +$head json_lexer$$ +is a $code local::graph::json_lexer$$ object. + +$head expected$$ +is the token that is expected. + +$head found$$ +is the token or text that was found. + +$head Report$$ +The current CppAD $cref ErrorHandler$$ is used to report +an error parsing this Json AD graph. + +$head Prototype$$ +$srccode%hpp% */ +public: + void report_error(const std::string& expected, const std::string& found); +/* %$$ +$end +------------------------------------------------------------------------------- +$begin json_lexer_next_index$$ +$spell + json + lexer +$$ + +$section json lexer: Advance Index by One$$ + +$head Syntax$$ +$codei% + %json_lexer%.next_index() +%$$ + +$head json_lexer$$ +is a $code local::graph::json_lexer$$ object. + +$head index_$$ +The input value of $code index_$$ is increased by one. +It is an error to call this routine when the input value +of $code index_$$ is greater than or equal $code json_.size()$$. + +$head line_number_$$ +If the previous character, before the call, was a new line, +$code line_number_$$ is increased by one. + +$head char_number_$$ +If the previous character, before the call, was a new line, +$code char_number$$ is set to one. +Otherwise, $code char_number_$$ is increased by one. + +$head Prototype$$ +$srccode%hpp% */ +private: + void next_index(void); +/* %$$ +$end +------------------------------------------------------------------------------- +$begin json_lexer_skip_white_space$$ +$spell + json + lexer +$$ + +$section json lexer: Skip White Space That Separates Tokens$$ + +$head Syntax$$ +$codei% + %json_lexer%.skip_white_space() +%$$ + +$head json_lexer$$ +is a json lexer object. + +$head Discussion$$ +This member functions is used to increase $code index_$$ until either +a non-white space character is found or $code index_$$ is equal +to $code json_.size()$$. + +$head Prototype$$ +$srccode%hpp% */ +private: + void skip_white_space(void); +/* %$$ +$end +------------------------------------------------------------------------------- +$begin json_lexer_constructor$$ +$spell + json + lexer + enum + op + arg +$$ + +$section json lexer: Constructor$$ + +$head Syntax$$ +$codei% + local::graph::lexer %json_lexer%(%json%) +%$$ + +$head json$$ +The argument $icode json$$ is an $cref json_ad_graph$$ +and it is assumed that $icode json$$ does not change +for as long as $icode json_lexer$$ exists. + +$head Initialization$$ +The current token, index, line number, and character number +are set to the first non white space character in $code json_$$. +If this is not a left brace character $code '{'$$, +the error is reported and the constructor does not return. + +$head Side Effect$$ +If $code local::graph::op_name2enum.size() == 0$$, +the routine $cref/set_operator_info/cpp_graph_op/set_operator_info/$$ +is called to initialize +$code op_enum2fixed_n_arg$$, +$code op_enum2name$$, and +$code op_name2enum$$. +This initialization cannot be done in +$cref/parallel mode/ta_in_parallel/$$. + +$head Prototype$$ +$srccode%hpp% */ +public: + json_lexer(const std::string& json); +/* %$$ +$end +------------------------------------------------------------------------------- +$begin json_lexer_check_next_char$$ +$spell + json + lexer + ch +$$ + +$section Get and Check Next Single Character Token$$ + +$head Syntax$$ +$codei% + %json_lexer%.check_next_char(%ch%) +%$$ + +$head index_$$ +The search for the character starts +at one greater than the input value for $code index_$$ and skips white space. + +$head ch$$ +Is a non white space +single character token that is expected. +If this character is not found, +the error is reported and this function does not return. +In the special case where $icode ch$$ is $code '\0'$$, +any non-white space character will be accepted +(but there must be such a character). + +$head token_$$ +If this routine returns, $code token_$$ has size one +and contains the character that is found. + + +$head Prototype$$ +$srccode%hpp% */ +public: + void check_next_char(char ch); +/* %$$ +$end +------------------------------------------------------------------------------- +$begin json_lexer_check_next_string$$ +$spell + json + lexer +$$ + +$section Get and Check Next Single Character Token$$ + +$head Syntax$$ +$codei% + %json_lexer%.check_next_string(%expected%) +%$$ + +$head index_$$ +The search for the string starts +at one greater than the input value for $code index_$$ and skips white space. + +$head expected$$ +Is the value (not including double quotes) for the string that is expected. +If this string is not found, the error is reported +and this function does not return. +In the special case where $icode expected$$ is empty, +any string will be accepted. + +$head token_$$ +If this routine returns, +$icode token_$$ is the string that was found. + + +$head Prototype$$ +$srccode%hpp% */ +public: + void check_next_string(const std::string& expected); +/* %$$ +$end +------------------------------------------------------------------------------- +$begin json_lexer_next_non_neg_int$$ +$spell + json + lexer + neg +$$ + +$section Get Next Non-Negative Integer$$ + +$head Syntax$$ +$codei% + %json_lexer%.next_non_neg_int() + %value% = %json_lexer%.token2size_t() +%$$ + +$head index_$$ +The search for the non-negative integer starts +at one greater than the input value for $code index_$$ and skips white space. + +$head token_$$ +is set to the non-negative integer. +If the next token is not a non-negative integer, +the error is reported and this function does not return. + +$head value$$ +If the current token is a non-negative integer, +$icode value$$ is the corresponding value. + +$head Prototype$$ +$srccode%hpp% */ +public: + void next_non_neg_int(void); + size_t token2size_t(void) const; + +/* %$$ +$end +------------------------------------------------------------------------------- +$begin json_lexer_next_float$$ +$spell + json + lexer +$$ + +$section Get Next Floating Point Number$$ + +$head Syntax$$ +$codei% + %ok% = %json_lexer%.next_float() + %value% = %json_lexer%.token2double() +%$$ + +$head index_$$ +The search for the floating point number starts +at one greater than the input value for $code index_$$ and skips white space. + +$head token_$$ +is set to the floating point number. +If the next token is not a floating point number, +the error is reported and this function does not return. + +$head value$$ +If the current token is a floating point number, +$icode value$$ is the corresponding value. + +$head Prototype$$ +$srccode%hpp% */ +public: + void next_float(void); + double token2double(void) const; + +/* %$$ +$end +*/ + +// ========================================================================== +}; // end class lexer +// ========================================================================== + + +} } } // END_NAMESPACE_CPPAD_LOCAL_GRAPH + + +# endif diff --git a/build-config/cppad/include/cppad/local/graph/json_lexer.omh b/build-config/cppad/include/cppad/local/graph/json_lexer.omh new file mode 100644 index 00000000..5d8cc410 --- /dev/null +++ b/build-config/cppad/include/cppad/local/graph/json_lexer.omh @@ -0,0 +1,24 @@ +----------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 Bradley M. Bell + + CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + + This Source Code may also be made available under the following + Secondary License when the conditions for such availability set forth + in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +----------------------------------------------------------------------------- +$begin json_lexer$$ +$spell + Json +$$ + +$section Lexical Analysis Class for a Json AD Graph$$. + +$childtable% + include/cppad/local/graph/json_lexer.hpp +%$$ + + +$end diff --git a/build-config/cppad/include/cppad/local/graph/json_parser.hpp b/build-config/cppad/include/cppad/local/graph/json_parser.hpp new file mode 100644 index 00000000..17bcc7c7 --- /dev/null +++ b/build-config/cppad/include/cppad/local/graph/json_parser.hpp @@ -0,0 +1,55 @@ +# ifndef CPPAD_LOCAL_GRAPH_JSON_PARSER_HPP +# define CPPAD_LOCAL_GRAPH_JSON_PARSER_HPP + +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 Bradley M. Bell + + CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + + This Source Code may also be made available under the following + Secondary License when the conditions for such availability set forth + in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +-------------------------------------------------------------------------- */ + +# include +# include +# include +# include + +/* +$begin json_parser$$ +$spell + Json + CppAD + obj +$$ + +$section Json AD Graph Parser$$ + +$head Syntax$$ +$codei%json_parser(%json%, %graph_obj%)%$$ + +$head json$$ +The $cref json_ad_graph$$. + +$head graph_obj$$ +This is a $code cpp_graph$$ object. +The input value of the object does not matter. +Upon return it is a $cref cpp_ad_graph$$ representation of this function. + +$head Prototype$$ +$srccode%hpp% */ +namespace CppAD { namespace local { namespace graph { + void json_parser( + const std::string& json , + cpp_graph& graph_obj + ); +} } } +/* %$$ +$end +*/ + + +# endif diff --git a/build-config/cppad/include/cppad/local/graph/json_writer.hpp b/build-config/cppad/include/cppad/local/graph/json_writer.hpp new file mode 100644 index 00000000..36a4cb39 --- /dev/null +++ b/build-config/cppad/include/cppad/local/graph/json_writer.hpp @@ -0,0 +1,54 @@ +# ifndef CPPAD_LOCAL_GRAPH_JSON_WRITER_HPP +# define CPPAD_LOCAL_GRAPH_JSON_WRITER_HPP + +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 Bradley M. Bell + + CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + + This Source Code may also be made available under the following + Secondary License when the conditions for such availability set forth + in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +-------------------------------------------------------------------------- */ + +# include +# include +# include +# include + +/* +$begin json_writer$$ +$spell + Json + CppAD + obj +$$ + +$section Json AD Graph Writer$$ + +$head Syntax$$ +$codei%json_writer( %json%, %graph_obj% )%$$ + +$head json$$ +The input value of $icode json$$ does not matter, +upon return it a $cref/json/json_ad_graph/$$ representation of the AD graph. + +$head graph_obj$$ +This is a $code cpp_graph$$ object. + +$head Prototype$$ +$srccode%hpp% */ +namespace CppAD { namespace local { namespace graph { + void json_writer( + std::string& json , + const cpp_graph& graph_obj + ); +} } } +/* %$$ +$end +*/ + + +# endif diff --git a/build-config/cppad/include/cppad/local/hash_code.hpp b/build-config/cppad/include/cppad/local/hash_code.hpp new file mode 100644 index 00000000..7812dd71 --- /dev/null +++ b/build-config/cppad/include/cppad/local/hash_code.hpp @@ -0,0 +1,244 @@ +# ifndef CPPAD_LOCAL_HASH_CODE_HPP +# define CPPAD_LOCAL_HASH_CODE_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ +# include +/*! +\file local/hash_code.hpp +CppAD hashing utility. +*/ + + +namespace CppAD { namespace local { // BEGIN_CPPAD_LOCAL_NAMESPACE +/*! +General purpose hash code for an arbitrary value. + +\tparam Value +is the type of the argument being hash coded. +It should be a plain old data class; i.e., +the values included in the equality operator in the object and +not pointed to by the object. + +\param value +the value that we are generating a hash code for. +All of the fields in value should have been set before the hash code +is computed (otherwise undefined values are used). + +\return +is a hash code that is between zero and CPPAD_HASH_TABLE_SIZE - 1. + +\par Checked Assertions +\li std::numeric_limits::max() >= CPPAD_HASH_TABLE_SIZE +\li sizeof(value) is even +\li sizeof(unsigned short) == 2 +*/ +template +unsigned short local_hash_code(const Value& value) +{ CPPAD_ASSERT_UNKNOWN( + std::numeric_limits::max() + >= + CPPAD_HASH_TABLE_SIZE + ); + CPPAD_ASSERT_UNKNOWN( sizeof(unsigned short) == 2 ); + CPPAD_ASSERT_UNKNOWN( sizeof(value) % 2 == 0 ); + // + const unsigned short* v + = reinterpret_cast(& value); + // + size_t i = sizeof(value) / 2 - 1; + // + size_t sum = v[i]; + // + while(i--) + sum += v[i]; + // + unsigned short code = static_cast( + sum % CPPAD_HASH_TABLE_SIZE + ); + return code; +} + +/*! +Specialized hash code for a CppAD operator and its arguments. + +\param op +is the operator that we are computing a hash code for. +If it is not one of the following operartors, the operator is not +hash coded and zero is returned: + +\li unary operators: +AbsOp, AcosOp, AcoshOp, AsinOp, AsinhOp, AtanOp, AtanhOp, CosOp, CoshOp +ExpOp, Expm1Op, LogOp, Log1pOp, SinOp, SinhOp, SqrtOp, TanOp, TanhOp + +\li binary operators where first argument is a parameter: +AddpvOp, DivpvOp, MulpvOp, PowpvOp, SubpvOp, ZmulpvOp + +\li binary operators where second argument is a parameter: +DivvpOp, PowvpOp, SubvpOp, Zmulvp + +\li binary operators where first is an index and second is a variable: +DisOp + +\li binary operators where both arguments are variables: +AddvvOp, DivvvOp, MulvvOp, PowvvOp, SubvvOp, ZmulvvOp + +\param arg +is a vector of length NumArg(op) or 2 (which ever is smaller), +containing the corresponding argument indices for this operator. + +\param npar +is the number of parameters corresponding to this operation sequence. + +\param par +is a vector of length npar containing the parameters +for this operation sequence; i.e., +given a parameter index of i, the corresponding parameter value is + par[i]. + + +\return +is a hash code that is between zero and CPPAD_HASH_TABLE_SIZE - 1. + +\par Checked Assertions + op must be one of the operators specified above. In addition, +\li std::numeric_limits::max() >= CPPAD_HASH_TABLE_SIZE +\li sizeof(size_t) is even +\li sizeof(Base) is even +\li sizeof(unsigned short) == 2 +\li size_t(op) < size_t(NumberOp) <= CPPAD_HASH_TABLE_SIZE +\li if the j-th argument for this operation is a parameter, arg[j] < npar. +*/ + +template +unsigned short local_hash_code( + OpCode op , + const addr_t* arg , + size_t npar , + const Base* par ) +{ CPPAD_ASSERT_UNKNOWN( + std::numeric_limits::max() + >= + CPPAD_HASH_TABLE_SIZE + ); + CPPAD_ASSERT_UNKNOWN( size_t (op) < size_t(NumberOp) ); + CPPAD_ASSERT_UNKNOWN( sizeof(unsigned short) == 2 ); + CPPAD_ASSERT_UNKNOWN( sizeof(addr_t) % 2 == 0 ); + CPPAD_ASSERT_UNKNOWN( sizeof(Base) % 2 == 0 ); + unsigned short op_fac = static_cast ( + CPPAD_HASH_TABLE_SIZE / static_cast(NumberOp) + ); + CPPAD_ASSERT_UNKNOWN( op_fac > 0 ); + + // number of shorts per addr_t value + size_t short_addr_t = sizeof(addr_t) / 2; + + // initialize with value that separates operators as much as possible + unsigned short code = static_cast( + static_cast(op) * op_fac + ); + + // now code in the operands + size_t i; + const unsigned short* v; + + // first argument + switch(op) + { // Binary operators where first arugment is a parameter. + // Code parameters by value instead of + // by index for two reasons. One, it gives better separation. + // Two, different indices can be same parameter value. + case AddpvOp: + case DivpvOp: + case MulpvOp: + case PowpvOp: + case SubpvOp: + case ZmulpvOp: + CPPAD_ASSERT_UNKNOWN( NumArg(op) == 2 ); + code += hash_code( par[arg[0]] ); + // + v = reinterpret_cast(arg + 1); + i = short_addr_t; + while(i--) + code += v[i]; + break; + + // Binary operator where first argument is an index and + // second is a variable (same as both variables). + case DisOp: + + // Binary operators where both arguments are variables + case AddvvOp: + case DivvvOp: + case MulvvOp: + case PowvvOp: + case SubvvOp: + case ZmulvvOp: + CPPAD_ASSERT_UNKNOWN( NumArg(op) == 2 ); + v = reinterpret_cast(arg + 0); + i = 2 * short_addr_t; + while(i--) + code += v[i]; + break; + + // Binary operators where second arugment is a parameter. + case DivvpOp: + case PowvpOp: + case SubvpOp: + case ZmulvpOp: + CPPAD_ASSERT_UNKNOWN( NumArg(op) == 2 ); + v = reinterpret_cast(arg + 0); + i = short_addr_t; + while(i--) + code += v[i]; + code += hash_code( par[arg[1]] ); + break; + + // Unary operators + case AbsOp: + case AcosOp: + case AcoshOp: + case AsinOp: + case AsinhOp: + case AtanOp: + case AtanhOp: + case CosOp: + case CoshOp: + case ErfOp: + case ErfcOp: + case ExpOp: + case Expm1Op: + case LogOp: + case Log1pOp: + case SignOp: + case SinOp: + case SinhOp: + case SqrtOp: + case TanOp: + case TanhOp: + CPPAD_ASSERT_UNKNOWN( NumArg(op) == 1 || op == ErfOp ); + v = reinterpret_cast(arg + 0); + i = short_addr_t; + while(i--) + code += v[i]; + break; + + // should have been one of he cases above + default: + CPPAD_ASSERT_UNKNOWN(false); + } + + return code % CPPAD_HASH_TABLE_SIZE; +} + +} } // END_CPPAD_LOCAL_NAMESPACE + +# endif diff --git a/build-config/cppad/include/cppad/local/independent.hpp b/build-config/cppad/include/cppad/local/independent.hpp new file mode 100644 index 00000000..b3bd82c8 --- /dev/null +++ b/build-config/cppad/include/cppad/local/independent.hpp @@ -0,0 +1,119 @@ +# ifndef CPPAD_LOCAL_INDEPENDENT_HPP +# define CPPAD_LOCAL_INDEPENDENT_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-18 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ +namespace CppAD { namespace local { // BEGIN_CPPAD_LOCAL_NAMESPACE +/* +\file local/independent.hpp +Start recording AD operations. +*/ + +/*! +Start recording AD operations: Implementation in local namespace. + +\tparam ADVector +This is simple vector type with elements of type AD. + +\param x +Vector of the independent variables. + +\param abort_op_index +operator index at which execution will be aborted (during the recording + +\param record_compare +should comparison operators be recorded. +of operations). The value zero corresponds to not aborting (will not match). + +\param dynamic +Vector of dynamic parameters. +*/ +template +template +void ADTape::Independent( + ADVector& x , + size_t abort_op_index , + bool record_compare , + ADVector& dynamic +) { + // check ADVector is Simple Vector class with AD elements + CheckSimpleVector< AD, ADVector>(); + + // dimension of the domain space + size_t n = x.size(); + CPPAD_ASSERT_KNOWN( + n > 0, + "Indepdendent: the argument vector x has zero size" + ); + CPPAD_ASSERT_UNKNOWN( Rec_.num_var_rec() == 0 ); + CPPAD_ASSERT_UNKNOWN( Rec_.get_abort_op_index() == 0 ); + CPPAD_ASSERT_UNKNOWN( Rec_.get_record_compare() == true ); + CPPAD_ASSERT_UNKNOWN( Rec_.get_num_dynamic_ind() == 0 ); + + // set record_compare and abort_op_index before doing anything else + Rec_.set_record_compare(record_compare); + Rec_.set_abort_op_index(abort_op_index); + Rec_.set_num_dynamic_ind( dynamic.size() ); + + // mark the beginning of the tape and skip the first variable index + // (zero) because parameters use taddr zero + CPPAD_ASSERT_NARG_NRES(BeginOp, 1, 1); + Rec_.PutOp(BeginOp); + Rec_.PutArg(0); + + // place each of the independent variables in the tape + CPPAD_ASSERT_NARG_NRES(InvOp, 0, 1); + for(size_t j = 0; j < n; j++) + { // tape address for this independent variable + CPPAD_ASSERT_UNKNOWN( ! Variable(x[j] ) ); + x[j].taddr_ = Rec_.PutOp(InvOp); + x[j].tape_id_ = id_; + x[j].ad_type_ = variable_enum; + CPPAD_ASSERT_UNKNOWN( size_t(x[j].taddr_) == j+1 ); + CPPAD_ASSERT_UNKNOWN( Variable(x[j] ) ); + } + + // done specifying all of the independent variables + size_independent_ = n; + + // parameter index zero is used by dynamic parameter tape + // to indicate that an argument is a variable + Base nan = CppAD::numeric_limits::quiet_NaN(); +# ifndef NDEBUG + CPPAD_ASSERT_UNKNOWN( Rec_.put_con_par(nan) == 0 ); +# else + Rec_.put_con_par(nan); +# endif + + // Place independent dynamic parameters at beginning of parameter vector, + // just after the nan at index zero. + for(size_t j = 0; j < Rec_.get_num_dynamic_ind(); ++j) + { CPPAD_ASSERT_UNKNOWN( ! Dynamic( dynamic[j] ) ); + CPPAD_ASSERT_UNKNOWN( Parameter( dynamic[j] ) ); + // + // dynamic parameters are placed at the end, so i == j +# ifndef NDEBUG + addr_t i = Rec_.put_dyn_par(dynamic[j].value_ , ind_dyn); + CPPAD_ASSERT_UNKNOWN( size_t(i) == j+1 ); +# else + Rec_.put_dyn_par(dynamic[j].value_ , ind_dyn); +# endif + // + // make this parameter dynamic + dynamic[j].taddr_ = static_cast(j+1); + dynamic[j].tape_id_ = id_; + dynamic[j].ad_type_ = dynamic_enum; + CPPAD_ASSERT_UNKNOWN( Dynamic( dynamic[j] ) ); + } +} +} } // END_CPPAD_LOCAL_NAMESPACE + +# endif diff --git a/build-config/cppad/include/cppad/local/is_pod.hpp b/build-config/cppad/include/cppad/local/is_pod.hpp new file mode 100644 index 00000000..68dbc2de --- /dev/null +++ b/build-config/cppad/include/cppad/local/is_pod.hpp @@ -0,0 +1,79 @@ +# ifndef CPPAD_LOCAL_IS_POD_HPP +# define CPPAD_LOCAL_IS_POD_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ +/* +$begin is_pod$$ +$spell + nullptr + CppAD + namespace + bool + inline +$$ + +$section The is_pod Template Function$$ + +$head Default Definition$$ +The default template definition is that +$codei% + is_pod<%Type%>() +%$$ +is false for all types. + +$head Fundamental Types$$ +This file specializes $codei%is_pod<%Type%>%$$ to be true where $icode Type$$ +is any of the c++11 fundamental types that hold data; i.e., +$code void$$ and $code nullptr_t$$ are excluded. + +$head Other Type$$ +You can inform CppAD that a particular $icode Type$$ is plain old data by +defining +$codei% + namespace CppAD { namespace local { + template <> inline bool is_pod<%Type%>(void) { return true; } + } } +%$$ +$end +*/ +namespace CppAD { namespace local { // BEGIN_CPPAD_LOCAL_NAMESPACE + // + template inline bool is_pod(void) { return false; } + // bool + template <> inline bool is_pod(void) {return true;} + // short + template <> inline bool is_pod(void) {return true;} + template <> inline bool is_pod(void) {return true;} + // int + template <> inline bool is_pod(void) {return true;} + template <> inline bool is_pod(void) {return true;} + // long + template <> inline bool is_pod(void) {return true;} + template <> inline bool is_pod(void) {return true;} + // long long + template <> inline bool is_pod(void) {return true;} + template <> inline bool is_pod(void) {return true;} + // Character types + template <> inline bool is_pod(void) {return true;} + template <> inline bool is_pod(void) {return true;} + template <> inline bool is_pod(void) {return true;} + template <> inline bool is_pod(void) {return true;} + template <> inline bool is_pod(void) {return true;} + template <> inline bool is_pod(void) {return true;} + // floating point types + template <> inline bool is_pod(void) {return true;} + template <> inline bool is_pod(void) {return true;} + template <> inline bool is_pod(void) {return true;} + +} } // END_CPPAD_LOCAL_NAMESPACE + +# endif diff --git a/build-config/cppad/include/cppad/local/is_pod.hpp.in b/build-config/cppad/include/cppad/local/is_pod.hpp.in new file mode 100644 index 00000000..ea11fa84 --- /dev/null +++ b/build-config/cppad/include/cppad/local/is_pod.hpp.in @@ -0,0 +1,41 @@ +# ifndef CPPAD_LOCAL_IS_POD_HPP +# define CPPAD_LOCAL_IS_POD_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ +// make sure size_t is defined because autotools version of +// is_pod_specialize_98 uses it +# include + +/*! +\file is_pod.hpp +File that defines is_pod(void) +*/ +namespace CppAD { namespace local { // BEGIN_CPPAD_LOCAL_NAMESPACE +/*! +Is this type plain old data; i.e., its constructor need not be called. + +The default definition is false. This include file defines it as true +for all the fundamental types except for void and nullptr_t. +*/ +template bool is_pod(void) { return false; } +// The following command suppresses doxygen processing for the code below +/// \cond +// C++98 Fundamental types +@is_pod_specialize_98@ + +// C++11 Fundamental types +@is_pod_specialize_11@ + +/// \endcond +} } // END_CPPAD_LOCAL_NAMESPACE + +# endif diff --git a/build-config/cppad/include/cppad/local/load_op.hpp b/build-config/cppad/include/cppad/local/load_op.hpp new file mode 100644 index 00000000..b70dd411 --- /dev/null +++ b/build-config/cppad/include/cppad/local/load_op.hpp @@ -0,0 +1,697 @@ +# ifndef CPPAD_LOCAL_LOAD_OP_HPP +# define CPPAD_LOCAL_LOAD_OP_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + + +namespace CppAD { namespace local { // BEGIN_CPPAD_LOCAL_NAMESPACE +/* + ------------------------------------------------------------------------------ +$begin load_op_var$$ +$spell + pv + Vec + op + var + isvar + ind + Taylor + arg + num + Addr + vecad +$$ +$section Accessing an Element in a Variable VecAD Vector$$ + +$head See Also$$ +$cref/op_code_var load/op_code_var/Load/$$. + +$head Syntax$$ +$codei%forward_load_%I%_op_0( + %play%, + %i_z%, + %arg%, + %parameter%, + %cap_order%, + %taylor%, + %vec_ad2isvar%, + %vec_ad2index%, + %load_op2var% +) +%$$ +where the index type $icode I$$ is $code p$$ (for parameter) +or $code v$$ (for variable). + +$head Prototype$$ +$srcthisfile% + 0%// BEGIN_FORWARD_LOAD_P_OP_0%// END_FORWARD_LOAD_P_OP_0%1 +%$$ +The prototype for $code forward_load_v_op_0$$ is the same +except for the function name. + +$head Notation$$ + +$subhead v$$ +We use $icode v$$ to denote the $cref VecAD$$ vector for this operation. + +$subhead x$$ +We use $icode x$$ to denote the $codei%AD%<%Base%>%$$ +index for this operation. + +$subhead i_vec$$ +We use $icode i_vec$$ to denote the $code size_t$$ value +corresponding to $icode x$$. + +$subhead n_load$$ +This is the number of load instructions in this recording; i.e., +$icode%play%->num_var_load_rec()%$$. + +$subhead n_all$$ +This is the number of values in the single array that includes +all the vectors together with the size of each vector; i.e., +$icode%play%->num_var_vecad_ind_rec()%$$. + +$head Addr$$ +Is the type used for address on this tape. + +$head Base$$ +base type for the operator; i.e., this operation was recorded +using AD and computations by this routine are done using type Base. + +$head play$$ +is the tape that this operation appears in. +This is for error detection and not used when NDEBUG is defined. + +$head i_z$$ +is the AD variable index corresponding to the result of this load operation. + +$head arg$$ + +$subhead arg[0]$$ +is the offset of this VecAD vector relative to the beginning +of the $icode vec_ad2isvar$$ and $icode vec_ad2index$$ arrays. + +$subhead arg[1]$$ +If this is +$code forward_load_p_op_0$$ ($code forward_load_v_op_0$$) +$icode%arg%[%1%]%$$ is the parameter index (variable index) +corresponding to $cref/i_vec/load_op_var/Notation/i_vec/$$. + +$subhead arg[2]$$ +Is the index of this VecAD load instruction in the +$icode load_op2var$$ array. + +$head parameter$$ +This is the vector of parameters for this recording which has size +$icode%play%->num_par_rec()%$$. + +$head cap_order$$ +number of columns in the matrix containing the Taylor coefficients. + +$head taylor$$ +Is the matrix of Taylor coefficients. + +$subhead Input$$ +In the $code forward_load_v_op_0$$ case, +$codei% + size_t( %taylor%[ %arg%[1]% * %cap_order% + 0 ] ) +%$$ +is the index in this VecAD vector. + +$subhead Output$$ +$icode%taylor%[ %i_z% * %cap_order% + 0 ]%$$ +is set to the zero order Taylor coefficient for the result of this operator. + +$head vec_ad2isvar$$ +This vector has size $icode n_all$$. +If $icode%vec_ad2isvar%[ %arg%[%0%] + %i_vec% ]%$$ is false (true), +the vector element is parameter (variable). + +$subhead i_pv$$ +If this element is a parameter (variable), +$codei% + %i_pv% = %vec_ad2index%[ %arg%[%0%] + %i_vec% ] +%$$ +is the corresponding parameter (variable) index; + +$head vec_ad2index$$ +This array has size $icode n_all$$ +The value $icode%vec_ad2index%[ %arg%[0] - 1 ]%$$ +is the number of elements in the user vector containing this load. +$icode%vec_ad2index%[%i_pv%]%$$ is the variable or +parameter index for this element, + +$head load_op2var$$ +is a vector with size $icode n_load$$. +The input value of its elements does not matter. +If the result of this load is a variable, +$codei% + %load_op2var%[%arg%[2]] = %i_pv% +%$$ +Otherwise, +$codei% + %load_op2var%[%arg%[2]] = 0 +%$$ + +$end +*/ +// BEGIN_FORWARD_LOAD_P_OP_0 +template +void forward_load_p_op_0( + const local::player* play , + size_t i_z , + const Addr* arg , + const Base* parameter , + size_t cap_order , + Base* taylor , + const bool* vec_ad2isvar , + const size_t* vec_ad2index , + Addr* load_op2var ) +// END_FORWARD_LOAD_P_OP_0 +{ CPPAD_ASSERT_UNKNOWN( NumArg(LdpOp) == 3 ); + CPPAD_ASSERT_UNKNOWN( NumRes(LdpOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( 0 < arg[0] ); + CPPAD_ASSERT_UNKNOWN( size_t(arg[1]) < play->num_par_rec() ); + CPPAD_ASSERT_UNKNOWN( size_t(arg[2]) < play->num_var_load_rec() ); + CPPAD_ASSERT_UNKNOWN( + size_t( std::numeric_limits::max() ) >= i_z + ); + + addr_t i_vec = addr_t( Integer( parameter[ arg[1] ] ) ); + CPPAD_ASSERT_KNOWN( + size_t(i_vec) < vec_ad2index[ arg[0] - 1 ] , + "VecAD: dynamic parmaeter index out or range during zero order forward" + ); + CPPAD_ASSERT_UNKNOWN( size_t(arg[0] + i_vec) < play->num_var_vecad_ind_rec() ); + + size_t i_pv = vec_ad2index[ arg[0] + i_vec ]; + Base* z = taylor + i_z * cap_order; + if( vec_ad2isvar[ arg[0] + i_vec ] ) + { CPPAD_ASSERT_UNKNOWN( i_pv < i_z ); + load_op2var[ arg[2] ] = addr_t( i_pv ); + Base* v_x = taylor + i_pv * cap_order; + z[0] = v_x[0]; + } + else + { CPPAD_ASSERT_UNKNOWN( i_pv < play->num_par_rec() ); + load_op2var[ arg[2] ] = 0; + Base v_x = parameter[i_pv]; + z[0] = v_x; + } +} +template +void forward_load_v_op_0( + const local::player* play , + size_t i_z , + const Addr* arg , + const Base* parameter , + size_t cap_order , + Base* taylor , + const bool* vec_ad2isvar , + const size_t* vec_ad2index , + Addr* load_op2var ) +{ CPPAD_ASSERT_UNKNOWN( NumArg(LdvOp) == 3 ); + CPPAD_ASSERT_UNKNOWN( NumRes(LdvOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( 0 < arg[0] ); + CPPAD_ASSERT_UNKNOWN( size_t(arg[1]) < i_z ); + CPPAD_ASSERT_UNKNOWN( size_t(arg[2]) < play->num_var_load_rec() ); + CPPAD_ASSERT_UNKNOWN( + size_t( std::numeric_limits::max() ) >= i_z + ); + + addr_t i_vec = addr_t(Integer(taylor[ size_t(arg[1]) * cap_order + 0 ] )); + CPPAD_ASSERT_KNOWN( + size_t(i_vec) < vec_ad2index[ arg[0] - 1 ] , + "VecAD: variable index out or range during zero order forward" + ); + CPPAD_ASSERT_UNKNOWN( size_t(arg[0] + i_vec) < play->num_var_vecad_ind_rec() ); + + size_t i_pv = vec_ad2index[ arg[0] + i_vec ]; + Base* z = taylor + i_z * cap_order; + if( vec_ad2isvar[ arg[0] + i_vec ] ) + { CPPAD_ASSERT_UNKNOWN( i_pv < i_z ); + load_op2var[ arg[2] ] = addr_t( i_pv ); + Base* v_x = taylor + i_pv * cap_order; + z[0] = v_x[0]; + } + else + { CPPAD_ASSERT_UNKNOWN( i_pv < play->num_par_rec() ); + load_op2var[ arg[2] ] = 0; + Base v_x = parameter[i_pv]; + z[0] = v_x; + } +} +/*! +------------------------------------------------------------------------------ +Shared documentation for sparsity operations corresponding to +op = LdpOp or LdvOp (not called). + + +The C++ source code corresponding to this operation is +\verbatim + v[x] = y +\endverbatim +where v is a VecAD vector, x is an AD object, +and y is AD or Base objects. +We define the index corresponding to v[x] by +\verbatim + i_pv = vec_ad2index[ arg[0] + i_vec ] +\endverbatim +where i_vec is defined under the heading arg[1] below: + + +\tparam Vector_set +is the type used for vectors of sets. It can be either +sparse::pack_setvec or sparse::list_setvec. + +\param op +is the code corresponding to this operator; +i.e., LdpOp or LdvOp. + +\param i_z +is the AD variable index corresponding to the variable z; i.e., +the set with index i_z in var_sparsity is the sparsity pattern +corresponding to z. + +\param arg +\n + arg[0] +is the offset corresponding to this VecAD vector in the VecAD combined array. + +\param num_combined +is the total number of elements in the VecAD combinded array. + +\param combined +is the VecAD combined array. +\n +\n + combined[ arg[0] - 1 ] +is the index of the set corresponding to the vector v in vecad_sparsity. +We use the notation i_v for this value; i.e., +\verbatim + i_v = combined[ arg[0] - 1 ] +\endverbatim + +\param var_sparsity +The set with index i_z in var_sparsity is the sparsity pattern for z. +This is an output for forward mode operations, +and an input for reverse mode operations. + +\param vecad_sparsity +The set with index i_v is the sparsity pattern for the vector v. +This is an input for forward mode operations. +For reverse mode operations, +the sparsity pattern for z is added to the sparsity pattern for v. + +\par Checked Assertions +\li NumArg(op) == 3 +\li NumRes(op) == 1 +\li 0 < arg[0] +\li arg[0] < num_combined +\li i_v < vecad_sparsity.n_set() +*/ +template +void sparse_load_op( + OpCode op , + size_t i_z , + const Addr* arg , + size_t num_combined , + const size_t* combined , + Vector_set& var_sparsity , + Vector_set& vecad_sparsity ) +{ + // This routine is only for documentaiton, it should not be used + CPPAD_ASSERT_UNKNOWN( false ); +} + + + +/*! +Forward mode, except for zero order, for op = LdpOp or op = LdvOp + + + +The C++ source code corresponding to this operation is +\verbatim + v[x] = y +\endverbatim +where v is a VecAD vector, x is an AD object, +and y is AD or Base objects. +We define the index corresponding to v[x] by +\verbatim + i_pv = vec_ad2index[ arg[0] + i_vec ] +\endverbatim +where i_vec is defined under the heading arg[1] below: + + +\tparam Base +base type for the operator; i.e., this operation was recorded +using AD and computations by this routine are done using type Base. + +\param play +is the tape that this operation appears in. +This is for error detection and not used when NDEBUG is defined. + +\param op +is the code corresponding to this operator; i.e., LdpOp or LdvOp +(only used for error checking). + +\param p +is the lowest order of the Taylor coefficient that we are computing. + +\param q +is the highest order of the Taylor coefficient that we are computing. + +\param r +is the number of directions for the Taylor coefficients that we +are computing. + +\param cap_order +number of columns in the matrix containing the Taylor coefficients. + +\par tpv +We use the notation +tpv = (cap_order-1) * r + 1 +which is the number of Taylor coefficients per variable + +\param i_z +is the AD variable index corresponding to the variable z. + +\param arg +arg[2] +Is the index of this vecad load instruction in the load_op2var array. + +\param load_op2var +is a vector with size play->num_var_load_rec(). +It contains the variable index corresponding to each load instruction. +In the case where the index is zero, +the instruction corresponds to a parameter (not variable). + +\par i_var +We use the notation +\verbatim + i_var = size_t( load_op2var[ arg[2] ] ) +\endverbatim + +\param taylor +\n +Input +\n +If i_var > 0, v[x] is a variable and +for k = 1 , ... , q +taylor[ i_var * tpv + (k-1)*r+1+ell ] +is the k-th order coefficient for v[x] in the ell-th direction, +\n +\n +Output +\n +for k = p , ... , q, +taylor[ i_z * tpv + (k-1)*r+1+ell ] +is set to the k-order Taylor coefficient for z in the ell-th direction. +*/ +template +void forward_load_op( + const local::player* play, + OpCode op , + size_t p , + size_t q , + size_t r , + size_t cap_order , + size_t i_z , + const Addr* arg , + const Addr* load_op2var , + Base* taylor ) +{ + CPPAD_ASSERT_UNKNOWN( NumArg(op) == 3 ); + CPPAD_ASSERT_UNKNOWN( NumRes(op) == 1 ); + CPPAD_ASSERT_UNKNOWN( q < cap_order ); + CPPAD_ASSERT_UNKNOWN( 0 < r); + CPPAD_ASSERT_UNKNOWN( 0 < p); + CPPAD_ASSERT_UNKNOWN( p <= q ); + CPPAD_ASSERT_UNKNOWN( size_t(arg[2]) < play->num_var_load_rec() ); + + size_t i_var = size_t( load_op2var[ arg[2] ] ); + CPPAD_ASSERT_UNKNOWN( i_var < i_z ); + + size_t num_taylor_per_var = (cap_order-1) * r + 1; + Base* z = taylor + i_z * num_taylor_per_var; + if( i_var > 0 ) + { Base* v_x = taylor + i_var * num_taylor_per_var; + for(size_t ell = 0; ell < r; ell++) + { for(size_t k = p; k <= q; k++) + { size_t m = (k-1) * r + 1 + ell; + z[m] = v_x[m]; + } + } + } + else + { for(size_t ell = 0; ell < r; ell++) + { for(size_t k = p; k <= q; k++) + { size_t m = (k-1) * r + 1 + ell; + z[m] = Base(0.0); + } + } + } +} + +/*! +Reverse mode for op = LdpOp or LdvOp. + + +The C++ source code corresponding to this operation is +\verbatim + v[x] = y +\endverbatim +where v is a VecAD vector, x is an AD object, +and y is AD or Base objects. +We define the index corresponding to v[x] by +\verbatim + i_pv = vec_ad2index[ arg[0] + i_vec ] +\endverbatim +where i_vec is defined under the heading arg[1] below: + + +This routine is given the partial derivatives of a function +G(z , y[x] , w , u ... ) +and it uses them to compute the partial derivatives of +\verbatim + H( y[x] , w , u , ... ) = G[ z( y[x] ) , y[x] , w , u , ... ] +\endverbatim + +\tparam Base +base type for the operator; i.e., this operation was recorded +using AD< Base > and computations by this routine are done using type + Base. + +\param op +is the code corresponding to this operator; i.e., LdpOp or LdvOp +(only used for error checking). + +\param d +highest order the Taylor coefficient that we are computing the partial +derivative with respect to. + +\param i_z +is the AD variable index corresponding to the variable z. + +\param arg + arg[2] +Is the index of this vecad load instruction in the +load_op2var array. + +\param cap_order +number of columns in the matrix containing the Taylor coefficients +(not used). + +\param taylor +matrix of Taylor coefficients (not used). + +\param nc_partial +number of colums in the matrix containing all the partial derivatives +(not used if arg[2] is zero). + +\param partial +If arg[2] is zero, y[x] is a parameter +and no values need to be modified; i.e., partial is not used. +Otherwise, y[x] is a variable and: +\n +\n + partial [ i_z * nc_partial + k ] +for k = 0 , ... , d +is the partial derivative of G +with respect to the k-th order Taylor coefficient for z. +\n +\n +If arg[2] is not zero, + partial [ arg[2] * nc_partial + k ] +for k = 0 , ... , d +is the partial derivative with respect to +the k-th order Taylor coefficient for x. +On input, it corresponds to the function G, +and on output it corresponds to the the function H. + +\param load_op2var +is a vector with size play->num_var_load_rec(). +It contains the variable index corresponding to each load instruction. +In the case where the index is zero, +the instruction corresponds to a parameter (not variable). + +\par Checked Assertions +\li NumArg(op) == 3 +\li NumRes(op) == 1 +\li d < cap_order +\li size_t(arg[2]) < i_z +*/ +template +void reverse_load_op( + OpCode op , + size_t d , + size_t i_z , + const Addr* arg , + size_t cap_order , + const Base* taylor , + size_t nc_partial , + Base* partial , + const Addr* load_op2var ) +{ size_t i_load = size_t( load_op2var[ arg[2] ] ); + + CPPAD_ASSERT_UNKNOWN( NumArg(op) == 3 ); + CPPAD_ASSERT_UNKNOWN( NumRes(op) == 1 ); + CPPAD_ASSERT_UNKNOWN( d < cap_order ); + CPPAD_ASSERT_UNKNOWN( i_load < i_z ); + + if( i_load > 0 ) + { + Base* pz = partial + i_z * nc_partial; + Base* py_x = partial + i_load * nc_partial; + size_t j = d + 1; + while(j--) + py_x[j] += pz[j]; + } +} + + +/*! +Forward mode sparsity operations for LdpOp and LdvOp + +\param dependency +is this a dependency (or sparsity) calculation. + +\copydetails CppAD::local::sparse_load_op +*/ +template +void forward_sparse_load_op( + bool dependency , + OpCode op , + size_t i_z , + const Addr* arg , + size_t num_combined , + const size_t* combined , + Vector_set& var_sparsity , + Vector_set& vecad_sparsity ) +{ + CPPAD_ASSERT_UNKNOWN( NumArg(op) == 3 ); + CPPAD_ASSERT_UNKNOWN( NumRes(op) == 1 ); + CPPAD_ASSERT_UNKNOWN( 0 < arg[0] ); + CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) < num_combined ); + size_t i_v = combined[ arg[0] - 1 ]; + CPPAD_ASSERT_UNKNOWN( i_v < vecad_sparsity.n_set() ); + + var_sparsity.assignment(i_z, i_v, vecad_sparsity); + if( dependency & (op == LdvOp) ) + var_sparsity.binary_union(i_z, i_z, size_t(arg[1]), var_sparsity); + + return; +} + + +/*! +Reverse mode Jacobian sparsity operations for LdpOp and LdvOp + +\param dependency +is this a dependency (or sparsity) calculation. + +\copydetails CppAD::local::sparse_load_op +*/ +template +void reverse_sparse_jacobian_load_op( + bool dependency , + OpCode op , + size_t i_z , + const Addr* arg , + size_t num_combined , + const size_t* combined , + Vector_set& var_sparsity , + Vector_set& vecad_sparsity ) +{ + CPPAD_ASSERT_UNKNOWN( NumArg(op) == 3 ); + CPPAD_ASSERT_UNKNOWN( NumRes(op) == 1 ); + CPPAD_ASSERT_UNKNOWN( 0 < arg[0] ); + CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) < num_combined ); + size_t i_v = combined[ arg[0] - 1 ]; + CPPAD_ASSERT_UNKNOWN( i_v < vecad_sparsity.n_set() ); + + vecad_sparsity.binary_union(i_v, i_v, i_z, var_sparsity); + if( dependency & (op == LdvOp) ) + var_sparsity.binary_union( size_t(arg[1]), size_t(arg[1]), i_z, var_sparsity); + + return; +} + + +/*! +Reverse mode Hessian sparsity operations for LdpOp and LdvOp + +\copydetails CppAD::local::sparse_load_op + +\param var_jacobian + var_jacobian[i_z] +is false (true) if the Jacobian of G with respect to z is always zero +(many be non-zero). + +\param vecad_jacobian + vecad_jacobian[i_v] +is false (true) if the Jacobian with respect to x is always zero +(may be non-zero). +On input, it corresponds to the function G, +and on output it corresponds to the function H. + +*/ +template +void reverse_sparse_hessian_load_op( + OpCode op , + size_t i_z , + const Addr* arg , + size_t num_combined , + const size_t* combined , + Vector_set& var_sparsity , + Vector_set& vecad_sparsity , + bool* var_jacobian , + bool* vecad_jacobian ) +{ + CPPAD_ASSERT_UNKNOWN( NumArg(op) == 3 ); + CPPAD_ASSERT_UNKNOWN( NumRes(op) == 1 ); + CPPAD_ASSERT_UNKNOWN( 0 < arg[0] ); + CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) < num_combined ); + size_t i_v = combined[ arg[0] - 1 ]; + CPPAD_ASSERT_UNKNOWN( i_v < vecad_sparsity.n_set() ); + + vecad_sparsity.binary_union(i_v, i_v, i_z, var_sparsity); + + vecad_jacobian[i_v] |= var_jacobian[i_z]; + + return; +} + + +} } // END_CPPAD_LOCAL_NAMESPACE +# endif diff --git a/build-config/cppad/include/cppad/local/log1p_op.hpp b/build-config/cppad/include/cppad/local/log1p_op.hpp new file mode 100644 index 00000000..fba31a25 --- /dev/null +++ b/build-config/cppad/include/cppad/local/log1p_op.hpp @@ -0,0 +1,203 @@ +# ifndef CPPAD_LOCAL_LOG1P_OP_HPP +# define CPPAD_LOCAL_LOG1P_OP_HPP + +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +namespace CppAD { namespace local { // BEGIN_CPPAD_LOCAL_NAMESPACE +/*! +\file log1p_op.hpp +Forward and reverse mode calculations for z = log1p(x). +*/ + +/*! +Compute forward mode Taylor coefficient for result of op = Log1pOp. + +The C++ source code corresponding to this operation is +\verbatim + z = log1p(x) +\endverbatim + +\copydetails CppAD::local::forward_unary1_op +*/ +template +void forward_log1p_op( + size_t p , + size_t q , + size_t i_z , + size_t i_x , + size_t cap_order , + Base* taylor ) +{ + size_t k; + + // check assumptions + CPPAD_ASSERT_UNKNOWN( NumArg(Log1pOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( NumRes(Log1pOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( q < cap_order ); + CPPAD_ASSERT_UNKNOWN( p <= q ); + + // Taylor coefficients corresponding to argument and result + Base* x = taylor + i_x * cap_order; + Base* z = taylor + i_z * cap_order; + + if( p == 0 ) + { z[0] = log1p( x[0] ); + p++; + if( q == 0 ) + return; + } + if ( p == 1 ) + { z[1] = x[1] / (Base(1.0) + x[0]); + p++; + } + for(size_t j = p; j <= q; j++) + { + z[j] = -z[1] * x[j-1]; + for(k = 2; k < j; k++) + z[j] -= Base(double(k)) * z[k] * x[j-k]; + z[j] /= Base(double(j)); + z[j] += x[j]; + z[j] /= (Base(1.0) + x[0]); + } +} + +/*! +Muiltiple directions Taylor coefficient for op = Log1pOp. + +The C++ source code corresponding to this operation is +\verbatim + z = log1p(x) +\endverbatim + +\copydetails CppAD::local::forward_unary1_op_dir +*/ +template +void forward_log1p_op_dir( + size_t q , + size_t r , + size_t i_z , + size_t i_x , + size_t cap_order , + Base* taylor ) +{ + + // check assumptions + CPPAD_ASSERT_UNKNOWN( NumArg(Log1pOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( NumRes(Log1pOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( 0 < q ); + CPPAD_ASSERT_UNKNOWN( q < cap_order ); + + // Taylor coefficients corresponding to argument and result + size_t num_taylor_per_var = (cap_order-1) * r + 1; + Base* x = taylor + i_x * num_taylor_per_var; + Base* z = taylor + i_z * num_taylor_per_var; + + size_t m = (q-1) * r + 1; + for(size_t ell = 0; ell < r; ell++) + { z[m+ell] = Base(double(q)) * x[m+ell]; + for(size_t k = 1; k < q; k++) + z[m+ell] -= Base(double(k)) * z[(k-1)*r+1+ell] * x[(q-k-1)*r+1+ell]; + z[m+ell] /= (Base(double(q)) + Base(q) * x[0]); + } +} + +/*! +Compute zero order forward mode Taylor coefficient for result of op = Log1pOp. + +The C++ source code corresponding to this operation is +\verbatim + z = log1p(x) +\endverbatim + +\copydetails CppAD::local::forward_unary1_op_0 +*/ +template +void forward_log1p_op_0( + size_t i_z , + size_t i_x , + size_t cap_order , + Base* taylor ) +{ + + // check assumptions + CPPAD_ASSERT_UNKNOWN( NumArg(Log1pOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( NumRes(Log1pOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( 0 < cap_order ); + + // Taylor coefficients corresponding to argument and result + Base* x = taylor + i_x * cap_order; + Base* z = taylor + i_z * cap_order; + + z[0] = log1p( x[0] ); +} + +/*! +Compute reverse mode partial derivatives for result of op = Log1pOp. + +The C++ source code corresponding to this operation is +\verbatim + z = log1p(x) +\endverbatim + +\copydetails CppAD::local::reverse_unary1_op +*/ + +template +void reverse_log1p_op( + size_t d , + size_t i_z , + size_t i_x , + size_t cap_order , + const Base* taylor , + size_t nc_partial , + Base* partial ) +{ size_t j, k; + + // check assumptions + CPPAD_ASSERT_UNKNOWN( NumArg(Log1pOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( NumRes(Log1pOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( d < cap_order ); + CPPAD_ASSERT_UNKNOWN( d < nc_partial ); + + // Taylor coefficients and partials corresponding to argument + const Base* x = taylor + i_x * cap_order; + Base* px = partial + i_x * nc_partial; + + // Taylor coefficients and partials corresponding to result + const Base* z = taylor + i_z * cap_order; + Base* pz = partial + i_z * nc_partial; + + Base inv_1px0 = Base(1.0) / (Base(1) + x[0]); + + j = d; + while(j) + { // scale partial w.r.t z[j] + pz[j] = azmul(pz[j] , inv_1px0); + + px[0] -= azmul(pz[j], z[j]); + px[j] += pz[j]; + + // further scale partial w.r.t. z[j] + pz[j] /= Base(double(j)); + + for(k = 1; k < j; k++) + { pz[k] -= Base(double(k)) * azmul(pz[j], x[j-k]); + px[j-k] -= Base(double(k)) * azmul(pz[j], z[k]); + } + --j; + } + px[0] += azmul(pz[0], inv_1px0); +} + +} } // END_CPPAD_LOCAL_NAMESPACE +# endif diff --git a/build-config/cppad/include/cppad/local/log_op.hpp b/build-config/cppad/include/cppad/local/log_op.hpp new file mode 100644 index 00000000..937062c5 --- /dev/null +++ b/build-config/cppad/include/cppad/local/log_op.hpp @@ -0,0 +1,202 @@ +# ifndef CPPAD_LOCAL_LOG_OP_HPP +# define CPPAD_LOCAL_LOG_OP_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-17 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +namespace CppAD { namespace local { // BEGIN_CPPAD_LOCAL_NAMESPACE +/*! +\file log_op.hpp +Forward and reverse mode calculations for z = log(x). +*/ + +/*! +Compute forward mode Taylor coefficient for result of op = LogOp. + +The C++ source code corresponding to this operation is +\verbatim + z = log(x) +\endverbatim + +\copydetails CppAD::local::forward_unary1_op +*/ +template +void forward_log_op( + size_t p , + size_t q , + size_t i_z , + size_t i_x , + size_t cap_order , + Base* taylor ) +{ + size_t k; + + // check assumptions + CPPAD_ASSERT_UNKNOWN( NumArg(LogOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( NumRes(LogOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( q < cap_order ); + CPPAD_ASSERT_UNKNOWN( p <= q ); + + // Taylor coefficients corresponding to argument and result + Base* x = taylor + i_x * cap_order; + Base* z = taylor + i_z * cap_order; + + if( p == 0 ) + { z[0] = log( x[0] ); + p++; + if( q == 0 ) + return; + } + if ( p == 1 ) + { z[1] = x[1] / x[0]; + p++; + } + for(size_t j = p; j <= q; j++) + { + z[j] = -z[1] * x[j-1]; + for(k = 2; k < j; k++) + z[j] -= Base(double(k)) * z[k] * x[j-k]; + z[j] /= Base(double(j)); + z[j] += x[j]; + z[j] /= x[0]; + } +} + +/*! +Muiltiple directions Taylor coefficient for op = LogOp. + +The C++ source code corresponding to this operation is +\verbatim + z = log(x) +\endverbatim + +\copydetails CppAD::local::forward_unary1_op_dir +*/ +template +void forward_log_op_dir( + size_t q , + size_t r , + size_t i_z , + size_t i_x , + size_t cap_order , + Base* taylor ) +{ + + // check assumptions + CPPAD_ASSERT_UNKNOWN( NumArg(LogOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( NumRes(LogOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( 0 < q ); + CPPAD_ASSERT_UNKNOWN( q < cap_order ); + + // Taylor coefficients corresponding to argument and result + size_t num_taylor_per_var = (cap_order-1) * r + 1; + Base* x = taylor + i_x * num_taylor_per_var; + Base* z = taylor + i_z * num_taylor_per_var; + + size_t m = (q-1) * r + 1; + for(size_t ell = 0; ell < r; ell++) + { z[m+ell] = Base(double(q)) * x[m+ell]; + for(size_t k = 1; k < q; k++) + z[m+ell] -= Base(double(k)) * z[(k-1)*r+1+ell] * x[(q-k-1)*r+1+ell]; + z[m+ell] /= (Base(double(q)) * x[0]); + } +} + +/*! +Compute zero order forward mode Taylor coefficient for result of op = LogOp. + +The C++ source code corresponding to this operation is +\verbatim + z = log(x) +\endverbatim + +\copydetails CppAD::local::forward_unary1_op_0 +*/ +template +void forward_log_op_0( + size_t i_z , + size_t i_x , + size_t cap_order , + Base* taylor ) +{ + + // check assumptions + CPPAD_ASSERT_UNKNOWN( NumArg(LogOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( NumRes(LogOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( 0 < cap_order ); + + // Taylor coefficients corresponding to argument and result + Base* x = taylor + i_x * cap_order; + Base* z = taylor + i_z * cap_order; + + z[0] = log( x[0] ); +} + +/*! +Compute reverse mode partial derivatives for result of op = LogOp. + +The C++ source code corresponding to this operation is +\verbatim + z = log(x) +\endverbatim + +\copydetails CppAD::local::reverse_unary1_op +*/ + +template +void reverse_log_op( + size_t d , + size_t i_z , + size_t i_x , + size_t cap_order , + const Base* taylor , + size_t nc_partial , + Base* partial ) +{ size_t j, k; + + // check assumptions + CPPAD_ASSERT_UNKNOWN( NumArg(LogOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( NumRes(LogOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( d < cap_order ); + CPPAD_ASSERT_UNKNOWN( d < nc_partial ); + + // Taylor coefficients and partials corresponding to argument + const Base* x = taylor + i_x * cap_order; + Base* px = partial + i_x * nc_partial; + + // Taylor coefficients and partials corresponding to result + const Base* z = taylor + i_z * cap_order; + Base* pz = partial + i_z * nc_partial; + + Base inv_x0 = Base(1.0) / x[0]; + + j = d; + while(j) + { // scale partial w.r.t z[j] + pz[j] = azmul(pz[j] , inv_x0); + + px[0] -= azmul(pz[j], z[j]); + px[j] += pz[j]; + + // further scale partial w.r.t. z[j] + pz[j] /= Base(double(j)); + + for(k = 1; k < j; k++) + { pz[k] -= Base(double(k)) * azmul(pz[j], x[j-k]); + px[j-k] -= Base(double(k)) * azmul(pz[j], z[k]); + } + --j; + } + px[0] += azmul(pz[0], inv_x0); +} + +} } // END_CPPAD_LOCAL_NAMESPACE +# endif diff --git a/build-config/cppad/include/cppad/local/mul_op.hpp b/build-config/cppad/include/cppad/local/mul_op.hpp new file mode 100644 index 00000000..d7fe1512 --- /dev/null +++ b/build-config/cppad/include/cppad/local/mul_op.hpp @@ -0,0 +1,359 @@ +# ifndef CPPAD_LOCAL_MUL_OP_HPP +# define CPPAD_LOCAL_MUL_OP_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-18 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +namespace CppAD { namespace local { // BEGIN_CPPAD_LOCAL_NAMESPACE +/*! +\file mul_op.hpp +Forward and reverse mode calculations for z = x * y. +*/ + +// --------------------------- Mulvv ----------------------------------------- +/*! +Compute forward mode Taylor coefficients for result of op = MulvvOp. + +The C++ source code corresponding to this operation is +\verbatim + z = x * y +\endverbatim +In the documentation below, +this operations is for the case where both x and y are variables +and the argument parameter is not used. + +\copydetails CppAD::local::forward_binary_op +*/ + +template +void forward_mulvv_op( + size_t p , + size_t q , + size_t i_z , + const addr_t* arg , + const Base* parameter , + size_t cap_order , + Base* taylor ) +{ + // check assumptions + CPPAD_ASSERT_UNKNOWN( NumArg(MulvvOp) == 2 ); + CPPAD_ASSERT_UNKNOWN( NumRes(MulvvOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( q < cap_order ); + CPPAD_ASSERT_UNKNOWN( p <= q ); + + // Taylor coefficients corresponding to arguments and result + Base* x = taylor + size_t(arg[0]) * cap_order; + Base* y = taylor + size_t(arg[1]) * cap_order; + Base* z = taylor + i_z * cap_order; + + size_t k; + for(size_t d = p; d <= q; d++) + { z[d] = Base(0.0); + for(k = 0; k <= d; k++) + z[d] += x[d-k] * y[k]; + } +} +/*! +Multiple directions forward mode Taylor coefficients for op = MulvvOp. + +The C++ source code corresponding to this operation is +\verbatim + z = x * y +\endverbatim +In the documentation below, +this operations is for the case where both x and y are variables +and the argument parameter is not used. + +\copydetails CppAD::local::forward_binary_op_dir +*/ + +template +void forward_mulvv_op_dir( + size_t q , + size_t r , + size_t i_z , + const addr_t* arg , + const Base* parameter , + size_t cap_order , + Base* taylor ) +{ + // check assumptions + CPPAD_ASSERT_UNKNOWN( NumArg(MulvvOp) == 2 ); + CPPAD_ASSERT_UNKNOWN( NumRes(MulvvOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( 0 < q ); + CPPAD_ASSERT_UNKNOWN( q < cap_order ); + + // Taylor coefficients corresponding to arguments and result + size_t num_taylor_per_var = (cap_order-1) * r + 1; + Base* x = taylor + size_t(arg[0]) * num_taylor_per_var; + Base* y = taylor + size_t(arg[1]) * num_taylor_per_var; + Base* z = taylor + i_z * num_taylor_per_var; + + size_t k, ell, m; + for(ell = 0; ell < r; ell++) + { m = (q-1)*r + ell + 1; + z[m] = x[0] * y[m] + x[m] * y[0]; + for(k = 1; k < q; k++) + z[m] += x[(q-k-1)*r + ell + 1] * y[(k-1)*r + ell + 1]; + } +} + +/*! +Compute zero order forward mode Taylor coefficients for result of op = MulvvOp. + +The C++ source code corresponding to this operation is +\verbatim + z = x * y +\endverbatim +In the documentation below, +this operations is for the case where both x and y are variables +and the argument parameter is not used. + +\copydetails CppAD::local::forward_binary_op_0 +*/ + +template +void forward_mulvv_op_0( + size_t i_z , + const addr_t* arg , + const Base* parameter , + size_t cap_order , + Base* taylor ) +{ + // check assumptions + CPPAD_ASSERT_UNKNOWN( NumArg(MulvvOp) == 2 ); + CPPAD_ASSERT_UNKNOWN( NumRes(MulvvOp) == 1 ); + + // Taylor coefficients corresponding to arguments and result + Base* x = taylor + size_t(arg[0]) * cap_order; + Base* y = taylor + size_t(arg[1]) * cap_order; + Base* z = taylor + i_z * cap_order; + + z[0] = x[0] * y[0]; +} + +/*! +Compute reverse mode partial derivatives for result of op = MulvvOp. + +The C++ source code corresponding to this operation is +\verbatim + z = x * y +\endverbatim +In the documentation below, +this operations is for the case where both x and y are variables +and the argument parameter is not used. + +\copydetails CppAD::local::reverse_binary_op +*/ + +template +void reverse_mulvv_op( + size_t d , + size_t i_z , + const addr_t* arg , + const Base* parameter , + size_t cap_order , + const Base* taylor , + size_t nc_partial , + Base* partial ) +{ + // check assumptions + CPPAD_ASSERT_UNKNOWN( NumArg(MulvvOp) == 2 ); + CPPAD_ASSERT_UNKNOWN( NumRes(MulvvOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( d < cap_order ); + CPPAD_ASSERT_UNKNOWN( d < nc_partial ); + + // Arguments + const Base* x = taylor + size_t(arg[0]) * cap_order; + const Base* y = taylor + size_t(arg[1]) * cap_order; + + // Partial derivatives corresponding to arguments and result + Base* px = partial + size_t(arg[0]) * nc_partial; + Base* py = partial + size_t(arg[1]) * nc_partial; + Base* pz = partial + i_z * nc_partial; + + + // number of indices to access + size_t j = d + 1; + size_t k; + while(j) + { --j; + for(k = 0; k <= j; k++) + { + px[j-k] += azmul(pz[j], y[k]); + py[k] += azmul(pz[j], x[j-k]); + } + } +} +// --------------------------- Mulpv ----------------------------------------- +/*! +Compute forward mode Taylor coefficients for result of op = MulpvOp. + +The C++ source code corresponding to this operation is +\verbatim + z = x * y +\endverbatim +In the documentation below, +this operations is for the case where x is a parameter and y is a variable. + +\copydetails CppAD::local::forward_binary_op +*/ + +template +void forward_mulpv_op( + size_t p , + size_t q , + size_t i_z , + const addr_t* arg , + const Base* parameter , + size_t cap_order , + Base* taylor ) +{ + // check assumptions + CPPAD_ASSERT_UNKNOWN( NumArg(MulpvOp) == 2 ); + CPPAD_ASSERT_UNKNOWN( NumRes(MulpvOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( q < cap_order ); + CPPAD_ASSERT_UNKNOWN( p <= q ); + + // Taylor coefficients corresponding to arguments and result + Base* y = taylor + size_t(arg[1]) * cap_order; + Base* z = taylor + i_z * cap_order; + + // Paraemter value + Base x = parameter[ arg[0] ]; + + for(size_t d = p; d <= q; d++) + z[d] = x * y[d]; +} +/*! +Multiple directions forward mode Taylor coefficients for op = MulpvOp. + +The C++ source code corresponding to this operation is +\verbatim + z = x * y +\endverbatim +In the documentation below, +this operations is for the case where x is a parameter and y is a variable. + +\copydetails CppAD::local::forward_binary_op_dir +*/ + +template +void forward_mulpv_op_dir( + size_t q , + size_t r , + size_t i_z , + const addr_t* arg , + const Base* parameter , + size_t cap_order , + Base* taylor ) +{ + // check assumptions + CPPAD_ASSERT_UNKNOWN( NumArg(MulpvOp) == 2 ); + CPPAD_ASSERT_UNKNOWN( NumRes(MulpvOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( 0 < q ); + CPPAD_ASSERT_UNKNOWN( q < cap_order ); + + // Taylor coefficients corresponding to arguments and result + size_t num_taylor_per_var = (cap_order-1) * r + 1; + size_t m = (q-1) * r + 1; + Base* y = taylor + size_t(arg[1]) * num_taylor_per_var + m; + Base* z = taylor + i_z * num_taylor_per_var + m; + + // Paraemter value + Base x = parameter[ arg[0] ]; + + for(size_t ell = 0; ell < r; ell++) + z[ell] = x * y[ell]; +} +/*! +Compute zero order forward mode Taylor coefficient for result of op = MulpvOp. + +The C++ source code corresponding to this operation is +\verbatim + z = x * y +\endverbatim +In the documentation below, +this operations is for the case where x is a parameter and y is a variable. + +\copydetails CppAD::local::forward_binary_op_0 +*/ + +template +void forward_mulpv_op_0( + size_t i_z , + const addr_t* arg , + const Base* parameter , + size_t cap_order , + Base* taylor ) +{ + // check assumptions + CPPAD_ASSERT_UNKNOWN( NumArg(MulpvOp) == 2 ); + CPPAD_ASSERT_UNKNOWN( NumRes(MulpvOp) == 1 ); + + // Paraemter value + Base x = parameter[ arg[0] ]; + + // Taylor coefficients corresponding to arguments and result + Base* y = taylor + size_t(arg[1]) * cap_order; + Base* z = taylor + i_z * cap_order; + + z[0] = x * y[0]; +} + +/*! +Compute reverse mode partial derivative for result of op = MulpvOp. + +The C++ source code corresponding to this operation is +\verbatim + z = x * y +\endverbatim +In the documentation below, +this operations is for the case where x is a parameter and y is a variable. + +\copydetails CppAD::local::reverse_binary_op +*/ + +template +void reverse_mulpv_op( + size_t d , + size_t i_z , + const addr_t* arg , + const Base* parameter , + size_t cap_order , + const Base* taylor , + size_t nc_partial , + Base* partial ) +{ + // check assumptions + CPPAD_ASSERT_UNKNOWN( NumArg(MulpvOp) == 2 ); + CPPAD_ASSERT_UNKNOWN( NumRes(MulpvOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( d < cap_order ); + CPPAD_ASSERT_UNKNOWN( d < nc_partial ); + + // Arguments + Base x = parameter[ arg[0] ]; + + // Partial derivatives corresponding to arguments and result + Base* py = partial + size_t(arg[1]) * nc_partial; + Base* pz = partial + i_z * nc_partial; + + // number of indices to access + size_t j = d + 1; + while(j) + { --j; + py[j] += azmul(pz[j], x); + } +} + + +} } // END_CPPAD_LOCAL_NAMESPACE +# endif diff --git a/build-config/cppad/include/cppad/local/op.hpp b/build-config/cppad/include/cppad/local/op.hpp new file mode 100644 index 00000000..fbed5728 --- /dev/null +++ b/build-config/cppad/include/cppad/local/op.hpp @@ -0,0 +1,59 @@ +# ifndef CPPAD_LOCAL_OP_HPP +# define CPPAD_LOCAL_OP_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +// used by the sparse operators +# include + +// operations +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include + + +# endif diff --git a/build-config/cppad/include/cppad/local/op_code_dyn.hpp b/build-config/cppad/include/cppad/local/op_code_dyn.hpp new file mode 100644 index 00000000..195d72ff --- /dev/null +++ b/build-config/cppad/include/cppad/local/op_code_dyn.hpp @@ -0,0 +1,439 @@ +# ifndef CPPAD_LOCAL_OP_CODE_DYN_HPP +# define CPPAD_LOCAL_OP_CODE_DYN_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +namespace CppAD { namespace local { // BEGIN_CPPAD_LOCAL_NAMESPACE +/*! +$begin op_code_dyn$$ +$spell + vec + Op + dyn + arg + hpp + cond_exp + ind + zmul + Namespace + enum + CppAD +$$ + +$section Dynamic Parameter Op Codes$$ + +$head Namespace$$ +The $code op_code_dyn$$ enum type is in the $code CppAD::local$$ namespace. + +$head AD Type$$ +All the operators below have no variable arguments, +at least one dynamic parameter argument, +and at most one constant argument; see +$cref ad_type_enum$$. +For example, all the unary operators have one dynamic parameter argument +and one dynamic parameter result. + +$head Unary$$ +The number of arguments for a unary operator is one +and it is a parameter index. +All the unary operators have one result that is a dynamic parameter. + +$head Binary$$ +The number of arguments for a binary operator is two +and they are parameter indices. +All the binary operators have one result that is a dynamic parameter. +For binary operators the first argument is the left operand +and the second is the right operand. + +$subhead zmul_dyn$$ +This binary operator has a non-standard name; see $cref azmul$$ for +its definition. + +$head ind_dyn$$ +This is an independent dynamic parameter operator. +It has no arguments and one result which is the value of the corresponding +independent dynamic parameter in the call to $cref new_dynamic$$. + +$comment ----------------------------------------------------------------- $$ +$head atom_dyn$$ +This operator is a call to an atomic function. +The number of arguments to this operator is +$icode%arg%[4+%n%+%m%]%$$; see below. + +$subhead arg[0]$$ +This is the index that identifies this atomic function; see +$code local/atomic_index.hpp$$. + +$subhead arg[1]$$ +This is the number of arguments to this atomic function. +We use the notation $icode%n% = %arg%[1]%$$ below. + +$subhead arg[2]$$ +This is the number of results for this atomic function. +We use the notation $icode%m% = %arg%[2]%$$ below. + +$subhead arg[3]$$ +This is the number of result values that are dynamic parameters +for this function call. + +$subhead arg[4+j]$$ +For $icode%j% = 0 , %...% , %n%-1%$$, +this is the parameter index for the $th j$$ argument to this atomic +function call. + +$subhead arg[4+n+i]$$ +For $icode%i% = 0 , %...% , %m%-1%$$, +this is the parameter index for the $th i$$ result to this atomic +function call. + +$subhead arg[4+n+m]$$ +This is the number of arguments to this operator; i.e., +$codei%5+%n%+%m%$$. + +$head result_dyn$$ +This is a place holder for a result of an atomic function call +that is a dynamic parameter. +It has no arguments, no results, and is only there so that the +number of dynamic parameters and the number of dynamic operators are equal. + +$comment ----------------------------------------------------------------- $$ +$head cond_exp_dyn$$ +This is a conditional expression operator and has five arguments +and one result. + +$subhead arg[0]$$ +This is the +$cref/CompareOp/base_cond_exp/CompareOp/$$ value for this operator. + +$subhead arg[1]$$ +This is the parameter index for the left operand to the comparison. + +$subhead arg[2]$$ +This is the parameter index for the right operand to the comparison. + +$subhead arg[3]$$ +This is the index of the parameter equal to the operator result if +the comparison result is true. + +$subhead arg[4]$$ +This is the index of the parameter equal to the operator result if +the comparison result is false. + +$comment ----------------------------------------------------------------- $$ +$head dis_dyn$$ +This is a call to a discrete function. +The discrete function has one argument and one result. +This operator has two arguments and one result. +It is not a binary operator because the first argument +is not the index of a parameter. + +$subhead arg[0]$$ +Is the discrete function index which depends on the $icode Base$$ +type used when this function was recorded. + +$subhead arg[1]$$ +Is the parameter index for the argument to the function. + +$comment ----------------------------------------------------------------- $$ +$head Source$$ +$srcthisfile% + 0%// BEGIN_OP_CODE_DYN%// END_OP_CODE_DYN%1 +%$$ +$end +*/ + +// BEGIN_SORT_THIS_LINE_PLUS_3 +// BEGIN_OP_CODE_DYN +enum op_code_dyn { + abs_dyn, // unary + acos_dyn, // unary + acosh_dyn, // unary + add_dyn, // binary + asin_dyn, // unary + asinh_dyn, // unary + atan_dyn, // unary + atanh_dyn, // unary + atom_dyn, // ? arguments: atomic function call + cond_exp_dyn, // 5 arguments: conditional expression + cos_dyn, // unary + cosh_dyn, // unary + dis_dyn, // 2 arguments: discrete function + div_dyn, // binary + erfc_dyn, // unary + erf_dyn, // unary + exp_dyn, // unary + expm1_dyn, // unary + fabs_dyn, // unary + ind_dyn, // 0 arguments: independent parameter + log1p_dyn, // unary + log_dyn, // unary + mul_dyn, // binary + pow_dyn, // binary + result_dyn, // 0 arguments: atomic function result + sign_dyn, // unary + sin_dyn, // unary + sinh_dyn, // unary + sqrt_dyn, // unary + sub_dyn, // binary + tan_dyn, // unary + tanh_dyn, // unary + zmul_dyn, // binary + number_dyn // number of operator codes and invalid operator value +}; +// END_OP_CODE_DYN +// END_SORT_THIS_LINE_MINUS_4 + +/* +$begin num_arg_dyn$$ +$spell + num_arg_dyn + op + enum +$$ + +$section Number of Arguments to a Dynamic Parameter Operator$$ + +$head Syntax$$ +$icode%n_arg% = local::num_arg_dyn(%op%) +%$$ + +$head Prototype$$ +$srcthisfile% + 0%// BEGIN_NUM_ARG_DYN_PROTOTYPE%// END_NUM_ARG_DYN_PROTOTYPE%1 +%$$ + +$head Parallel Mode$$ +This routine has static data so its first call cannot be in Parallel mode. + +$head op$$ +is the operator in question. + +$head n_arg$$ +The return value is the number of arguments as commented in the +$cref/source/op_code_dyn/Source/$$ for $code enum op_code_dyn$$. +There is one exception: if $icode op$$ is $code atom_dyn$$, +$icode n_arg$$ is zero; see $cref/atom_dyn/op_code_dyn/atom_dyn/$$ +for the true number of arguments in this case. + +$head atom_dyn$$ +All of the dynamic parameter operators have a fixed number of arguments +except for the $cref/atom_dyn/op_code_dyn/atom_dyn/$$ +operator which calls an atomic functions. +In this special case the return value $icode n_arg$$ is zero +which is not correct. + +$end +*/ +// BEGIN_NUM_ARG_DYN_PROTOTYPE +inline size_t num_arg_dyn(op_code_dyn op) +// END_NUM_ARG_DYN_PROTOTYPE +{ CPPAD_ASSERT_FIRST_CALL_NOT_PARALLEL; + + // BEGIN_SORT_THIS_LINE_PLUS_2 + static const size_t num_arg_table[] = { + /* abs_dyn */ 1, + /* acos_dyn */ 1, + /* acosh_dyn */ 1, + /* add_dyn */ 2, + /* asin_dyn */ 1, + /* asinh_dyn */ 1, + /* atan_dyn */ 1, + /* atanh_dyn */ 1, + /* atom_dyn */ 0, + /* cond_exp_dyn */ 5, + /* cos_dyn */ 1, + /* cosh_dyn */ 1, + /* dis_dyn */ 2, + /* div_dyn */ 2, + /* erfc_dyn */ 1, + /* erf_dyn */ 1, + /* exp_dyn */ 1, + /* expm1_dyn */ 1, + /* fabs_dyn */ 1, + /* ind_dyn */ 0, + /* log1p_dyn */ 1, + /* log_dyn */ 1, + /* mul_dyn */ 2, + /* pow_dyn */ 2, + /* result_dyn */ 0, + /* sign_dyn */ 1, + /* sin_dyn */ 1, + /* sinh_dyn */ 1, + /* sqrt_dyn */ 1, + /* sub_dyn */ 2, + /* tan_dyn */ 1, + /* tanh_dyn */ 1, + /* zmul_dyn */ 2, + 0 // number_dyn (not used) + }; + // END_SORT_THIS_LINE_MINUS_3 + // + static bool first = true; + if( first ) + { CPPAD_ASSERT_UNKNOWN( + size_t(number_dyn)+1 == sizeof(num_arg_table)/sizeof(num_arg_table[0]) + ); + first = false; + } + return num_arg_table[op]; +} + +/* +$begin op_name_dyn$$ +$spell + dyn + op + enum + cond_exp +$$ + +$section Number of Arguments to a Dynamic Parameter Operator$$ + +$head Syntax$$ +$icode%name% = local::op_name_dyn(%op%) +%$$ + +$head Prototype$$ +$srcthisfile% + 0%// BEGIN_OP_NAME_DYN_PROTOTYPE%// END_OP_NAME_DYN_PROTOTYPE%1 +%$$ + +$head Parallel Mode$$ +This routine has static data so its first call cannot be in Parallel mode. + +$head op$$ +is the operator in question. + +$head name$$ +The return value $icode name$$ is the same as the operator enum symbol +(see $cref/source/op_code_dyn/Source/$$ for $code enum op_code_dyn$$) +without the $code _dyn$$ at the end. For example, +the name corresponding to the +$cref/cond_exp_dyn/op_code_dyn/cond_exp_dyn/$$ operator is $code cond_exp$$. + +$end +*/ +// BEGIN_OP_NAME_DYN_PROTOTYPE +inline const char* op_name_dyn(op_code_dyn op) +// END_OP_NAME_DYN_PROTOTYPE +{ CPPAD_ASSERT_FIRST_CALL_NOT_PARALLEL; + + // BEGIN_SORT_THIS_LINE_PLUS_2 + static const char* op_name_table[] = { + /* abs_dyn */ "abs", + /* acos_dyn */ "acos", + /* acosh_dyn */ "acosh", + /* add_dyn */ "add", + /* asin_dyn */ "asin", + /* asinh_dyn */ "asinh", + /* atan_dyn */ "atan", + /* atanh_dyn */ "atanh", + /* atom_dyn */ "call", + /* cond_exp_dyn */ "cond_exp", + /* cos_dyn */ "cos", + /* cosh_dyn */ "cosh", + /* dis_dyn */ "dis", + /* div_dyn */ "div", + /* erfc_dyn */ "erfc", + /* erf_dyn */ "erf", + /* exp_dyn */ "exp", + /* expm1_dyn */ "expm1", + /* fabs_dyn */ "fabs", + /* ind_dyn */ "ind", + /* log1p_dyn */ "log1p", + /* log_dyn */ "log", + /* mul_dyn */ "mul", + /* pow_dyn */ "pow", + /* result_dyn */ "result", + /* sign_dyn */ "sign", + /* sin_dyn */ "sin", + /* sinh_dyn */ "sinh", + /* sqrt_dyn */ "sqrt", + /* sub_dyn */ "sub", + /* tan_dyn */ "tan", + /* tanh_dyn */ "tanh", + /* zmul_dyn */ "zmul", + /* number_dyn */ "number" + }; + // END_SORT_THIS_LINE_MINUS_3 + static bool first = true; + if( first ) + { CPPAD_ASSERT_UNKNOWN( + size_t(number_dyn)+1 == sizeof(op_name_table)/sizeof(op_name_table[0]) + ); + first = false; + } + return op_name_table[op]; +} + +/* +$begin num_non_par_arg_dyn$$ +$spell + arg + dyn + op + num +$$ + +$section Number Non-Parameter Arguments to a Dynamic Parameters Operator$$ + +$head Syntax$$ +$icode%num% = local::num_non_par_arg_dyn(%op%) +%$$ + +$head Prototype$$ +$srcthisfile% + 0%// BEGIN_NUM_NON_PAR_ARG_DYN%// END_NUM_NON_PAR_ARG_DYN%1 +%$$ + +$head op$$ +is the operator in question. + +$head num$$ +The return value $icode num$$ is the number of arguments, +for this operator $icode op$$, that are not parameters indices. +All of the non-parameter arguments come first +so $icode num$$ is also the offset for the +first argument that is a parameter index. + +$head atom_dyn$$ +The $cref/atom_dyn/op_code_dyn/atom_dyn/$$ case is special, +$icode num$$ is zero for this case but it is not as documented above; see +$cref/atom_dyn/op_code_dyn/atom_dyn/$$. + +$end +*/ +// BEGIN_NUM_NON_PAR_ARG_DYN +inline size_t num_non_par_arg_dyn(op_code_dyn op) +// END_NUM_NON_PAR_ARG_DYN +{ + size_t num; + switch(op) + { case atom_dyn: + num = 4; + break; + + case cond_exp_dyn: + case dis_dyn: + num = 1; + break; + + default: + num = 0; + } + // + return num; +} + +} } // END_CPPAD_LOCAL_NAMESPACE + +# endif diff --git a/build-config/cppad/include/cppad/local/op_code_var.hpp b/build-config/cppad/include/cppad/local/op_code_var.hpp new file mode 100644 index 00000000..f1115594 --- /dev/null +++ b/build-config/cppad/include/cppad/local/op_code_var.hpp @@ -0,0 +1,1512 @@ +# ifndef CPPAD_LOCAL_OP_CODE_VAR_HPP +# define CPPAD_LOCAL_OP_CODE_VAR_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ +# include +# include +# include + +# include +# include +# include +# include + +// needed before one can use CPPAD_ASSERT_FIRST_CALL_NOT_PARALLEL +# include + +namespace CppAD { namespace local { // BEGIN_CPPAD_LOCAL_NAMESPACE +/*! +$begin op_code_var$$ +$spell + ind + pos + Pri + Ldp + Ldv + Vec + Stpp + Stvp + Stpv + Stvv + initializes + Cond + Rel + Namespace + CppAD + Op + opcode + enum + arg + addr + pv + vp + vv + AAddpv + exp + Funap + Funav + Funrp + Funrv +$$ + +$head Namespace$$ +All of these definitions are in the $code CppAD::local$$ namespace. + +$section Variable Op Codes$$ + +$head opcode_t$$ +This type is used to save space when storing operator enum type in vectors. +$srccode%hpp% */ +typedef CPPAD_VEC_ENUM_TYPE opcode_t; +/* %$$ + +$head OpCode$$ +This enum type is used to distinguish different $codei%AD<%Base%>%$$ +atomic operations. +Each value in the enum type ends with the characters $code Op$$. +Ignoring the $code Op$$ at the end, +the operators appear in alphabetical order. + +$head arg[i]$$ +We use the notation $icode%arg[%i%]%$$ below +for the $th i$$ operator argument which is a position integer +represented using the type $code addr_t$$. + +$head Unary$$ +An operator commented as unary below +has one argument (arg[0]) and it is a variable index. +All of these operators have one result variable. + +$head Binary And Compare$$ +An operator commented as binary or compare below +has two arguments. +If it is a compare operator it has no result variables +(the result is true or false but not a variable). +Otherwise, it has one result variable. +These operators use the following convention for the operator ending +and the left argument (arg[0]) and right argument (arg[1]): +$table +$icode Ending$$ $pre $$ $cnext $icode Left$$ $cnext $icode Right$$ $rnext +$code pvOp$$ $cnext parameter index $cnext variable index $rnext +$code vpOp$$ $cnext variable index $cnext parameter index $rnext +$code vvOp$$ $cnext variable index $cnext variable index +$tend +For example, $code AddpvOp$$ represents the addition operator where the left +operand is a parameter and the right operand is a variable. + +$subhead Pow$$ +The binary $codei%pow(%x%, %y%)%$$ operators are +special because they have three variable results instead of one. +To be specific, they compute +$codei%log(%x%)%$$, +$codei%log(%x%) * %y%$$, +$codei%exp( log(%x%) * %y%)%$$ + +$comment ------------------------------------------------------------------ $$ +$head AFunOp$$ +This operator appears at the start and end of every atomic function call. +This operator has no results variables. + +$subhead arg[0]$$ +This is the $cref atomic_index$$ for this function. + +$subhead arg[1]$$ +This is the $cref/id/atomic_one/id/$$ information used by an +old atomic class that has been deprecated + +$subhead arg[2]$$ +is the number of arguments to this atomic function. +We use the notation $icode%n% = %arg%[2]%$$ below. + +$subhead arg[3]$$ +is the number of results for this atomic function. +We use the notation $icode%m% = %arg%[3]%$$ below. + +$subhead Arguments$$ +There are $icode n$$ operators after the first $code AFunOp$$, +one for each argument. +If the $th j$$ argument is a parameter (variable) +the corresponding operator is $code FunapOp$$ ( $code FunavOp$$ ), and +the corresponding operator argument is a parameter index (variable index). +These operators have no result variables. + +$subhead Results$$ +There are $icode m$$ operators after the last argument operator +one for each result. +If the $th i$$ result is a parameter (variable) +the corresponding operator is $code FunrpOp$$ ( $code FunrvOp$$ ). +In the parameter case, there is one argument and it is the parameter index, +and not result variables. +In the variable case, there are no arguments and one result variable. +The index for the new variable with the next possible index. + +$comment ------------------------------------------------------------------ $$ +$head BeginOp$$ +This operator marks the start of the tape. +It has one parameter index argument that is nan and corresponds +to parameter index zero. +It also has one variable result that has index zero which is used to +indicate that a value is not a variable. +for indicate an parameter. + +$comment ------------------------------------------------------------------ $$ +$head CExpOp$$ +This is a $cref/conditional expression/condexp/$$; i.e., the corresponding +source code is +$codei% + %result% = CondExp%Rel%(%left%, %right%, %if_true%, %if_false% +%$$ +This operator has one variable result. + +$subhead arg[0]$$ +This is a $cref/CompareOp/base_cond_exp/CompareOp/$$ value corresponding +to $cref/Rel/condexp/Rel/$$ above. ($icode%Rel% = Ne%$$ is not possible). + +$subhead arg[1]$$ +The first four bits of this integer are used as flags; see below. + +$subhead arg[2]$$ +If arg[1] & 1 is true (false), +this is the variable index (parameter index) corresponding to $icode left$$. + +$subhead arg[3]$$ +If arg[1] & 2 is true (false), +this is the variable index (parameter index) corresponding to $icode right$$. + +$subhead arg[4]$$ +If arg[1] & 4 is true (false), +this is the variable index (parameter index) corresponding to $icode if_true$$. + +$subhead arg[5]$$ +If arg[1] & 8 is true (false), +this is the variable index (parameter index) corresponding to $icode if_false$$. + +$comment ------------------------------------------------------------------ $$ +$head CSkipOp$$ +The conditional skip operator (used to skip operations that depend on false +branches to conditional expressions). +This operator has not result variables. + +$subhead arg[0]$$ +This is a $cref/CompareOp/base_cond_exp/CompareOp/$$ value corresponding +to this conditional skip. + +$subhead arg[1]$$ +The first two bits of this integer are used as flags; see below. + +$subhead arg[2]$$ +If arg[1] & 1 is true (false), +this is the variable index (parameter index) corresponding to $icode left$$. + +$subhead arg[3]$$ +If arg[1] & 2 is true (false), +this is the variable index (parameter index) corresponding to $icode right$$. + +$subhead arg[4]$$ +is the number of operations to skip if the comparison is true. +We use the notation $icode%n% = %arg%[4]%$$ below. + +$subhead arg[5]$$ +is the number of operations to skip if the comparison is false. +We use the notation $icode%m% = %arg%[5]%$$ below. + +$subhead arg[6+i]$$ +For $icode%i% = 0, %...%, %n%-1%$$, this is the index +of an operator that can be skipped if the comparison is true. + +$subhead arg[6+n+i]$$ +For $icode%i% = 0, %...%, %m%-1%$$, this is the index +of an operator that can be skipped if the comparison is false. + +$subhead arg[6+n+m]$$ +The is the total number operators that might be skipped; i.e., $icode%n%+%m%$$. + +$comment ------------------------------------------------------------------ $$ +$head CSumOp$$ +Is a cumulative summation operator +which has one result variable. + +$subhead arg[0]$$ +is the index of the parameter that initializes the summation. + +$subhead arg[1]$$ +argument index that flags the end of the addition variables, +we use the notation $icode%k% = %arg%[1]%$$ below. + +$subhead arg[2]$$ +argument index that flags the end of the subtraction variables, +we use the notation $icode%ell% = %arg%[2]%$$ below. + +$subhead arg[3]$$ +argument index that flags the end of the addition dynamic parameters, +we use the notation $icode%m% = %arg%[3]%$$ below. + +$subhead arg[4]$$ +argument index that flags the end of the subtraction dynamic parameters, +we use the notation $icode%n% = %arg%[4]%$$ below. + +$subhead arg[5+i]$$ +for $icode%i% = 0, %...%, %k%-6%$$, +this is the index of the $th i$$ variable to be added in the summation. + +$subhead arg[k+i]$$ +for $icode%i% = 0, %...%, %ell%-%k%-1%$$, +this is the index of the $th i$$ variable to be subtracted in the summation. + +$subhead arg[ell+i]$$ +for $icode%i% = 0, %...%, %m%-%ell%-1%$$, this is the index of the +$th i$$ dynamic parameter to be added in the summation. + +$subhead arg[m+i]$$ +for $icode%i% = 0, %...%, %n%-%m%-1%$$, this is the index of the +$th i$$ dynamic parameter to be subtracted in the summation. + +$subhead arg[n]$$ +This is equal to $icode n$$. +Note that there are $icode%n%+1%$$ arguments to this operator +and having this value at the end enable reverse model to know how far +to back up to get to the start of this operation. + +$comment ------------------------------------------------------------------ $$ +$head DisOp$$ +Call to a user defined $cref discrete$$ function. +This operator has one result variable. + +$subhead arg[0]$$ +is the index, in the order of the functions defined by the user, +for this discrete function. + +$subhead arg[1]$$ +variable index corresponding to the argument for this function call. + +$comment ------------------------------------------------------------------ $$ +$head Load$$ +The load operators create a new variable corresponding to +$icode%vec%[%ind%]%$$ where $icode vec$$ is a $cref VecAD$$ vector +and $icode ind$$ is an $codei%AD<%Base%>%$$. +For these operators either $icode vec$$ or $icode ind$$ is a variable +and there is one variable result. + +$subhead LdpOp$$ +This load is used for an index $icode ind$$ that is a parameter. + +$subhead LdvOp$$ +This load is used for an index $icode ind$$ that is a variable. + +$subhead arg[0]$$ +is the offset of this VecAD vector +relative to the beginning of the single array +that contains all VecAD elements for all the VecAD vectors. +This corresponds to the first element of this vector and not its size +(which comes just before the first element). + +$subhead arg[1]$$ +is the index in this VecAD vector for this load operation. +For the $code LdpOp$$ ($code LdvOp$$) operator this is the +parameter index (variable index) corresponding to $icode ind$$. + +$subhead arg[2]$$ +is the index of this VecAD load operation in the set of all +the load operations in this recording. +This includes both dynamic parameter and variable loads. +It is used to map load operations to corresponding +dynamic parameters and variables. + +$comment ------------------------------------------------------------------ $$ +$head Store$$ +The store operators store information corresponding to +$icode%vec%[%ind%]% = %right%$$ where $icode vec$$ is a $cref VecAD$$ vector +and $icode ind$$ is an $codei%AD<%Base%>%$$. +For these operators either $icode vec$$, $icode ind$$, or $icode right$$ +is a variable and there is no result. + +$subhead StppOp$$ +This store is used when $icode ind$$ and $icode right$$ are parameters. + +$subhead StpvOp$$ +This store is used when $icode ind$$ is a parameter +and $icode right$$ is a variable. + +$subhead StvpOp$$ +This store is used when $icode ind$$ is a variable +and $icode right$$ is a parameter. + +$subhead StvvOp$$ +This store is used when $icode index$$ and $icode right$$ are variables. + +$subhead arg[0]$$ +is the offset of this VecAD vector +relative to the beginning of the single array +that contains all VecAD elements for all the VecAD vectors. +This corresponds to the first element of this vector and not its size +(which comes just before the first element). + +$subhead arg[1]$$ +is the index in this VecAD vector for this store operation. +For the $code StppOp$$ and $code StpvOp$$ cases +this is the parameter index corresponding to $icode ind$$. +For the $code StvpOp$$ and $code StvvOp$$ cases, +this is the variable index corresponding to $icode ind$$. + +$subhead arg[2]$$ +For the $code StppOp$$ and $code StvpOp$$ cases, +this is the parameter index corresponding to $icode right$$. +For the $code StpvOp$$ and $code StvvOp$$ cases, +this is the variable index corresponding to $icode right$$. + +$comment ------------------------------------------------------------------ $$ +$head ParOp$$ +This operator has one result that is equal to a parameter +(not that all the derivatives for this result will be zero). + +$subhead arg[0]$$ +Is the index of the parameter that determines the value of the variable. + +$comment ------------------------------------------------------------------ $$ +$head PriOp$$ +This operator implements the $cref PrintFor$$ command +$codei% + PrintFor(%pos%, %before%, %value%, %after%) +%$$ + +$subhead arg[0]$$ +The first two bits of this integer are used as flags; see below. + +$subhead arg[1]$$ +If arg[1] & 1 is true (false), +this is the variable index (parameter index) corresponding to $icode pos$$. + +$subhead arg[2]$$ +is the text index corresponding to $icode before$$. + +$subhead arg[3]$$ +If arg[1] & 2 is true (false), +this is the variable index (parameter index) corresponding to $icode value$$. + +$subhead arg[4]$$ +is the text index corresponding to $icode after$$. + +$comment ------------------------------------------------------------------ $$ + +$head Source$$ +$srccode%hpp% */ +// BEGIN_SORT_THIS_LINE_PLUS_2 +enum OpCode { + AbsOp, // unary fabs + AcosOp, // unary acos + AcoshOp, // unary acosh + AddpvOp, // binary + + AddvvOp, // ... + AFunOp, // see its heading above + AsinOp, // unary asin + AsinhOp, // unary asinh + AtanOp, // unary atan + AtanhOp, // unary atanh + BeginOp, // see its heading above + CExpOp, // ... + CosOp, // unary cos + CoshOp, // unary cosh + CSkipOp, // see its heading above + CSumOp, // ... + DisOp, // ... + DivpvOp, // binary / + DivvpOp, // ... + DivvvOp, // ... + EndOp, // used to mark the end of the tape + EqppOp, // compare equal + EqpvOp, // ... + EqvvOp, // ... + ErfOp, // unary erf + ErfcOp, // unary erfc + ExpOp, // unary exp + Expm1Op, // unary expm1 + FunapOp, // see AFun heading above + FunavOp, // ... + FunrpOp, // ... + FunrvOp, // ... + InvOp, // independent variable, no argumements, one result variable + LdpOp, // see its heading above + LdvOp, // ... + LeppOp, // compare <= + LepvOp, // ... + LevpOp, // ... + LevvOp, // ... + LogOp, // unary log + Log1pOp, // unary log1p + LtppOp, // compare < + LtpvOp, // ... + LtvpOp, // ... + LtvvOp, // ... + MulpvOp, // binary * + MulvvOp, // ... + NeppOp, // compare != + NepvOp, // ... + NevvOp, // ... + ParOp, // see its heading above + PowpvOp, // see Pow heading above + PowvpOp, // ... + PowvvOp, // ... + PriOp, // see its heading above + SignOp, // unary sign + SinOp, // unary sin + SinhOp, // unary sinh + SqrtOp, // unary sqrt + StppOp, // see its heading above + StpvOp, // ... + StvpOp, // ... + StvvOp, // ... + SubpvOp, // binary - + SubvpOp, // ... + SubvvOp, // ... + TanOp, // unary tan + TanhOp, // unary tanh + ZmulpvOp, // binary azmul + ZmulvpOp, // ... + ZmulvvOp, // ... + NumberOp // number of operator codes (not an operator) +}; +// END_SORT_THIS_LINE_MINUS_3 +/* %$$ +$end +*/ +// Note that bin/check_op_code.sh assumes the pattern NumberOp occurs +// at the end of this list and only at the end of this list. + +/*! +Number of arguments for a specified operator. + +\return +Number of arguments corresponding to the specified operator. + +\param op +Operator for which we are fetching the number of arugments. + +\par NumArgTable +this table specifes the number of arguments stored for each +occurance of the operator that is the i-th value in the OpCode enum type. +For example, for the first three OpCode enum values we have +\verbatim +OpCode j NumArgTable[j] Meaning +AbsOp 0 1 index of variable we are taking absolute value of +AcosOp 1 1 index of variable we are taking acos of +AcoshOp 2 1 index of variable we are taking acosh of +\endverbatim +Note that the meaning of the arguments depends on the operator. +*/ +inline size_t NumArg( OpCode op) +{ CPPAD_ASSERT_FIRST_CALL_NOT_PARALLEL; + + // agreement with OpCode is checked by bin/check_op_code.sh + static const size_t NumArgTable[] = { + 1, // AbsOp + 1, // AcosOp + 1, // AcoshOp + 2, // AddpvOp + 2, // AddvvOp + 4, // AFunOp + 1, // AsinOp + 1, // AsinhOp + 1, // AtanOp + 1, // AtanhOp + 1, // BeginOp offset first real argument to have index 1 + 6, // CExpOp + 1, // CosOp + 1, // CoshOp + 0, // CSkipOp (actually has a variable number of arguments, not zero) + 0, // CSumOp (actually has a variable number of arguments, not zero) + 2, // DisOp + 2, // DivpvOp + 2, // DivvpOp + 2, // DivvvOp + 0, // EndOp + 2, // EqppOp + 2, // EqpvOp + 2, // EqvvOp + 3, // ErfOp + 3, // ErfcOp + 1, // ExpOp + 1, // Expm1Op + 1, // FunapOp + 1, // FunavOp + 1, // FunrpOp + 0, // FunrvOp + 0, // InvOp + 3, // LdpOp + 3, // LdvOp + 2, // LeppOp + 2, // LepvOp + 2, // LevpOp + 2, // LevvOp + 1, // LogOp + 1, // Log1pOp + 2, // LtppOp + 2, // LtpvOp + 2, // LtvpOp + 2, // LtvvOp + 2, // MulpvOp + 2, // MulvvOp + 2, // NeppOp + 2, // NepvOp + 2, // NevvOp + 1, // ParOp + 2, // PowpvOp + 2, // PowvpOp + 2, // PowvvOp + 5, // PriOp + 1, // SignOp + 1, // SinOp + 1, // SinhOp + 1, // SqrtOp + 3, // StppOp + 3, // StpvOp + 3, // StvpOp + 3, // StvvOp + 2, // SubpvOp + 2, // SubvpOp + 2, // SubvvOp + 1, // TanOp + 1, // TanhOp + 2, // ZmulpvOp + 2, // ZmulvpOp + 2, // ZmulvvOp + 0 // NumberOp not used + }; +# ifndef NDEBUG + // only do these checks once to save time + static bool first = true; + if( first ) + { first = false; + // check that NumberOp is last value in op code table + CPPAD_ASSERT_UNKNOWN( + size_t(NumberOp) + 1 == sizeof(NumArgTable)/sizeof(NumArgTable[0]) + ); + //Check that the type CPPAD_VEC_ENUM_TYPE as required by define.hpp + CPPAD_ASSERT_UNKNOWN( is_pod() ); + size_t number_op_size_t = size_t( NumberOp ); + CPPAD_ASSERT_UNKNOWN( + number_op_size_t < std::numeric_limits::max() + ); + } + // do this check every time + CPPAD_ASSERT_UNKNOWN( size_t(op) < size_t(NumberOp) ); +# endif + + return NumArgTable[op]; +} + +/*! +Number of variables resulting from the specified operation. + +\param op +Operator for which we are fecching the number of results. + +\par NumResTable +table specifes the number of varibles that result for each +occurance of the operator that is the i-th value in the OpCode enum type. +For example, for the first three OpCode enum values we have +\verbatim +OpCode j NumResTable[j] Meaning +AbsOp 0 1 variable that is the result of the absolute value +AcosOp 1 2 acos(x) and sqrt(1-x*x) are required for this op +AcoshOp 2 2 acosh(x) and sqrt(x*x-1) are required for this op +\endverbatim +*/ +inline size_t NumRes(OpCode op) +{ CPPAD_ASSERT_FIRST_CALL_NOT_PARALLEL; + + // agreement with OpCode is checked by bin/check_op_code.sh + static const size_t NumResTable[] = { + 1, // AbsOp + 2, // AcosOp + 2, // AcoshOp + 1, // AddpvOp + 1, // AddvvOp + 0, // AFunOp + 2, // AsinOp + 2, // AsinhOp + 2, // AtanOp + 2, // AtanhOp + 1, // BeginOp offsets first variable to have index one (not zero) + 1, // CExpOp + 2, // CosOp + 2, // CoshOp + 0, // CSkipOp + 1, // CSumOp + 1, // DisOp + 1, // DivpvOp + 1, // DivvpOp + 1, // DivvvOp + 0, // EndOp + 0, // EqppOp + 0, // EqpvOp + 0, // EqvvOp + 5, // ErfOp + 5, // ErfcOp + 1, // ExpOp + 1, // Expm1Op + 0, // FunapOp + 0, // FunavOp + 0, // FunrpOp + 1, // FunrvOp + 1, // InvOp + 1, // LdpOp + 1, // LdvOp + 0, // LeppOp + 0, // LepvOp + 0, // LevpOp + 0, // LevvOp + 1, // LogOp + 1, // Log1pOp + 0, // LtppOp + 0, // LtpvOp + 0, // LtvpOp + 0, // LtvvOp + 1, // MulpvOp + 1, // MulvvOp + 0, // NeppOp + 0, // NepvOp + 0, // NevvOp + 1, // ParOp + 3, // PowpvOp + 3, // PowvpOp + 3, // PowvvOp + 0, // PriOp + 1, // SignOp + 2, // SinOp + 2, // SinhOp + 1, // SqrtOp + 0, // StppOp + 0, // StpvOp + 0, // StvpOp + 0, // StvvOp + 1, // SubpvOp + 1, // SubvpOp + 1, // SubvvOp + 2, // TanOp + 2, // TanhOp + 1, // ZmulpvOp + 1, // ZmulvpOp + 1, // ZmulvvOp + 0 // NumberOp not used and avoids g++ 4.3.2 warn when pycppad builds + }; + // check ensuring conversion to size_t is as expected + CPPAD_ASSERT_UNKNOWN( size_t(NumberOp) + 1 == + sizeof(NumResTable) / sizeof(NumResTable[0]) + ); + // this test ensures that all indices are within the table + CPPAD_ASSERT_UNKNOWN( size_t(op) < size_t(NumberOp) ); + + return NumResTable[op]; +} + + +/*! +Fetch the name for a specified operation. + +\return +name of the specified operation. + +\param op +Operator for which we are fetching the name +*/ +inline const char* OpName(OpCode op) +{ // agreement with OpCode is checked by bin/check_op_code.sh + static const char *OpNameTable[] = { + "Abs" , + "Acos" , + "Acosh" , + "Addpv" , + "Addvv" , + "AFun" , + "Asin" , + "Asinh" , + "Atan" , + "Atanh" , + "Begin" , + "CExp" , + "Cos" , + "Cosh" , + "CSkip" , + "CSum" , + "Dis" , + "Divpv" , + "Divvp" , + "Divvv" , + "End" , + "Eqpp" , + "Eqpv" , + "Eqvv" , + "Erf" , + "Erfc" , + "Exp" , + "Expm1" , + "Funap" , + "Funav" , + "Funrp" , + "Funrv" , + "Inv" , + "Ldp" , + "Ldv" , + "Lepp" , + "Lepv" , + "Levp" , + "Levv" , + "Log" , + "Log1p" , + "Ltpp" , + "Ltpv" , + "Ltvp" , + "Ltvv" , + "Mulpv" , + "Mulvv" , + "Nepp" , + "Nepv" , + "Nevv" , + "Par" , + "Powpv" , + "Powvp" , + "Powvv" , + "Pri" , + "Sign" , + "Sin" , + "Sinh" , + "Sqrt" , + "Stpp" , + "Stpv" , + "Stvp" , + "Stvv" , + "Subpv" , + "Subvp" , + "Subvv" , + "Tan" , + "Tanh" , + "Zmulpv", + "Zmulvp", + "Zmulvv", + "Number" // not used + }; + // check ensuring conversion to size_t is as expected + CPPAD_ASSERT_UNKNOWN( + size_t(NumberOp) + 1 == sizeof(OpNameTable)/sizeof(OpNameTable[0]) + ); + // this test ensures that all indices are within the table + CPPAD_ASSERT_UNKNOWN( size_t(op) < size_t(NumberOp) ); + + return OpNameTable[op]; +} + +/*! +Prints a single field corresponding to an operator. + +A specified leader is printed in front of the value +and then the value is left justified in the following width character. + +\tparam Type +is the type of the value we are printing. + +\param os +is the stream that we are printing to. + +\param leader +are characters printed before the value. + +\param value +is the value being printed. + +\param width +is the number of character to print the value in. +If the value does not fit in the width, the value is replace +by width '*' characters. +*/ +template +void printOpField( + std::ostream &os , + const char * leader , + const Type &value , + size_t width ) +{ + std::ostringstream buffer; + std::string str; + + // first print the leader + os << leader; + + // print the value into an internal buffer + buffer << std::setw( int(width) ) << value; + str = buffer.str(); + + // length of the string + size_t len = str.size(); + if( len > width ) + { + for(size_t i = 0; i < width-1; i++) + os << str[i]; + os << "*"; + return; + } + + // count number of spaces at begining + size_t nspace = 0; + while(str[nspace] == ' ' && nspace < len) + nspace++; + + // left justify the string + size_t i = nspace; + while( i < len ) + os << str[i++]; + + i = width - len + nspace; + while(i--) + os << " "; +} + +/*! +Prints a single operator and its operands + +\tparam Base +Is the base type for these AD< Base > operations. + +\param os +is the output stream that the information is printed on. + +\param play +Is the entire recording for the tape that this operator is in. + +\param i_op +is the index for the operator corresponding to this operation. + +\param i_var +is the index for the variable corresponding to the result of this operation +(if NumRes(op) > 0). + +\param op +The operator code (OpCode) for this operation. + +\param arg +is the vector of argument indices for this operation +(must have NumArg(op) elements). +*/ +template +void printOp( + std::ostream& os , + const local::player* play, + size_t i_op , + size_t i_var , + OpCode op , + const addr_t* arg ) +{ + CPPAD_ASSERT_KNOWN( + ! thread_alloc::in_parallel() , + "cannot print trace of AD operations in parallel mode" + ); + static const char *CompareOpName[] = + { "Lt", "Le", "Eq", "Ge", "Gt", "Ne" }; + + // print operator + printOpField(os, "o=", i_op, 5); + if( NumRes(op) > 0 && op != BeginOp ) + printOpField(os, "v=", i_var, 5); + else + printOpField(os, "v=", "", 5); + if( op == CExpOp || op == CSkipOp ) + { printOpField(os, "", OpName(op), 5); + printOpField(os, "", CompareOpName[ arg[0] ], 3); + } + else + printOpField(os, "", OpName(op), 8); + + // print other fields + size_t ncol = 5; + switch( op ) + { + case CSkipOp: + /* + arg[0] = the Rel operator: Lt, Le, Eq, Ge, Gt, or Ne + arg[1] & 1 = is left a variable + arg[1] & 2 = is right a variable + arg[2] = index correspoding to left + arg[3] = index correspoding to right + arg[4] = number of operations to skip if CExpOp comparison is true + arg[5] = number of operations to skip if CExpOp comparison is false + arg[6] -> arg[5+arg[4]] = skip operations if true + arg[6+arg[4]] -> arg[5+arg[4]+arg[5]] = skip operations if false + arg[6+arg[4]+arg[5]] = arg[4] + arg[5] + */ + CPPAD_ASSERT_UNKNOWN( arg[6+arg[4]+arg[5]] == arg[4]+arg[5] ); + CPPAD_ASSERT_UNKNOWN(arg[1] != 0); + if( arg[1] & 1 ) + printOpField(os, " vl=", arg[2], ncol); + else + printOpField(os, " pl=", play->GetPar(arg[2]), ncol); + if( arg[1] & 2 ) + printOpField(os, " vr=", arg[3], ncol); + else + printOpField(os, " pr=", play->GetPar(arg[3]), ncol); + if( size_t(arg[4]) < 3 ) + { for(addr_t i = 0; i < arg[4]; i++) + printOpField(os, " ot=", arg[6+i], ncol); + } + else + { printOpField(os, "\n\tot=", arg[6+0], ncol); + for(addr_t i = 1; i < arg[4]; i++) + printOpField(os, " ot=", arg[6+i], ncol); + } + if( size_t(arg[5]) < 3 ) + { for(addr_t i = 0; i < arg[5]; i++) + printOpField(os, " of=", arg[6+arg[4]+i], ncol); + } + else + { printOpField(os, "\n\tof=", arg[6+arg[4]+0], ncol); + { for(addr_t i = 1; i < arg[5]; i++) + printOpField(os, " of=", arg[6+arg[4]+i], ncol); + } + } + break; + + case CSumOp: + /* + arg[0] = index of parameter that initializes summation + arg[1] = end in arg of addition variables in summation + arg[2] = end in arg of subtraction variables in summation + arg[3] = end in arg of addition dynamic parameters in summation + arg[4] = end in arg of subtraction dynamic parameters in summation + arg[5], ... , arg[arg[1]-1]: indices for addition variables + arg[arg[1]], ... , arg[arg[2]-1]: indices for subtraction variables + arg[arg[2]], ... , arg[arg[3]-1]: indices for additon dynamics + arg[arg[3]], ... , arg[arg[4]-1]: indices for subtraction dynamics + arg[arg[4]] = arg[4] + */ + CPPAD_ASSERT_UNKNOWN( arg[arg[4]] == arg[4] ); + printOpField(os, " pr=", play->GetPar(arg[0]), ncol); + for(addr_t i = 5; i < arg[1]; i++) + printOpField(os, " +v=", arg[i], ncol); + for(addr_t i = arg[1]; i < arg[2]; i++) + printOpField(os, " -v=", arg[i], ncol); + for(addr_t i = arg[2]; i < arg[3]; i++) + printOpField(os, " +d=", play->GetPar(arg[i]), ncol); + for(addr_t i = arg[3]; i < arg[4]; i++) + printOpField(os, " -d=", play->GetPar(arg[i]), ncol); + break; + + case LdpOp: + CPPAD_ASSERT_UNKNOWN( NumArg(op) == 3 ); + printOpField(os, "off=", arg[0], ncol); + printOpField(os, " p=", play->GetPar(arg[1]), ncol); + break; + + case LdvOp: + CPPAD_ASSERT_UNKNOWN( NumArg(op) == 3 ); + printOpField(os, "off=", arg[0], ncol); + printOpField(os, " v=", arg[1], ncol); + break; + + case StppOp: + CPPAD_ASSERT_UNKNOWN( NumArg(op) == 3 ); + printOpField(os, "off=", arg[0], ncol); + printOpField(os, " pl=", play->GetPar(arg[1]), ncol); + printOpField(os, " pr=", play->GetPar(arg[2]), ncol); + break; + + case StpvOp: + CPPAD_ASSERT_UNKNOWN( NumArg(op) == 3 ); + printOpField(os, "off=", arg[0], ncol); + printOpField(os, " p=", play->GetPar(arg[1]), ncol); + printOpField(os, " v=", arg[2], ncol); + break; + + case StvpOp: + CPPAD_ASSERT_UNKNOWN( NumArg(op) == 3 ); + printOpField(os, "off=", arg[0], ncol); + printOpField(os, " v=", arg[1], ncol); + printOpField(os, " p=", play->GetPar(arg[2]), ncol); + break; + + case StvvOp: + CPPAD_ASSERT_UNKNOWN( NumArg(op) == 3 ); + printOpField(os, "off=", arg[0], ncol); + printOpField(os, " vl=", arg[1], ncol); + printOpField(os, " vr=", arg[2], ncol); + break; + + case AddvvOp: + case DivvvOp: + case EqvvOp: + case LevvOp: + case LtvvOp: + case NevvOp: + case MulvvOp: + case PowvvOp: + case SubvvOp: + case ZmulvvOp: + CPPAD_ASSERT_UNKNOWN( NumArg(op) == 2 ); + printOpField(os, " vl=", arg[0], ncol); + printOpField(os, " vr=", arg[1], ncol); + break; + + case AddpvOp: + case EqpvOp: + case DivpvOp: + case LepvOp: + case LtpvOp: + case NepvOp: + case SubpvOp: + case MulpvOp: + case PowpvOp: + case ZmulpvOp: + CPPAD_ASSERT_UNKNOWN( NumArg(op) == 2 ); + printOpField(os, " pl=", play->GetPar(arg[0]), ncol); + printOpField(os, " vr=", arg[1], ncol); + break; + + case DivvpOp: + case LevpOp: + case LtvpOp: + case PowvpOp: + case SubvpOp: + case ZmulvpOp: + CPPAD_ASSERT_UNKNOWN( NumArg(op) == 2 ); + printOpField(os, " vl=", arg[0], ncol); + printOpField(os, " pr=", play->GetPar(arg[1]), ncol); + break; + + case AbsOp: + case AcosOp: + case AcoshOp: + case AsinOp: + case AsinhOp: + case AtanOp: + case AtanhOp: + case CosOp: + case CoshOp: + case ExpOp: + case Expm1Op: + case LogOp: + case Log1pOp: + case SignOp: + case SinOp: + case SinhOp: + case SqrtOp: + case FunavOp: + case TanOp: + case TanhOp: + CPPAD_ASSERT_UNKNOWN( NumArg(op) == 1 ); + printOpField(os, " v=", arg[0], ncol); + break; + + case ErfOp: + case ErfcOp: + CPPAD_ASSERT_UNKNOWN( NumArg(op) == 3 ); + // arg[1] points to the parameter 0 + // arg[2] points to the parameter 2 / sqrt(pi) + printOpField(os, " v=", arg[0], ncol); + break; + + case ParOp: + case FunapOp: + case FunrpOp: + CPPAD_ASSERT_UNKNOWN( NumArg(op) == 1 ); + printOpField(os, " p=", play->GetPar(arg[0]), ncol); + break; + + case AFunOp: + CPPAD_ASSERT_UNKNOWN( NumArg(op) == 4 ); + { + // get the name of this atomic function + bool set_null = false; + size_t atom_index = size_t( arg[0] ); + size_t type = 0; // set to avoid warning + std::string name; + void* v_ptr = nullptr; // set to avoid warning + atomic_index(set_null, atom_index, type, &name, v_ptr); + printOpField(os, " f=", name.c_str(), ncol); + printOpField(os, " i=", arg[1], ncol); + printOpField(os, " n=", arg[2], ncol); + printOpField(os, " m=", arg[3], ncol); + } + break; + + case PriOp: + CPPAD_ASSERT_NARG_NRES(op, 5, 0); + if( arg[0] & 1 ) + printOpField(os, " v=", arg[1], ncol); + else + printOpField(os, " p=", play->GetPar(arg[1]), ncol); + os << "before=\"" << play->GetTxt(arg[2]) << "\""; + if( arg[0] & 2 ) + printOpField(os, " v=", arg[3], ncol); + else + printOpField(os, " p=", play->GetPar(arg[3]), ncol); + os << "after=\"" << play->GetTxt(arg[4]) << "\""; + break; + + case BeginOp: + // argument not used (created by independent) + CPPAD_ASSERT_UNKNOWN( NumArg(op) == 1 ); + break; + + case EndOp: + case InvOp: + case FunrvOp: + CPPAD_ASSERT_UNKNOWN( NumArg(op) == 0 ); + break; + + case DisOp: + CPPAD_ASSERT_UNKNOWN( NumArg(op) == 2 ); + { const char* name = discrete::name(arg[0]); + printOpField(os, " f=", name, ncol); + printOpField(os, " x=", arg[1], ncol); + } + break; + + + case CExpOp: + CPPAD_ASSERT_UNKNOWN(arg[1] != 0); + CPPAD_ASSERT_UNKNOWN( NumArg(op) == 6 ); + if( arg[1] & 1 ) + printOpField(os, " vl=", arg[2], ncol); + else + printOpField(os, " pl=", play->GetPar(arg[2]), ncol); + if( arg[1] & 2 ) + printOpField(os, " vr=", arg[3], ncol); + else + printOpField(os, " pr=", play->GetPar(arg[3]), ncol); + if( arg[1] & 4 ) + printOpField(os, " vt=", arg[4], ncol); + else + printOpField(os, " pt=", play->GetPar(arg[4]), ncol); + if( arg[1] & 8 ) + printOpField(os, " vf=", arg[5], ncol); + else + printOpField(os, " pf=", play->GetPar(arg[5]), ncol); + break; + + case EqppOp: + case LeppOp: + case LtppOp: + case NeppOp: + CPPAD_ASSERT_UNKNOWN( NumArg(op) == 2 ); + printOpField(os, " pl=", play->GetPar(arg[0]), ncol); + printOpField(os, " pr=", play->GetPar(arg[1]), ncol); + break; + + default: + CPPAD_ASSERT_UNKNOWN(0); + } +} + +/*! +Prints the result values correspnding to an operator. + +\tparam Base +Is the base type for these AD< Base > operations. + +\tparam Value +Determines the type of the values that we are printing. + +\param os +is the output stream that the information is printed on. + +\param nfz +is the number of forward sweep calculated values of type Value +that correspond to this operation +(ignored if NumRes(op) == 0). + +\param fz +points to the first forward calculated value +that correspond to this operation +(ignored if NumRes(op) == 0). + +\param nrz +is the number of reverse sweep calculated values of type Value +that correspond to this operation +(ignored if NumRes(op) == 0). + +\param rz +points to the first reverse calculated value +that correspond to this operation +(ignored if NumRes(op) == 0). +*/ +template +void printOpResult( + std::ostream &os , + size_t nfz , + const Value *fz , + size_t nrz , + const Value *rz ) +{ + size_t k; + for(k = 0; k < nfz; k++) + os << "| fz[" << k << "]=" << fz[k]; + for(k = 0; k < nrz; k++) + os << "| rz[" << k << "]=" << rz[k]; +} + +/*! +Determines which arguments are variaibles for an operator. + +\param op +is the operator. Note that CSkipOp and CSumOp are special cases +because the true number of arguments is not equal to NumArg(op) +and the true number of arguments num_arg can be large. +It may be more efficient to handle these cases separately +(see below). + +\param arg +is the argument vector for this operator. + +\param is_variable +If the input value of the elements in this vector do not matter. +Upon return, resize has been used to set its size to the true number +of arguments to this operator. +If op != CSkipOp and op != CSumOp, is_variable.size() = NumArg(op). +The j-th argument for this operator is a +variable index if and only if is_variable[j] is true. Note that the variable +index 0, for the BeginOp, does not correspond to a real variable and false +is returned for this case. + +\par CSkipOp +In the case of CSkipOp, +\code + is_variable.size() = 7 + arg[4] + arg[5]; + is_variable[2] = (arg[1] & 1) != 0; + is_variable[3] = (arg[1] & 2) != 0; +\endcode +and all the other is_variable[j] values are false. + +\par CSumOp +In the case of CSumOp, +\code + is_variable.size() = arg[4] + for(size_t j = 5; j < arg[2]; ++j) + is_variable[j] = true; +\endcode +and all the other is_variable values are false. +*/ +template +void arg_is_variable( + OpCode op , + const Addr* arg , + pod_vector& is_variable ) +{ size_t num_arg = NumArg(op); + is_variable.resize( num_arg ); + // + switch(op) + { + // ------------------------------------------------------------------- + // cases where true number of arugments = NumArg(op) == 0 + + case EndOp: + case InvOp: + case FunrvOp: + CPPAD_ASSERT_UNKNOWN( NumArg(op) == 0 ); + break; + + // ------------------------------------------------------------------- + // cases where NumArg(op) == 1 + case AbsOp: + case AcoshOp: + case AcosOp: + case AsinhOp: + case AsinOp: + case AtanhOp: + case AtanOp: + case CoshOp: + case CosOp: + case Expm1Op: + case ExpOp: + case Log1pOp: + case LogOp: + case SignOp: + case SinhOp: + case SinOp: + case SqrtOp: + case TanhOp: + case TanOp: + case FunavOp: + CPPAD_ASSERT_UNKNOWN( NumArg(op) == 1 ); + is_variable[0] = true; + break; + + case BeginOp: + case ParOp: + case FunapOp: + case FunrpOp: + CPPAD_ASSERT_UNKNOWN( NumArg(op) == 1 ); + is_variable[0] = false; + break; + + + // ------------------------------------------------------------------- + // cases where NumArg(op) == 2 + + case AddpvOp: + case DisOp: + case DivpvOp: + case EqpvOp: + case LepvOp: + case LtpvOp: + case MulpvOp: + case NepvOp: + case PowpvOp: + case SubpvOp: + case ZmulpvOp: + CPPAD_ASSERT_UNKNOWN( NumArg(op) == 2 ); + is_variable[0] = false; + is_variable[1] = true; + break; + + case DivvpOp: + case LevpOp: + case LtvpOp: + case PowvpOp: + case SubvpOp: + case ZmulvpOp: + CPPAD_ASSERT_UNKNOWN( NumArg(op) == 2 ); + is_variable[0] = true; + is_variable[1] = false; + break; + + case AddvvOp: + case DivvvOp: + case EqvvOp: + case LevvOp: + case LtvvOp: + case MulvvOp: + case NevvOp: + case PowvvOp: + case SubvvOp: + case ZmulvvOp: + CPPAD_ASSERT_UNKNOWN( NumArg(op) == 2 ); + is_variable[0] = true; + is_variable[1] = true; + break; + + case ErfOp: + case ErfcOp: + CPPAD_ASSERT_UNKNOWN( NumArg(op) == 3 ); + is_variable[0] = true; + is_variable[1] = false; // parameter index corresponding to zero + is_variable[2] = false; // parameter index corresponding to one + break; + + // -------------------------------------------------------------------- + // cases where NumArg(op) == 3 + + case LdpOp: + case StppOp: + CPPAD_ASSERT_UNKNOWN( NumArg(op) == 3 ); + is_variable[0] = false; + is_variable[1] = false; + is_variable[2] = false; + break; + + case LdvOp: + case StvpOp: + CPPAD_ASSERT_UNKNOWN( NumArg(op) == 3 ); + is_variable[0] = false; + is_variable[1] = true; + is_variable[2] = false; + break; + + case StpvOp: + CPPAD_ASSERT_UNKNOWN( NumArg(op) == 3 ); + is_variable[0] = false; + is_variable[1] = false; + is_variable[2] = true; + break; + + case StvvOp: + CPPAD_ASSERT_UNKNOWN( NumArg(op) == 3 ); + is_variable[0] = false; + is_variable[1] = true; + is_variable[2] = true; + break; + + // -------------------------------------------------------------------- + // case where NumArg(op) == 4 + case AFunOp: + CPPAD_ASSERT_UNKNOWN( NumArg(op) == 4 ); + for(size_t i = 0; i < 4; i++) + is_variable[i] = false; + break; + + // -------------------------------------------------------------------- + // case where NumArg(op) == 5 + case PriOp: + CPPAD_ASSERT_UNKNOWN( NumArg(op) == 5 ); + is_variable[0] = false; + is_variable[1] = (arg[0] & 1) != 0; + is_variable[2] = false; + is_variable[3] = (arg[0] & 2) != 0; + is_variable[4] = false; + break; + + // -------------------------------------------------------------------- + // case where NumArg(op) == 6 + case CExpOp: + CPPAD_ASSERT_UNKNOWN( NumArg(op) == 6 ); + is_variable[0] = false; + is_variable[1] = false; + is_variable[2] = (arg[0] & 1) != 0; + is_variable[3] = (arg[0] & 2) != 0; + is_variable[4] = (arg[0] & 4) != 0; + is_variable[5] = (arg[0] & 8) != 0; + break; + + // ------------------------------------------------------------------- + // CSkipOp: + case CSkipOp: + CPPAD_ASSERT_UNKNOWN( NumArg(op) == 0 ) + // + // true number of arguments + num_arg = size_t(7 + arg[4] + arg[5]); + is_variable.resize(num_arg); + is_variable[0] = false; + is_variable[1] = false; + is_variable[2] = (arg[1] & 1) != 0; + is_variable[3] = (arg[1] & 2) != 0; + for(size_t i = 4; i < num_arg; ++i) + is_variable[i] = false; + break; + + // ------------------------------------------------------------------- + // CSumOp: + case CSumOp: + CPPAD_ASSERT_UNKNOWN( NumArg(op) == 0 ) + // + // true number of arguments + num_arg = size_t(arg[4]); + // + is_variable.resize( num_arg ); + for(size_t i = 0; i < num_arg; ++i) + is_variable[i] = (5 <= i) & (i < size_t(arg[2])); + break; + + case EqppOp: + case LeppOp: + case LtppOp: + case NeppOp: + CPPAD_ASSERT_UNKNOWN( NumArg(op) == 2 ); + is_variable[0] = false; + is_variable[1] = false; + break; + + // -------------------------------------------------------------------- + default: + CPPAD_ASSERT_UNKNOWN(false); + break; + } + return; +} + +} } // END_CPPAD_LOCAL_NAMESPACE +# endif diff --git a/build-config/cppad/include/cppad/local/optimize/cexp_info.hpp b/build-config/cppad/include/cppad/local/optimize/cexp_info.hpp new file mode 100644 index 00000000..92e457c6 --- /dev/null +++ b/build-config/cppad/include/cppad/local/optimize/cexp_info.hpp @@ -0,0 +1,123 @@ +# ifndef CPPAD_LOCAL_OPTIMIZE_CEXP_INFO_HPP +# define CPPAD_LOCAL_OPTIMIZE_CEXP_INFO_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ +# include // defines CompareOp +# include + +/*! +$begin optimize_cexp_info$$ +$spell + struct + cexp + op + Funap + Funav + Funrp + Funrv + cskip + arg +$$ + +$section Optimization Information About Conditional Expressions$$ + +$head struct_cexp_info$$ +information about a conditional expression +in the old operation sequence (before optimization). +$srcthisfile% + 0%// BEGIN_STRUCT_CEXP_INFO%// END_STRUCT_CEXP_INFO%1 +%$$ + +$subhead i_op$$ +is the operator index for this conditional expression. + +$subhead left$$ +is the variable or parameter index (depending on flag) +for left operand in the comparison. + +$subhead right$$ +is the variable or parameter index (depending on flag) +for right operand in the comparison. + +$subhead max_left_right$$ +is the maximum of the left and right variable indices. +This is a variable index, so parameters correspond to index zero. + +$subhead cop$$ +is the comparison operator for this conditional expression. + +$subhead flag$$ +$list number$$ +(flag & 1) is true if and only if left is a variable +$lnext +(flag & 2) is true if and only if right is a variable +$lend + +$head struct_cskip_new$$ +information about a conditional expression +in thew new operation sequence (after optimization). +$srcthisfile% + 0%// BEGIN_STRUCT_CSKIP_NEW%// END_STRUCT_CSKIP_NEW%1 +%$$ + +$subhead left$$ +is the variable or parameter index (depending on flag) +for left operand in the comparison. + +$subhead right$$ +is the variable or parameter index (depending on flag) +for right operand in the comparison. + +$subhead max_left_right$$ +is the maximum of the left and right variable indices. +This is a variable index, so parameters correspond to index zero. + +$subhead i_arg$$ +index where this conditional skips arguments start +(in the vector or arguments for all operators). + +$end +*/ + +// BEGIN_CPPAD_LOCAL_OPTIMIZE_NAMESPACE +namespace CppAD { namespace local { namespace optimize { +/*! +Information about one conditional expression. +*/ +// BEGIN_STRUCT_CEXP_INFO +struct struct_cexp_info { + addr_t i_op; + addr_t left; + addr_t right; + addr_t max_left_right; + CompareOp cop; + unsigned char flag; +}; +// END_STRUCT_CEXP_INFO + +// BEGIN_STRUCT_CSKIP_NEW +struct struct_cskip_new { + size_t left; + size_t right; + size_t max_left_right; + size_t i_arg; +}; +// END_STRUCT_CSKIP_NEW + +} } } // END_CPPAD_LOCAL_OPTIMIZE_NAMESPACE + +namespace CppAD { namespace local { + template <> inline bool is_pod(void) + { return true; } +} } + +# endif diff --git a/build-config/cppad/include/cppad/local/optimize/csum_op_info.hpp b/build-config/cppad/include/cppad/local/optimize/csum_op_info.hpp new file mode 100644 index 00000000..3f8572f5 --- /dev/null +++ b/build-config/cppad/include/cppad/local/optimize/csum_op_info.hpp @@ -0,0 +1,42 @@ +# ifndef CPPAD_LOCAL_OPTIMIZE_CSUM_OP_INFO_HPP +# define CPPAD_LOCAL_OPTIMIZE_CSUM_OP_INFO_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ +# include +# include // defines addr_t + +/*! +\file csum_op_info.hpp +Information about one old variable that is part of a new CSumOp operation. +*/ + +// BEGIN_CPPAD_LOCAL_OPTIMIZE_NAMESPACE +namespace CppAD { namespace local { namespace optimize { +/*! +Information about one old variable that is part of a new CSumOp operation. +*/ +struct struct_csum_op_info { + /// Pointer to first argument (child) for this old operator. + /// Set by the reverse sweep at beginning of optimization. + const addr_t* arg; + + /// Was this old variable added to the summation + /// (if not it was subtracted) + bool add; + + /// Operator for which this old variable is the result, NumRes(op) > 0. + OpCode op; +}; + +} } } // END_CPPAD_LOCAL_OPTIMIZE_NAMESPACE + +# endif diff --git a/build-config/cppad/include/cppad/local/optimize/csum_stacks.hpp b/build-config/cppad/include/cppad/local/optimize/csum_stacks.hpp new file mode 100644 index 00000000..1ebb5da4 --- /dev/null +++ b/build-config/cppad/include/cppad/local/optimize/csum_stacks.hpp @@ -0,0 +1,47 @@ +# ifndef CPPAD_LOCAL_OPTIMIZE_CSUM_STACKS_HPP +# define CPPAD_LOCAL_OPTIMIZE_CSUM_STACKS_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-18 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ +# include +# include + +/*! +\file csum_stacks.hpp +Information about one cumulative summation operation. +*/ + +// BEGIN_CPPAD_LOCAL_OPTIMIZE_NAMESPACE +namespace CppAD { namespace local { namespace optimize { +/*! +Information about one cumulative summation operation. +*/ +struct struct_csum_stacks { + + /// old operator indices for this cummulative summation + std::stack op_info; + + /// old variable indices to be added + std::stack add_var; + + /// old variable indices to be subtracted + std::stack sub_var; + + /// dynamic parameter indices to be added + std::stack add_dyn; + + /// dynamic parameter indices to be subtracted + std::stack sub_dyn; +}; + +} } } // END_CPPAD_LOCAL_OPTIMIZE_NAMESPACE + +# endif diff --git a/build-config/cppad/include/cppad/local/optimize/get_cexp_info.hpp b/build-config/cppad/include/cppad/local/optimize/get_cexp_info.hpp new file mode 100644 index 00000000..bb2e1f42 --- /dev/null +++ b/build-config/cppad/include/cppad/local/optimize/get_cexp_info.hpp @@ -0,0 +1,260 @@ +# ifndef CPPAD_LOCAL_OPTIMIZE_GET_CEXP_INFO_HPP +# define CPPAD_LOCAL_OPTIMIZE_GET_CEXP_INFO_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +# include +# include +# include + +// BEGIN_CPPAD_LOCAL_OPTIMIZE_NAMESPACE +namespace CppAD { namespace local { namespace optimize { + +/*! +$begin optimize_get_cexp_info.hpp$$ +$spell + cexp + itr + op + iterator + bool + Exp + deallocate + Funap + Funav + Funrp + Funrv + num + var +$$ + +$section Information for Each Conditional Expression$$ + +$head Syntax$$ +$codei%get_cexp_info( + %play%, + %random_itr%, + %op_previous%, + %op_usage%, + %cexp2op%, + %cexp_set%, + %cexp_info%, + %skip_op_true%, + %skip_op_false% +)%$$ + +$head Prototype$$ +$srcthisfile% + 0%// BEGIN_PROTOTYPE%// END_PROTOTYPE%1 +%$$ + + +$head Restrictions$$ +Do not call this routine unless you are optimizing conditional expressions +and there are conditional expressions in the operation sequence. + +$head Base$$ +base type for the operator; i.e., this operation was recorded +using AD and computations by this routine are done using type Base. + +$head play$$ +This is the old operation sequence. + +$head random_itr$$ +This is a random iterator for the old operation sequence. + +$head cexp2op$$ +This is the number of conditional expressions in the operation sequence +and must be non-zero. + +$head cexp_set$$ +This is a vector of sets, the i-th set, set[i], +is a set of elements for the i-th operator. +If e is an element of set[i], let j = e / 2 and k = e % 2. +If the comparison for the j-th conditional expression is equal to bool(k), +the i-th operator can be skipped (is not used by any of the results). +Note that j indexes the subset of operators that are conditional expressions +in the old operation sequence. + +$head cexp_info$$ +The input size of this vector must be zero. +Upon return cexp_info has size equal to the number of conditional expressions +in the operation sequence; i.e., the number of CExpOp operators. +The value cexp_info[j] is the information corresponding to the j-th +conditional expression in the operation sequence. +This vector is in the same order as the operation sequence; i.e. +if j1 > j2, cexp_info[j1].i_op > cexp_info[j2].i_op. +Note that skip_op_true and skip_op_false could be part of this structure, +but then we would allocate and deallocate two vectors for each conditional +expression in the operation sequence. + +$head skip_op_true$$ +This vector of sets is empty on input. +Upon return, the j-th set is the operators that are not used when +comparison result for cexp_info[j] is true. +Note that FunapOp, FunavOp, FunrpOp, and FunrvOp, are not in this +set and should be skipped when the corresponding AFunOp are skipped. + +$head skip_op_false$$ +This vector of sets is empty on input. +Upon return, the j-th set is the operators that are not used when +comparison result for cexp_info[j] is false. +Note that FunapOp, FunavOp, FunrpOp, and FunrvOp, are not in this +set and should be skipped when the corresponding AFunOp are skipped. + +$head op_previous$$ +This argument has size equal to the number of operators +in the operation sequence; i.e., num_op = play->nun_var_rec(). +If op_previous[i] == 0, no replacement was found for the i-th operator. +If op_previous[i] != 0, op_usage[ op_previous[i] ] == usage_t(yes_usage). + +$head op_usage$$ +This argument has size equal to the number of operators +in the operation sequence; i.e., num_op = play->nun_var_rec(). +The value op_usage[i] is the usage for +the i-th operator in the operation sequence. + +$end +*/ + +// BEGIN_PROTOTYPE +template +void get_cexp_info( + const player* play , + const play::const_random_iterator& random_itr , + const pod_vector& op_previous , + const pod_vector& op_usage , + const pod_vector& cexp2op , + const sparse::list_setvec& cexp_set , + vector& cexp_info , + sparse::list_setvec& skip_op_true , + sparse::list_setvec& skip_op_false ) +// END_PROTOTYPE +{ + CPPAD_ASSERT_UNKNOWN( cexp_set.n_set() > 0 ); + CPPAD_ASSERT_UNKNOWN( cexp_info.size() == 0 ); + + // number of operators in the tape + const size_t num_op = play->num_op_rec(); + CPPAD_ASSERT_UNKNOWN( op_usage.size() == num_op ); + CPPAD_ASSERT_UNKNOWN( op_previous.size() == num_op ); + // + // number of conditional expressions in the tape + size_t num_cexp_op = cexp2op.size(); + // + // initialize mapping from variable index to operator index + CPPAD_ASSERT_UNKNOWN( + size_t( (std::numeric_limits::max)() ) >= num_op + ); + // ---------------------------------------------------------------------- + // compute cexp_info + // ---------------------------------------------------------------------- + // + // initialize information for each conditional expression + cexp_info.resize(num_cexp_op); + skip_op_true.resize(num_cexp_op, num_op); + skip_op_false.resize(num_cexp_op, num_op); + // + for(size_t i = 0; i < num_cexp_op; i++) + { size_t i_op = size_t( cexp2op[i] ); + CPPAD_ASSERT_UNKNOWN( + op_previous[i_op] == 0 || op_usage[i_op] == usage_t(yes_usage) + ); + OpCode op; // operator + const addr_t* arg; // arguments + size_t i_var; // variable index of first result + random_itr.op_info(i_op, op, arg, i_var); + CPPAD_ASSERT_UNKNOWN( op == CExpOp ); + // + struct_cexp_info info; + info.i_op = addr_t(i_op); + info.cop = CompareOp( arg[0] ); + info.flag = static_cast(arg[1]); + info.left = arg[2]; + info.right = arg[3]; + // + // max_left_right + addr_t index = 0; + if( arg[1] & 1 ) + index = std::max(index, info.left); + if( arg[1] & 2 ) + index = std::max(index, info.right); + info.max_left_right = index; + // + cexp_info[i] = info; + }; + // Determine which operators can be conditionally skipped + size_t i_op = 0; + while(i_op < num_op) + { size_t j_op = i_op; + bool keep = op_usage[i_op] != usage_t(no_usage); + keep &= op_usage[i_op] != usage_t(csum_usage); + keep &= op_previous[i_op] == 0; + if( keep ) + { sparse::list_setvec_const_iterator itr(cexp_set, i_op); + if( *itr != cexp_set.end() ) + { if( play->GetOp(i_op) == AFunOp ) + { // i_op is the first operations in this atomic function call. + // Find the last operation in this call. + ++j_op; + while( play->GetOp(j_op) != AFunOp ) + { switch( play->GetOp(j_op) ) + { case FunapOp: + case FunavOp: + case FunrpOp: + case FunrvOp: + break; + + default: + CPPAD_ASSERT_UNKNOWN(false); + } + ++j_op; + } + } + } + while( *itr != cexp_set.end() ) + { size_t element = *itr; + size_t index = element / 2; + bool compare = bool( element % 2 ); + if( compare == false ) + { // cexp_info[index].skip_op_false.push_back(i_op); + skip_op_false.post_element(index, i_op); + if( j_op != i_op ) + { // cexp_info[index].skip_op_false.push_back(j_op); + skip_op_false.post_element(index, j_op); + } + } + else + { // cexp_info[index].skip_op_true.push_back(i_op); + skip_op_true.post_element(index, i_op); + if( j_op != i_op ) + { // cexp_info[index].skip_op_true.push_back(j_op); + skip_op_true.post_element(index, j_op); + } + } + ++itr; + } + } + CPPAD_ASSERT_UNKNOWN( i_op <= j_op ); + i_op += (1 + j_op) - i_op; + } + // process postings for skip_op_false, skip_op_true + for(size_t i = 0; i < num_cexp_op; ++i) + { skip_op_false.process_post(i); + skip_op_true.process_post(i); + } + return; +} + +} } } // END_CPPAD_LOCAL_OPTIMIZE_NAMESPACE + +# endif diff --git a/build-config/cppad/include/cppad/local/optimize/get_dyn_previous.hpp b/build-config/cppad/include/cppad/local/optimize/get_dyn_previous.hpp new file mode 100644 index 00000000..e36f0bba --- /dev/null +++ b/build-config/cppad/include/cppad/local/optimize/get_dyn_previous.hpp @@ -0,0 +1,447 @@ +# ifndef CPPAD_LOCAL_OPTIMIZE_GET_DYN_PREVIOUS_HPP +# define CPPAD_LOCAL_OPTIMIZE_GET_DYN_PREVIOUS_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ +/*! +\file get_cexp_info.hpp +Create operator information tables +*/ + +# include +# include +# include + +// BEGIN_CPPAD_LOCAL_OPTIMIZE_NAMESPACE +namespace CppAD { namespace local { namespace optimize { + +/*! +mapping from a dynamic parameter index to its arguments + +\param i_dyn +is the dynamic parameter index + +\param dyn_ind2par_ind +is the mapping from dynamic parameter index to parameter index +(size is number of dynamic parameters). + +\param dyn_par_is +i-th element is true (false) if i-th parameter is (is not) dynamic +(size is number of parameters). + +\param dyn_arg_offset +j-th element is the offset in dyn_par_arg of the first argument for j-th +dynamic parameter's operator (size is number of dynamic parameters). +This is only defined for dynamic parameters indices less than or equal i_dyn. + +\param dyn_par_arg +it the vector of arguments for all the dynamic parameter operators. +This is only defined for dynamic parameters indices less than or equal i_dyn. + +\param par_ind2dyn_ind +is the mapping from parameter index to dynamic parameter index +(size is number of parameters). This is only defined for parameter +indices less than or equal the parameter index corresponding to i_dyn. + +\param dyn_previous +is the mapping from dynamic parameter index to previous dynamic parameter +that can be used as a replacement (size is number of dynamic parameters). +This is only defined for dynamic parameters indices less than or equal i_dyn. + +\param arg_match +Size of this vector must be number of arguments for operator for i_dyn. +The input value of its elements does not matter. +Upn return it containts the parameter indices for the arguments +to use when matching this operator +Arguments that are dynamic prarameters, and have previous matches, +have been replaced by their previous matches. +*/ +inline void dyn_arg_match( + size_t i_dyn , + const pod_vector& dyn_ind2par_ind , + const pod_vector & dyn_par_is , + const pod_vector& dyn_arg_offset , + const pod_vector& dyn_par_arg , + const pod_vector& par_ind2dyn_ind , + const pod_vector& dyn_previous , + pod_vector& arg_match ) +{ + // number of dynamic parameters + addr_t num_dynamic_par = addr_t( dyn_ind2par_ind.size() ); + // + // check some assumptions + CPPAD_ASSERT_UNKNOWN( size_t( num_dynamic_par ) == dyn_arg_offset.size() ); + CPPAD_ASSERT_UNKNOWN( size_t( num_dynamic_par ) == dyn_previous.size() ); + CPPAD_ASSERT_UNKNOWN( dyn_par_is.size() == par_ind2dyn_ind.size() ); + // + // number of arguments for this operator + addr_t n_arg = addr_t( arg_match.size() ); + // + // index in dyn_par_arg of first argument for this operator + addr_t i_arg = dyn_arg_offset[i_dyn]; + // + // loop over arguments for this operator + for(addr_t j = 0; j < n_arg; ++j) + { // parameter index for this argument + addr_t j_par = dyn_par_arg[i_arg + j]; + CPPAD_ASSERT_UNKNOWN( j_par < dyn_ind2par_ind[i_dyn] ); + // + // map dynamic parameters arguments to previous matches + if( dyn_par_is[j_par] ) + { addr_t j_dyn = par_ind2dyn_ind[j_par]; + if( dyn_previous[j_dyn] != num_dynamic_par ) + { CPPAD_ASSERT_UNKNOWN( dyn_previous[j_dyn] < j_dyn ); + // previous dynamic parameter + j_dyn = dyn_previous[j_dyn]; + // correspoding parameter + j_par = dyn_ind2par_ind[j_dyn]; + } + } + arg_match[j] = j_par; + } + return; +} + +/*! +Get mapping from each dynamic parameter to a previous dynamic parameter +that can be used to replace it (if one exists). + +\tparam Base +base type for the operator; i.e., this operation was recorded +using AD< Base > and computations by this routine are done using type + Base. + +\param play +This is the old operation sequence. + +\param random_itr +This is a random iterator for the old operation sequence. + +\param par_usage +The size of this vector is the number of parameters in the +operation sequence.i.e., play->nun_var_rec(). +It is the usage counting previous operator optimization of operators. + +\param dyn_previous +The input size of this vector must be zero. +Upon return it has size equal to the number of dynamic parameters in the +operation sequence; i.e., num_dyn = play->num_dynamic_par(). +Let k = dyn_parvious[j]. If k == num_dyn, no replacement was found for the +j-th dynamic parameter. If k != num_dyn, the k-th dynamic parameter can be +used in place of the j-th dynamic parameter, k < j, dyn_previous[k] != num_dyn, +par_usage[dyn_ind2par_ind[k]] == true. +*/ + +template +void get_dyn_previous( + const player* play , + const play::const_random_iterator& random_itr , + pod_vector& par_usage , + pod_vector& dyn_previous ) +{ + // number of parameters in the recording + size_t num_par = play->num_par_rec(); + + // number of dynamic parameters in the recording + size_t num_dynamic_par = play->num_dynamic_par(); + + // number of independent dynamic parameters in the recording + size_t num_dynamic_ind = play->num_dynamic_ind(); + + // check some assumptions + CPPAD_ASSERT_UNKNOWN( dyn_previous.size() == 0 ); + CPPAD_ASSERT_UNKNOWN( par_usage.size() == num_par ); + CPPAD_ASSERT_UNKNOWN( num_dynamic_par <= num_par ); + CPPAD_ASSERT_UNKNOWN( num_dynamic_ind <= num_dynamic_par ); + CPPAD_ASSERT_UNKNOWN( num_arg_dyn( ind_dyn ) == 0 ); + + // dynamic parameter information + dyn_previous.resize( num_dynamic_par ); + const pod_vector& dyn_ind2par_ind( play->dyn_ind2par_ind() ); + const pod_vector& dyn_par_is( play->dyn_par_is() ); + const pod_vector& dyn_par_op( play->dyn_par_op() ); + const pod_vector& dyn_par_arg( play->dyn_par_arg() ); + + // mapping from parameter index to dynamic parameter index + // only defined when dyn_par_is is true + pod_vector par_ind2dyn_ind(num_par); + + // mapping from dynamic parameter index to first argument index + pod_vector dyn_arg_offset(num_dynamic_par); + + // ---------------------------------------------------------------------- + // compute dyn_previous + // ---------------------------------------------------------------------- + sparse::list_setvec hash_table_dyn; + hash_table_dyn.resize(CPPAD_HASH_TABLE_SIZE, num_dynamic_par); + // + // Initialize in dyn_par_arg + // (independent dynamic parameters do not have any arguments) + size_t i_arg = 0; + // + // independent dynamic parameters + for(size_t i_dyn = 0; i_dyn < num_dynamic_ind; ++i_dyn) + { // parameter index + size_t i_par = size_t( dyn_ind2par_ind[i_dyn] ); + // dynamic parameter index is one greater because phantom parameter + // at index 0 is not dynamic + CPPAD_ASSERT_UNKNOWN( i_par == i_dyn + 1 ); + // mapping from parameter index to dynamic parameter index + par_ind2dyn_ind[i_par] = addr_t( i_dyn ); + // never get optimized out + dyn_previous[i_dyn] = addr_t( num_dynamic_par ); + } + // + // other dynamic parameters + for(size_t i_dyn = num_dynamic_ind; i_dyn < num_dynamic_par; ++i_dyn) + { // Initialize previous for this dynamic parameter. This is only + // defined for dynamic parameter indices less than or equal i_dyn + dyn_previous[i_dyn] = addr_t( num_dynamic_par ); + // + // mapping from dynamic parameter index to argument offset + // is only defined for j_dyn <= i_dyn + dyn_arg_offset[i_dyn] = addr_t( i_arg ); + // + // parameter index for this dynamic parameter + size_t i_par = size_t( dyn_ind2par_ind[i_dyn] ); + // + // mapping from parameter indices to dynamic parameter indices + // is only defined when dyn_par_is[i_par] is true and for parameter + // indices less than or equal i_par + CPPAD_ASSERT_UNKNOWN( dyn_par_is[i_par] ); + par_ind2dyn_ind[i_par] = addr_t( i_dyn ); + // + // operator for this dynamic parameter + op_code_dyn op = op_code_dyn( dyn_par_op[i_dyn] ); + // + // temporary used below and decaled here to reduce memory allocation + pod_vector arg_match; + // + // temporaries used below and decaled here to reduce indentation level + bool match; + size_t code; + size_t count; + // + // check for a previous match for i_dyn + if( par_usage[i_par] ) switch( op ) + { + // --------------------------------------------------------------- + // unary operators + case abs_dyn: + case acos_dyn: + case acosh_dyn: + case asin_dyn: + case asinh_dyn: + case atan_dyn: + case atanh_dyn: + case cos_dyn: + case cosh_dyn: + case erf_dyn: + case erfc_dyn: + case exp_dyn: + case expm1_dyn: + case fabs_dyn: + case log_dyn: + case log1p_dyn: + case sign_dyn: + case sin_dyn: + case sinh_dyn: + case sqrt_dyn: + case tan_dyn: + case tanh_dyn: + CPPAD_ASSERT_UNKNOWN( num_arg_dyn(op) == 1); + CPPAD_ASSERT_UNKNOWN( dyn_par_is[i_par] ); + { size_t num_arg = 1; + arg_match.resize(num_arg); + dyn_arg_match( + i_dyn, + dyn_ind2par_ind, + dyn_par_is, + dyn_arg_offset, + dyn_par_arg, + par_ind2dyn_ind, + dyn_previous, + arg_match + ); + opcode_t op_t = opcode_t(op); + code = optimize_hash_code( + op_t, num_arg, arg_match.data() + ); + // + // iterator for the set with this hash code + sparse::list_setvec_const_iterator itr(hash_table_dyn, code); + // + // check for a match + count = 0; + match = false; + while( ! match && *itr != num_dynamic_par ) + { ++count; + // + // candidate for current dynamic parameter + size_t k_dyn = *itr; + CPPAD_ASSERT_UNKNOWN( k_dyn < i_dyn ); + // + // argument offset for the candidate + addr_t k_arg = dyn_arg_offset[k_dyn]; + // + match = op_t == dyn_par_op[k_dyn]; + match &= arg_match[0] == dyn_par_arg[k_arg + 0]; + if( ! match ) + ++itr; + } + if( match ) + { size_t k_dyn = *itr; + CPPAD_ASSERT_UNKNOWN( k_dyn < i_dyn ); + dyn_previous[i_dyn] = addr_t( k_dyn ); + } + else + { CPPAD_ASSERT_UNKNOWN( count < 11 ); + if( count == 10 ) + { // restart list for this hash code + hash_table_dyn.clear(code); + } + // Add this entry to hash table. + // Not using post_element becasue we need to iterate for + // this code before adding another element for this code. + hash_table_dyn.add_element(code, i_dyn); + } + } + break; + + // --------------------------------------------------------------- + // binary operators + case add_dyn: + case div_dyn: + case mul_dyn: + case pow_dyn: + case sub_dyn: + case zmul_dyn: + CPPAD_ASSERT_UNKNOWN( num_arg_dyn(op) == 2); + CPPAD_ASSERT_UNKNOWN( dyn_par_is[i_par] ); + match = false; + { size_t num_arg = 2; + arg_match.resize(num_arg); + dyn_arg_match( + i_dyn, + dyn_ind2par_ind, + dyn_par_is, + dyn_arg_offset, + dyn_par_arg , + par_ind2dyn_ind, + dyn_previous, + arg_match + ); + opcode_t op_t = opcode_t(op); + code = optimize_hash_code( + op_t, num_arg, arg_match.data() + ); + // + // iterator for the set with this hash code + sparse::list_setvec_const_iterator itr(hash_table_dyn, code); + // + // check for a match + count = 0; + while( ! match && *itr != num_dynamic_par ) + { ++count; + // + // candidate for current dynamic parameter + size_t k_dyn = *itr; + CPPAD_ASSERT_UNKNOWN( k_dyn < i_dyn ); + // + // argument offset for the candidate + addr_t k_arg = dyn_arg_offset[k_dyn]; + // + match = op_t == dyn_par_op[k_dyn]; + match &= arg_match[0] == dyn_par_arg[k_arg + 0]; + match &= arg_match[1] == dyn_par_arg[k_arg + 1]; + if( ! match ) + ++itr; + } + if( match ) + { size_t k_dyn = *itr; + CPPAD_ASSERT_UNKNOWN( k_dyn < i_dyn ); + dyn_previous[i_dyn] = addr_t( k_dyn ); + } + } + if( (! match) & ( (op == add_dyn) | (op == mul_dyn) ) ) + { size_t num_arg = 2; + std::swap( arg_match[0], arg_match[1] ); + opcode_t op_t = opcode_t(op); + size_t code_swp = optimize_hash_code( + op_t, num_arg, arg_match.data() + ); + // + // iterator for the set with this hash code + sparse::list_setvec_const_iterator itr(hash_table_dyn, code_swp); + // + // check for a match + while( ! match && *itr != num_dynamic_par ) + { // + // candidate for current dynamic parameter + size_t k_dyn = *itr; + CPPAD_ASSERT_UNKNOWN( k_dyn < i_dyn ); + // + // argument offset for the candidate + addr_t k_arg = dyn_arg_offset[k_dyn]; + // + match = op_t == dyn_par_op[k_dyn]; + match &= arg_match[0] == dyn_par_arg[k_arg + 0]; + match &= arg_match[1] == dyn_par_arg[k_arg + 1]; + if( ! match ) + ++itr; + } + if( match ) + { size_t k_dyn = *itr; + CPPAD_ASSERT_UNKNOWN( k_dyn < i_dyn ); + dyn_previous[i_dyn] = addr_t( k_dyn ); + } + } + if( ! match ) + { CPPAD_ASSERT_UNKNOWN( count < 11 ); + if( count == 10 ) + { // restart list for this hash code + hash_table_dyn.clear(code); + } + // Add the entry to hash table + // Not using post_element becasue we need to iterate for + // this code before adding another element for this code. + hash_table_dyn.add_element(code, i_dyn); + } + + // -------------------------------------------------------------- + // skipping these cases for now + case dis_dyn: + case cond_exp_dyn: + case atom_dyn: + case result_dyn: + break; + + + // -------------------------------------------------------------- + // should be no other cases; e.g., no ind_dyn or number_dyn. + default: + CPPAD_ASSERT_UNKNOWN(false); + break; + } + i_arg += num_arg_dyn(op); + if( op == atom_dyn ) + { CPPAD_ASSERT_UNKNOWN( num_arg_dyn(op) == 0 ); + size_t n = size_t( dyn_par_arg[i_arg + 1] ); + size_t m = size_t( dyn_par_arg[i_arg + 2] ); + size_t n_arg = 5 + n + m; + i_arg += n_arg; + } + } +} + +} } } // END_CPPAD_LOCAL_OPTIMIZE_NAMESPACE + +# endif diff --git a/build-config/cppad/include/cppad/local/optimize/get_op_previous.hpp b/build-config/cppad/include/cppad/local/optimize/get_op_previous.hpp new file mode 100644 index 00000000..312a8470 --- /dev/null +++ b/build-config/cppad/include/cppad/local/optimize/get_op_previous.hpp @@ -0,0 +1,269 @@ +# ifndef CPPAD_LOCAL_OPTIMIZE_GET_OP_PREVIOUS_HPP +# define CPPAD_LOCAL_OPTIMIZE_GET_OP_PREVIOUS_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ +# include +# include + +// BEGIN_CPPAD_LOCAL_OPTIMIZE_NAMESPACE +namespace CppAD { namespace local { namespace optimize { +/* +$begin optimize_get_op_previous$$ +$spell + itr + iterator + bool + Exp + num + var + Op + cexp + Arg + Res +$$ + +$section Get Mapping From Op to Previous Op That is Equivalent$$ + +$head Syntax$$ +$icode%exceed_collision_limit% = get_op_previous( + %collision_limit%, + %play%, + %random_itr%, + %cexp_set%, + %op_previous%, + %op_usage% +)%$$ + +$head Prototype$$ +$srcthisfile% + 0%// BEGIN_PROTOTYPE%// END_PROTOTYPE%1 +%$$ + +$head Base$$ +base type for the operator; i.e., this operation was recorded +using AD and computations by this routine are done using type Base. + +$head collision_limit$$ +is the maximum number of collisions (matches) +allowed in the hash expression has table. + +$head play$$ +is the old operation sequence. + +$head random_itr$$ +is a random iterator for the old operation sequence. + +$head cexp_set$$ +set[i] is a set of elements for the i-th operator. +Suppose that e is an element of set[i], j = e / 2, k = e % 2. +If the comparison for the j-th conditional expression is equal to bool(k), +the i-th operator can be skipped (is not used by any of the results). +Note the j indexes the CExpOp operators in the operation sequence. +On input, cexp_set is does not count previous optimization. +On output, it does count previous optimization. + +$head op_previous$$ +The input size of this vector must be zero. +Upon return it has size equal to the number of operators +in the operation sequence; i.e., num_op = play->nun_var_rec(). +Let j = op_previous[i]. If j = 0, no replacement was found for i-th operator. +If j != 0: +$list number$$ +j < i +$lnext +op_previous[j] == 0 +$lnext +op_usage[j] == usage_t(yes_usage) +$lnext +i-th operator has NumArg(op) <= 3 +$lnext +i-th operator has 0 < NumRes(op) +$lnext +i-th operator is not one of the following: +$nospell PriOp, ParOp, InvOp, EndOp, CexpOp, BeginOp.$$ +$lnext +i-th operator is not one of the load store operator: +$nospell LtpvOp, LtvpOp, LtvvOp, StppOp, StpvOp, StvpOp, StvvOp.$$ +$lnext +i-th operator is not a atomic function operator: +$nospell AFunOp, FunapOp, FunavOp, FunrpOp, FunrvOp.$$ +$lend + +$head op_usage$$ +The size of this vector is the number of operators in the +old operation sequence.i.e., play->nun_var_rec(). +On input, op_usage[i] is the usage for +the i-th operator in the operation sequence not counting previous +optimization. +On output, it is the usage counting previous operator optimization. + +$head exceed_collision_limit$$ +If the $icode collision_limit$$ is exceeded (is not exceeded), +the return value is true (false). + +$end +*/ + +// BEGIN_PROTOTYPE +template +bool get_op_previous( + size_t collision_limit , + const player* play , + const play::const_random_iterator& random_itr , + sparse::list_setvec& cexp_set , + pod_vector& op_previous , + pod_vector& op_usage ) +// END_PROTOTYPE +{ bool exceed_collision_limit = false; + // + // number of operators in the tape + const size_t num_op = random_itr.num_op(); + CPPAD_ASSERT_UNKNOWN( op_previous.size() == 0 ); + CPPAD_ASSERT_UNKNOWN( op_usage.size() == num_op ); + op_previous.resize( num_op ); + // + // number of conditional expressions in the tape + // + // initialize mapping from variable index to operator index + CPPAD_ASSERT_UNKNOWN( + size_t( (std::numeric_limits::max)() ) >= num_op + ); + // ---------------------------------------------------------------------- + // compute op_previous + // ---------------------------------------------------------------------- + sparse::list_setvec hash_table_op; + hash_table_op.resize(CPPAD_HASH_TABLE_SIZE, num_op); + // + pod_vector work_bool; + pod_vector work_addr_t; + for(size_t i_op = 0; i_op < num_op; ++i_op) + { op_previous[i_op] = 0; + + if( op_usage[i_op] == usage_t(yes_usage) ) + switch( random_itr.get_op(i_op) ) + { + // ---------------------------------------------------------------- + // these operators never match pevious operators + case BeginOp: + case CExpOp: + case CSkipOp: + case CSumOp: + case EndOp: + case InvOp: + case LdpOp: + case LdvOp: + case ParOp: + case PriOp: + case StppOp: + case StpvOp: + case StvpOp: + case StvvOp: + case AFunOp: + case FunapOp: + case FunavOp: + case FunrpOp: + case FunrvOp: + break; + + // ---------------------------------------------------------------- + // check for a previous match + case AbsOp: + case AcosOp: + case AcoshOp: + case AddpvOp: + case AddvvOp: + case AsinOp: + case AsinhOp: + case AtanOp: + case AtanhOp: + case CosOp: + case CoshOp: + case DisOp: + case DivpvOp: + case DivvpOp: + case DivvvOp: + case EqpvOp: + case EqvvOp: + case ErfOp: + case ErfcOp: + case ExpOp: + case Expm1Op: + case LepvOp: + case LevpOp: + case LevvOp: + case LogOp: + case Log1pOp: + case LtpvOp: + case LtvpOp: + case LtvvOp: + case MulpvOp: + case MulvvOp: + case NepvOp: + case NevvOp: + case PowpvOp: + case PowvpOp: + case PowvvOp: + case SignOp: + case SinOp: + case SinhOp: + case SqrtOp: + case SubpvOp: + case SubvpOp: + case SubvvOp: + case TanOp: + case TanhOp: + case ZmulpvOp: + case ZmulvpOp: + case ZmulvvOp: + exceed_collision_limit |= match_op( + collision_limit, + random_itr, + op_previous, + i_op, + hash_table_op, + work_bool, + work_addr_t + ); + if( op_previous[i_op] != 0 ) + { // like a unary operator that assigns i_op equal to previous. + size_t previous = size_t( op_previous[i_op] ); + bool sum_op = false; + CPPAD_ASSERT_UNKNOWN( previous < i_op ); + op_inc_arg_usage( + play, sum_op, i_op, previous, op_usage, cexp_set + ); + } + break; + + // ---------------------------------------------------------------- + default: + CPPAD_ASSERT_UNKNOWN(false); + break; + } + } + /* --------------------------------------------------------------------- + // Print out hash code usage summary + CppAD::vector count(collision_limit + 1); + for(size_t i = 0; i <= collision_limit; ++i) + count[i] = 0; + for(size_t code = 0; code < CPPAD_HASH_TABLE_SIZE; ++code) + { size_t size = hash_table_op.number_elements(code); + ++count[size]; + } + std::cout << "count = " << count << "\n"; + --------------------------------------------------------------------- */ + return exceed_collision_limit; +} + +} } } // END_CPPAD_LOCAL_OPTIMIZE_NAMESPACE + +# endif diff --git a/build-config/cppad/include/cppad/local/optimize/get_op_usage.hpp b/build-config/cppad/include/cppad/local/optimize/get_op_usage.hpp new file mode 100644 index 00000000..504f2f85 --- /dev/null +++ b/build-config/cppad/include/cppad/local/optimize/get_op_usage.hpp @@ -0,0 +1,853 @@ +# ifndef CPPAD_LOCAL_OPTIMIZE_GET_OP_USAGE_HPP +# define CPPAD_LOCAL_OPTIMIZE_GET_OP_USAGE_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ +# include +# include +# include + +// BEGIN_CPPAD_LOCAL_OPTIMIZE_NAMESPACE +namespace CppAD { namespace local { namespace optimize { + +/// Is this an addition or subtraction operator +inline bool op_add_or_sub( + OpCode op ///< operator we are checking +) +{ bool result; + switch(op) + { + case AddpvOp: + case AddvvOp: + case SubpvOp: + case SubvpOp: + case SubvvOp: + result = true; + break; + + default: + result = false; + break; + } + return result; +} + +/*! +$begin optimize_op_inc_arg_usage$$ +$spell + cexp + op + arg + csum + optimizer +$$ + +$section +Increase Argument Usage and Propagate cexp_set From Result to Argument +$$ + +$head Prototype$$ +$srcthisfile% + 0%// BEGIN_OP_INC_ARG_USAGE%// END_PROTOTYPE%1 +%$$ + + +$head play$$ +is the player for the old operation sequence. + +$head check_csum$$ +is result an addition or subtraction operator, +and the optimizer is allowed to generate cumulative sum operators. + +$head i_result$$ +is the operator index for the result operator. +There are no posting waiting to be processed for the corresponding cexp_set. + +$head i_arg$$ +is the operator index for the argument to the result operator. +There may be postings waiting to be processed for the corresponding cexp_set. + +$head op_usage$$ +structure that holds the information for each of the operators. +The output value of op_usage[i_arg] is increased; to be specific, +If check_csum is true and the input value of op_usage[i_arg] +is usage_t(no_usage), its output value is usage_t(csum_usage). +Otherwise, the output value of op_usage[i_arg] is usage_t(yes_usage). + +$head cexp_set$$ +This is a vector of sets with one set for each operator. +We denote the i-th set by set[i]. +These are the conditional expression conditions that must be +satisfied for this argument to be used. + +$list number$$ +In the special case where cexp_set.n_set() is zero, +cexp_set is not changed. +$lnext +If cexp_set.n_set() != 0 and op_usage[i_arg] == usage_t(no_usage), +the input value of set[i_arg] must be empty. +In this case the output value if set[i_arg] is equal to set[i_result] +(which may also be empty). +$lnext +If cexp_set.n_set() != 0 and op_usage[i_arg] != usage_t(no_usage), +the output value of set[i_arg] is the intersection of +its input value and set[i_result]. +$lend + +$end +*/ +// BEGIN_OP_INC_ARG_USAGE +template +void op_inc_arg_usage( + const player* play , + bool check_csum , + size_t i_result , + size_t i_arg , + pod_vector& op_usage , + sparse::list_setvec& cexp_set ) +// END_PROTOTYPE +{ // value of argument input on input to this routine + enum_usage arg_usage = enum_usage( op_usage[i_arg] ); + // + // new value for usage + op_usage[i_arg] = usage_t(yes_usage); + if( check_csum ) + { if( arg_usage == no_usage ) + { OpCode op_a = play->GetOp(i_arg); + if( op_add_or_sub( op_a ) ) + { op_usage[i_arg] = usage_t(csum_usage); + } + } + } + // + // cexp_set + if( cexp_set.n_set() == 0 ) + return; + // + if( arg_usage == no_usage ) + { // set[i_arg] = set[i_result] + // not necessary to process posts for set i_result + cexp_set.assignment(i_arg, i_result, cexp_set); + } + else + { // set[i_arg] = set[i_arg] intersect set[i_result] + // is necessary to process postts for set i_arg + cexp_set.process_post(i_arg); + cexp_set.binary_intersection(i_arg, i_arg, i_result, cexp_set); + } + // + return; +} + +/*! +$begin optimize_get_op_usage$$ +$spell + Ind + var + itr + dep_taddr + cexp + vecad + Addr + iterator + NumRes + PriOp + Exp + bool + Vec +$$ + +$section +Use Reverse Activity Analysis to Get Usage Information for Each Operator +$$ + +$head Prototype$$ +$srcthisfile% + 0%// BEGIN_GET_OP_USAGE%// END_PROTOTYPE%1 +%$$ + +$head Base$$ +Base type for the operator; i.e., this operation was recorded +using $codei%AD<%Base%>%$$ and computations by this routine are done +using type $icode Base$$. + +$head Addr$$ +Type used by random iterator for the player. + +$head cumulative_sum_op$$ +If this is true (false), cumulative summation operator are allowed +(not allowed) to be generated by the optimization. + +$head compare_op$$ +if this is true, arguments are considered used if they appear in compare +operators. This is a side effect because compare operators have boolean +results (and the result is not in the tape; i.e. NumRes(op) is zero +for these operators. (This is an example of a side effect.) + +$head print_for_op$$ +if this is true, arguments are considered used if they appear in +print forward operators; i.e., PriOp. +This is also a side effect; i.e. NumRes(PriOp) is zero. + +$head conditional_skip$$ +If this is true, +the conditional expression information cexp_info will be calculated. +This may be time intensive and may not have much benefit in the optimized +recording. + + +$head play$$ +This is the operation sequence. + +$head random_itr$$ +This is a random iterator for the operation sequence. + +$head dep_taddr$$ +is a vector of indices for the dependent variables +(where the reverse activity analysis starts). + +$head cexp2op$$ +The input size of this vector must be zero. +Upon return it has size equal to the number of conditional expressions, +CExpOp operators. The value $icode%cexp2op[%j%]%$$ is the operator +index corresponding to the $th j$$ conditional expressions. + +$head cexp_set$$ +This is a vector of sets that is empty on input. +If $icode conditional_skip$$ is false, $icode cexp_usage$$ is not modified. +Otherwise, set[i] is a set of elements for the i-th operator. +Suppose that e is an element of set[i], j = e / 2, k = e % 2. +If the comparison for the j-th conditional expression is equal to bool(k), +the i-th operator can be skipped (is not used by any of the results). +Note that j indexes the CExpOp operators in the operation sequence. + +$head vecad_used$$ +The input size of this vector must be zero. +Upon return it has size equal to the number of VecAD vectors +in the operations sequences; i.e., play->num_var_vecad_rec(). +The VecAD vectors are indexed in the order that their indices appear +in the one large play->GetVecInd that holds all the VecAD vectors. + +$head op_usage$$ +The input size of this vector must be zero. +Upon return it has size equal to the number of operators +in the operation sequence; i.e., num_op = play->nun_var_rec(). +The value $icode%op_usage%[%i%]%$$ has been set to the usage for +the i-th operator in the operation sequence. +Atomic function calls are a special case, +the first and second AFunOp have usage corresponding to the entire call. +The arguments have the usage for particular parameter or variable. +This usage is only for creating variables, not for creating +dynamic parameters. + +$end +*/ +// BEGIN_GET_OP_USAGE +template +void get_op_usage( + bool conditional_skip , + bool compare_op , + bool print_for_op , + bool cumulative_sum_op , + const player* play , + const play::const_random_iterator& random_itr , + const pod_vector& dep_taddr , + pod_vector& cexp2op , + sparse::list_setvec& cexp_set , + pod_vector& vecad_used , + pod_vector& op_usage ) +// END_PROTOTYPE +{ + CPPAD_ASSERT_UNKNOWN( cexp_set.n_set() == 0 ); + CPPAD_ASSERT_UNKNOWN( vecad_used.size() == 0 ); + CPPAD_ASSERT_UNKNOWN( op_usage.size() == 0 ); + + // number of operators in the tape + const size_t num_op = play->num_op_rec(); + // + // initialize mapping from variable index to operator index + CPPAD_ASSERT_UNKNOWN( + size_t( (std::numeric_limits::max)() ) >= num_op + ); + // ----------------------------------------------------------------------- + // information about current operator + OpCode op; // operator + const addr_t* arg; // arguments + size_t i_op; // operator index + size_t i_var; // variable index of first result + // ----------------------------------------------------------------------- + // information about atomic function calls + size_t atom_index=0, atom_old=0, atom_m=0, atom_n=0, atom_i=0, atom_j=0; + enum_atom_state atom_state; + // + // work space used by user atomic functions + vector atom_x; // value of parameters in x + vector type_x; // type for each argument + vector atom_ix; // variables indices for argument vector + vector depend_y; // results that are used + vector depend_x; // arguments that are used + // + // parameter information (used by atomic function calls) +# ifndef NDEBUG + size_t num_par = play->num_par_rec(); +# endif + CPPAD_ASSERT_UNKNOWN( num_par > 0 ) + const Base* parameter = play->GetPar(); + // ----------------------------------------------------------------------- + // vecad information + size_t num_vecad = play->num_var_vecad_rec(); + size_t num_vecad_ind = play->num_var_vecad_ind_rec(); + // + vecad_used.resize(num_vecad); + for(size_t i = 0; i < num_vecad; i++) + vecad_used[i] = false; + // + vector arg2vecad(num_vecad_ind); + for(size_t i = 0; i < num_vecad_ind; i++) + arg2vecad[i] = num_vecad; // invalid value + size_t arg_0 = 1; // value of arg[0] for theh first vecad + for(size_t i = 0; i < num_vecad; i++) + { + // mapping from arg[0] value to index for this vecad object. + arg2vecad[arg_0] = i; + // + // length of this vecad object + size_t length = play->GetVecInd(arg_0 - 1); + // + // set to proper index in GetVecInd for next VecAD arg[0] value + arg_0 += length + 1; + } + CPPAD_ASSERT_UNKNOWN( arg_0 == num_vecad_ind + 1 ); + // ----------------------------------------------------------------------- + // conditional expression information + // + size_t num_cexp_op = 0; + if( conditional_skip ) + { for(i_op = 0; i_op < num_op; ++i_op) + { if( random_itr.get_op(i_op) == CExpOp ) + { // count the number of conditional expressions. + ++num_cexp_op; + } + } + } + // + cexp2op.resize( num_cexp_op ); + // + // number of sets + size_t num_set = 0; + if( conditional_skip && num_cexp_op > 0) + num_set = num_op; + // + // conditional expression index = element / 2 + // conditional expression compare = bool ( element % 2) + size_t end_set = 2 * num_cexp_op; + // + if( num_set > 0 ) + cexp_set.resize(num_set, end_set); + // ----------------------------------------------------------------------- + // initilaize operator usage for reverse dependency analysis. + op_usage.resize( num_op ); + for(i_op = 0; i_op < num_op; ++i_op) + op_usage[i_op] = usage_t(no_usage); + for(size_t i = 0; i < dep_taddr.size(); i++) + { i_op = random_itr.var2op(dep_taddr[i]); + op_usage[i_op] = usage_t(yes_usage); // dependent variables + } + // ---------------------------------------------------------------------- + // Reverse pass to compute usage and cexp_set for each operator + // ---------------------------------------------------------------------- + // + // Initialize reverse pass + size_t last_atom_i_op = 0; + size_t cexp_index = num_cexp_op; + atom_state = end_atom; + i_op = num_op; + while(i_op != 0 ) + { --i_op; + if( num_set > 0 ) + { // no more elements will be added to this set + cexp_set.process_post(i_op); + } + // + // this operator information + random_itr.op_info(i_op, op, arg, i_var); + // + // Is the result of this operation used. + // (This only makes sense when NumRes(op) > 0.) + usage_t use_result = op_usage[i_op]; + // + bool check_csum = false; + switch( op ) + { + // ============================================================= + // normal operators + // ============================================================= + + // Only one variable with index arg[0] + case SubvpOp: + check_csum = cumulative_sum_op; + // + case AbsOp: + case AcosOp: + case AcoshOp: + case AsinOp: + case AsinhOp: + case AtanOp: + case AtanhOp: + case CosOp: + case CoshOp: + case DivvpOp: + case ErfOp: + case ErfcOp: + case ExpOp: + case Expm1Op: + case LogOp: + case Log1pOp: + case PowvpOp: + case SignOp: + case SinOp: + case SinhOp: + case SqrtOp: + case TanOp: + case TanhOp: + case ZmulvpOp: + CPPAD_ASSERT_UNKNOWN( NumRes(op) > 0 ); + if( use_result != usage_t(no_usage) ) + { size_t j_op = random_itr.var2op(size_t(arg[0])); + op_inc_arg_usage( + play, check_csum, i_op, j_op, op_usage, cexp_set + ); + } + break; // -------------------------------------------- + + // Only one variable with index arg[1] + case AddpvOp: + case SubpvOp: + check_csum = cumulative_sum_op; + // + case DisOp: + case DivpvOp: + case MulpvOp: + case PowpvOp: + case ZmulpvOp: + CPPAD_ASSERT_UNKNOWN( NumRes(op) > 0 ); + if( use_result != usage_t(no_usage) ) + { size_t j_op = random_itr.var2op(size_t(arg[1])); + op_inc_arg_usage( + play, check_csum, i_op, j_op, op_usage, cexp_set + ); + } + break; // -------------------------------------------- + + // arg[0] and arg[1] are the only variables + case AddvvOp: + case SubvvOp: + check_csum = cumulative_sum_op; + // + case DivvvOp: + case MulvvOp: + case PowvvOp: + case ZmulvvOp: + CPPAD_ASSERT_UNKNOWN( NumRes(op) > 0 ); + if( use_result != usage_t(no_usage) ) + { for(size_t i = 0; i < 2; i++) + { size_t j_op = random_itr.var2op(size_t(arg[i])); + op_inc_arg_usage( + play, check_csum, i_op, j_op, op_usage, cexp_set + ); + } + } + break; // -------------------------------------------- + + // Conditional expression operators + // arg[2], arg[3], arg[4], arg[5] are parameters or variables + case CExpOp: + CPPAD_ASSERT_UNKNOWN( NumRes(op) > 0 ); + if( conditional_skip ) + { --cexp_index; + cexp2op[ cexp_index ] = addr_t(i_op); + } + if( use_result != usage_t(no_usage) ) + { CPPAD_ASSERT_UNKNOWN( NumArg(CExpOp) == 6 ); + // propgate from result to left argument + if( arg[1] & 1 ) + { size_t j_op = random_itr.var2op(size_t(arg[2])); + op_inc_arg_usage( + play, check_csum, i_op, j_op, op_usage, cexp_set + ); + } + // propgate from result to right argument + if( arg[1] & 2 ) + { size_t j_op = random_itr.var2op(size_t(arg[3])); + op_inc_arg_usage( + play, check_csum, i_op, j_op, op_usage, cexp_set + ); + } + // are if_true and if_false cases the same variable + bool same_variable = (arg[1] & 4) != 0; + same_variable &= (arg[1] & 8) != 0; + same_variable &= arg[4] == arg[5]; + // + // if_true + if( arg[1] & 4 ) + { size_t j_op = random_itr.var2op(size_t(arg[4])); + bool can_skip = conditional_skip & (! same_variable); + can_skip &= op_usage[j_op] == usage_t(no_usage); + op_inc_arg_usage( + play, check_csum, i_op, j_op, op_usage, cexp_set + ); + if( can_skip ) + { // j_op corresponds to the value used when the + // comparison result is true. It can be skipped when + // the comparison is false (0). + size_t element = 2 * cexp_index + 0; + cexp_set.post_element(j_op, element); + // + op_usage[j_op] = usage_t(yes_usage); + } + } + // + // if_false + if( arg[1] & 8 ) + { size_t j_op = random_itr.var2op(size_t(arg[5])); + bool can_skip = conditional_skip & (! same_variable); + can_skip &= op_usage[j_op] == usage_t(no_usage); + op_inc_arg_usage( + play, check_csum, i_op, j_op, op_usage, cexp_set + ); + if( can_skip ) + { // j_op corresponds to the value used when the + // comparison result is false. It can be skipped when + // the comparison is true (0). + size_t element = 2 * cexp_index + 1; + cexp_set.post_element(j_op, element); + // + op_usage[j_op] = usage_t(yes_usage); + } + } + } + break; // -------------------------------------------- + + // Operations that are never used + // (new CSkip options are generated if conditional_skip is true) + case CSkipOp: + case ParOp: + break; + + // Operators that are always used + case InvOp: + case BeginOp: + case EndOp: + op_usage[i_op] = usage_t(yes_usage); + break; // ----------------------------------------------- + + // The print forward operator + case PriOp: + CPPAD_ASSERT_NARG_NRES(op, 5, 0); + if( print_for_op ) + { op_usage[i_op] = usage_t(yes_usage); + if( arg[0] & 1 ) + { // arg[1] is a variable + size_t j_op = random_itr.var2op(size_t(arg[1])); + op_inc_arg_usage( + play, check_csum, i_op, j_op, op_usage, cexp_set + ); + } + if( arg[0] & 2 ) + { // arg[3] is a variable + size_t j_op = random_itr.var2op(size_t(arg[3])); + op_inc_arg_usage( + play, check_csum, i_op, j_op, op_usage, cexp_set + ); + } + } + break; // ----------------------------------------------------- + + // ============================================================= + // Comparison operators + // ============================================================= + + // Compare operators where arg[1] is only variable + case LepvOp: + case LtpvOp: + case EqpvOp: + case NepvOp: + CPPAD_ASSERT_UNKNOWN( NumRes(op) == 0 ); + if( compare_op ) + { op_usage[i_op] = usage_t(yes_usage); + // + size_t j_op = random_itr.var2op(size_t(arg[1])); + op_inc_arg_usage( + play, check_csum, i_op, j_op, op_usage, cexp_set + ); + } + break; // ---------------------------------------------- + + // Compare operators where arg[0] is only variable + case LevpOp: + case LtvpOp: + CPPAD_ASSERT_UNKNOWN( NumRes(op) == 0 ); + if( compare_op ) + { op_usage[i_op] = usage_t(yes_usage); + // + size_t j_op = random_itr.var2op(size_t(arg[0])); + op_inc_arg_usage( + play, check_csum, i_op, j_op, op_usage, cexp_set + ); + } + break; // ---------------------------------------------- + + // Compare operators where arg[0] and arg[1] are variables + case LevvOp: + case LtvvOp: + case EqvvOp: + case NevvOp: + CPPAD_ASSERT_UNKNOWN( NumRes(op) == 0 ); + if( compare_op ) + { op_usage[i_op] = usage_t(yes_usage); + // + for(size_t i = 0; i < 2; i++) + { size_t j_op = random_itr.var2op(size_t(arg[i])); + op_inc_arg_usage( + play, check_csum, i_op, j_op, op_usage, cexp_set + ); + } + } + break; // ---------------------------------------------- + + // ============================================================= + // VecAD operators + // ============================================================= + + // load operator using a parameter index + case LdpOp: + CPPAD_ASSERT_UNKNOWN( NumRes(op) > 0 ); + if( use_result != usage_t(no_usage) ) + { size_t i_vec = arg2vecad[ arg[0] ]; + vecad_used[i_vec] = true; + } + break; // -------------------------------------------- + + // load operator using a variable index + case LdvOp: + CPPAD_ASSERT_UNKNOWN( NumRes(op) > 0 ); + if( use_result != usage_t(no_usage) ) + { size_t i_vec = arg2vecad[ arg[0] ]; + vecad_used[i_vec] = true; + // + size_t j_op = random_itr.var2op(size_t(arg[1])); + op_usage[j_op] = usage_t(yes_usage); + } + break; // -------------------------------------------- + + // Store a variable using a parameter index + case StpvOp: + CPPAD_ASSERT_UNKNOWN( NumRes(op) == 0 ); + if( vecad_used[ arg2vecad[ arg[0] ] ] ) + { op_usage[i_op] = usage_t(yes_usage); + // + size_t j_op = random_itr.var2op(size_t(arg[2])); + op_usage[j_op] = usage_t(yes_usage); + } + break; // -------------------------------------------- + + // Store a variable using a variable index + case StvvOp: + CPPAD_ASSERT_UNKNOWN( NumRes(op) == 0 ); + if( vecad_used[ arg2vecad[ arg[0] ] ] ) + { op_usage[i_op] = usage_t(yes_usage); + // + size_t j_op = random_itr.var2op(size_t(arg[1])); + op_usage[j_op] = usage_t(yes_usage); + size_t k_op = random_itr.var2op(size_t(arg[2])); + op_usage[k_op] = usage_t(yes_usage); + } + break; // ----------------------------------------------------- + + // ============================================================= + // cumulative summation operator + // ============================================================ + case CSumOp: + CPPAD_ASSERT_UNKNOWN( NumRes(op) == 1 ); + { + for(size_t i = 5; i < size_t(arg[2]); i++) + { size_t j_op = random_itr.var2op(size_t(arg[i])); + op_inc_arg_usage( + play, check_csum, i_op, j_op, op_usage, cexp_set + ); + } + } + break; + + // ============================================================= + // user defined atomic operators + // ============================================================ + + case AFunOp: + // start or end atomic operation sequence + if( atom_state == end_atom ) + { // reverse_user using random_itr instead of play + atom_index = size_t(arg[0]); + atom_old = size_t(arg[1]); + atom_n = size_t(arg[2]); + atom_m = size_t(arg[3]); + atom_j = atom_n; + atom_i = atom_m; + atom_state = ret_atom; + // ------------------------------------------------------- + last_atom_i_op = i_op; + CPPAD_ASSERT_UNKNOWN( i_op > atom_n + atom_m + 1 ); + CPPAD_ASSERT_UNKNOWN( + op_usage[last_atom_i_op] == usage_t(no_usage) + ); +# ifndef NDEBUG + if( cexp_set.n_set() > 0 ) + { cexp_set.process_post(last_atom_i_op); + CPPAD_ASSERT_UNKNOWN( + cexp_set.number_elements(last_atom_i_op) == 0 + ); + } +# endif + // + atom_x.resize( atom_n ); + type_x.resize( atom_n ); + atom_ix.resize( atom_n ); + // + depend_y.resize( atom_m ); + depend_x.resize( atom_n ); + for(size_t i = 0; i < atom_m; i++) + depend_y[ i ] = false; + } + else + { // reverse_user using random_itr instead of play + CPPAD_ASSERT_UNKNOWN( atom_state == start_atom ); + CPPAD_ASSERT_UNKNOWN( atom_n == size_t(arg[2]) ); + CPPAD_ASSERT_UNKNOWN( atom_m == size_t(arg[3]) ); + CPPAD_ASSERT_UNKNOWN( atom_j == 0 ); + CPPAD_ASSERT_UNKNOWN( atom_i == 0 ); + atom_state = end_atom; + // ------------------------------------------------------- + CPPAD_ASSERT_UNKNOWN( + i_op + atom_n + atom_m + 1 == last_atom_i_op + ); + if( op_usage[last_atom_i_op] != usage_t(no_usage) ) + { // call atomic function for this operation + sweep::call_atomic_rev_depend( + atom_index, atom_old, atom_x, type_x, depend_x, depend_y + ); + for(size_t j = 0; j < atom_n; j++) + if( depend_x[j] ) + { // The parameter or variable correspnding to the j-th + // argument gets used + op_usage[i_op + 1 + j] = true; + if( type_x[j] == variable_enum ) + { CPPAD_ASSERT_UNKNOWN( atom_ix[j] > 0 ); + if( depend_x[j] ) + { size_t j_op = random_itr.var2op(atom_ix[j]); + op_inc_arg_usage(play, check_csum, + last_atom_i_op, j_op, op_usage, cexp_set + ); + } + } + } + } + // copy set infomation from last to first + if( cexp_set.n_set() > 0 ) + { cexp_set.process_post(last_atom_i_op); + cexp_set.assignment(i_op, last_atom_i_op, cexp_set); + } + // copy usage information from last to first + op_usage[i_op] = op_usage[last_atom_i_op]; + } + break; // ------------------------------------------------------- + + case FunapOp: + // parameter argument in an atomic operation sequence + CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) < num_par ); + // + // reverse_user using random_itr instead of play + CPPAD_ASSERT_NARG_NRES(op, 1, 0); + CPPAD_ASSERT_UNKNOWN( 0 < atom_j && atom_j <= atom_n ); + --atom_j; + if( atom_j == 0 ) + atom_state = start_atom; + // ------------------------------------------------------------- + atom_ix[atom_j] = 0; + // + // parameter arguments + atom_x[atom_j] = parameter[arg[0]]; + if( play->dyn_par_is()[arg[0]] ) + type_x[atom_j] = dynamic_enum; + else + type_x[atom_j] = constant_enum; + // + break; + + case FunavOp: + // variable argument in an atomic operation sequence + CPPAD_ASSERT_UNKNOWN( 0 < arg[0] ); + // + // reverse_user using random_itr instead of play + CPPAD_ASSERT_NARG_NRES(op, 1, 0); + CPPAD_ASSERT_UNKNOWN( 0 < atom_j && atom_j <= atom_n ); + --atom_j; + if( atom_j == 0 ) + atom_state = start_atom; + // ------------------------------------------------------------- + atom_ix[atom_j] = size_t(arg[0]); + // + // variable arguments as parameters + atom_x[atom_j] = CppAD::numeric_limits::quiet_NaN(); + type_x[atom_j] = variable_enum; + // + break; + + case FunrvOp: + // variable result in an atomic operation sequence + // + // reverse_user using random_itr instead of play + CPPAD_ASSERT_NARG_NRES(op, 0, 1); + CPPAD_ASSERT_UNKNOWN( 0 < atom_i && atom_i <= atom_m ); + --atom_i; + if( atom_i == 0 ) + atom_state = arg_atom; + // ------------------------------------------------------------- + if( use_result ) + { depend_y[atom_i] = true; + op_inc_arg_usage( + play, check_csum, i_op, last_atom_i_op, op_usage, cexp_set + ); + } + break; // -------------------------------------------------------- + + case FunrpOp: + CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) < num_par ); + // + // reverse_user using random_itr instead of play + CPPAD_ASSERT_NARG_NRES(op, 1, 0); + CPPAD_ASSERT_UNKNOWN( 0 < atom_i && atom_i <= atom_m ); + --atom_i; + if( atom_i == 0 ) + atom_state = arg_atom; + break; + // ============================================================ + + // all cases should be handled above + default: + CPPAD_ASSERT_UNKNOWN(0); + } + } + return; +} + +} } } // END_CPPAD_LOCAL_OPTIMIZE_NAMESPACE + +# endif diff --git a/build-config/cppad/include/cppad/local/optimize/get_par_usage.hpp b/build-config/cppad/include/cppad/local/optimize/get_par_usage.hpp new file mode 100644 index 00000000..64539716 --- /dev/null +++ b/build-config/cppad/include/cppad/local/optimize/get_par_usage.hpp @@ -0,0 +1,506 @@ +# ifndef CPPAD_LOCAL_OPTIMIZE_GET_PAR_USAGE_HPP +# define CPPAD_LOCAL_OPTIMIZE_GET_PAR_USAGE_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ +/*! +\file get_cexp_info.hpp +Create operator information tables +*/ +# include + +// BEGIN_CPPAD_LOCAL_OPTIMIZE_NAMESPACE +namespace CppAD { namespace local { namespace optimize { + +/*! +$begin optimize_get_par_usage$$ +$spell + Addr + iterator + itr + op + num + var + vecad + Vec + Ind +$$ + +$section Use Reverse Activity Analysis to Get Usage for Each Parameter$$ + +$head Prototype$$ +$srcthisfile% + 0%// BEGIN_GET_PAR_USAGE%// END_PROTOTYPE%1 +%$$ + +$head Base$$ +Base type for the operator; i.e., this operation was recorded +using $codei%AD<%Base%>%$$ +and computations by this routine are done using type $icode Base$$. + +$head Addr$$ +Type used by random iterator for the player. + +$head play$$ +This is the operation sequence. + +$head random_itr$$ +This is a random iterator for the operation sequence. + +$head op_usage$$ +This argument has size equal to the number of operators +in the operation sequence; i.e., num_op = play->nun_var_rec(). +The value $icode%op_usage%[%i%]%$$ have been set to the usage for +the i-th operator in the operation sequence. + +$head vecad_used$$ +This argument has size equal to the number of VecAD vectors +in the operations sequences; i.e., play->num_var_vecad_rec(). +The VecAD vectors are indexed in the order that their indices appear +in the one large play->GetVecInd that holds all the VecAD vectors. + +$head par_usage$$ +The input size of this vector must be zero. +Upon return it has size equal to the number of parameters +in the operation sequence; i.e., play->num_par_rec(); +The value $icode%par_usage%[%i%]%$$ is true if an only if +the i-th parameter is used to compute a dependent variable +or parameter. +The nan at the beginning of the parameter vector +and the independent dynamic parameters are always used. + +$end +*/ + +// BEGIN_GET_PAR_USAGE +template +void get_par_usage( + const player* play , + const play::const_random_iterator& random_itr , + const pod_vector& op_usage , + pod_vector& vecad_used , + pod_vector& par_usage ) +// END_PROTOTYPE +{ + CPPAD_ASSERT_UNKNOWN( op_usage.size() == play->num_op_rec() ); + CPPAD_ASSERT_UNKNOWN( par_usage.size() == 0 ); + // + // number of operators in the tape + const size_t num_op = play->num_op_rec(); + // + // number of parameters in the tape + const size_t num_par = play->num_par_rec(); + // + // number of dynamic parameters + const size_t num_dynamic_par = play->num_dynamic_par(); + // + // number of independent dynamic parameters + size_t num_dynamic_ind = play->num_dynamic_ind(); + // + // number of VecAD vectors + size_t num_vecad_vec = play->num_var_vecad_rec(); + // + // dynamic parameter information + const pod_vector& dyn_par_is( play->dyn_par_is() ); + const pod_vector& dyn_par_op( play->dyn_par_op() ); + const pod_vector& dyn_par_arg( play->dyn_par_arg() ); + const pod_vector& dyn_ind2par_ind( play->dyn_ind2par_ind() ); + const pod_vector_maybe& all_par_vec( play->all_par_vec() ); + // ----------------------------------------------------------------------- + // initialize par_usage + par_usage.resize(num_par); + par_usage[0] = true; // true for nan at beginning of parameter vector + for(size_t i_par = 1; i_par <= num_dynamic_ind; ++i_par) + par_usage[i_par] = true; // true for independent dynamic parameters + for(size_t i_par = num_dynamic_ind+1; i_par < num_par; ++i_par) + par_usage[i_par] = false; // initialize as false for other parameters + // + // ----------------------------------------------------------------------- + // set usage to true for VecAD parameters that get used + size_t start_this_vector = 0; + for(size_t i_vec = 0; i_vec < num_vecad_vec; ++i_vec) + { // length of this vector (note length is not a parameter) + size_t length = play->GetVecInd(start_this_vector); + // + if( vecad_used[i_vec] ) + { // this vector gets used + for(size_t k = 1; k <= length; ++k) + { // index of parameter used by this VecAD vector + size_t i_par = play->GetVecInd(start_this_vector + k); + // must not be a dynamic parameter + CPPAD_ASSERT_UNKNOWN( ! dyn_par_is[i_par] ); + // set usage for this parameter + par_usage[i_par] = true; + } + } + start_this_vector += length + 1; + } + CPPAD_ASSERT_UNKNOWN( start_this_vector == play->num_var_vecad_ind_rec() ); + // + // ----------------------------------------------------------------------- + // forward pass to mark which parameters are used by necessary operators + // ----------------------------------------------------------------------- + // + // information about atomic function calls + size_t atom_index=0, atom_old=0, atom_m=0, atom_n=0, atom_i=0, atom_j=0; + enum_atom_state atom_state = start_atom; + // + // work space used by user atomic functions + vector parameter_x; // value of parameters in x + vector type_x; // type for each component of z + vector atom_ix; // variables indices for argument vector + vector depend_y; // results that are used + vector depend_x; // arguments that are used + // + for(size_t i_op = 0; i_op < num_op; ++i_op) + { + // information about current operator + OpCode op; // operator + const addr_t* arg; // arguments + size_t i_var; // variable index of first result + random_itr.op_info(i_op, op, arg, i_var); + // + bool skip = op_usage[i_op] == usage_t(no_usage); + skip &= atom_state == start_atom; + if( ! skip ) switch( op ) + { + // add or subtract with left a parameter and right a variable + case AddpvOp: + case SubpvOp: + if( dyn_par_is[ arg[0] ] ) + par_usage[ arg[0] ] = true; + else + { // determine if this parameter will be absorbed by csum + if( ! (op_usage[i_op] == csum_usage) ) + { // determine operator corresponding to variable + size_t j_op = random_itr.var2op(size_t(arg[1])); + CPPAD_ASSERT_UNKNOWN( op_usage[j_op] != no_usage ); + if( op_usage[j_op] != csum_usage ) + par_usage[ arg[0] ] = true; + } + } + break; + + // subtract with left a variable and right a parameter + case SubvpOp: + if( dyn_par_is[ arg[1] ] ) + par_usage[ arg[1] ] = true; + else + { // determine if this parameter will be absorbed by csum + if( ! (op_usage[i_op] == csum_usage) ) + { // determine operator corresponding to variable + size_t j_op = random_itr.var2op(size_t(arg[0])); + CPPAD_ASSERT_UNKNOWN( op_usage[j_op] != no_usage ); + if( op_usage[j_op] != csum_usage ) + par_usage[ arg[1] ] = true; + } + } + break; + + + + // cases with no parameter arguments + case AbsOp: + case AcosOp: + case AcoshOp: + case AddvvOp: + case AsinOp: + case AsinhOp: + case AtanOp: + case AtanhOp: + case BeginOp: + case CosOp: + case CoshOp: + case CSkipOp: + case DisOp: + case DivvvOp: + case EndOp: + case EqvvOp: + case ExpOp: + case Expm1Op: + case InvOp: + case LdvOp: + case LevvOp: + case LogOp: + case Log1pOp: + case LtvvOp: + case MulvvOp: + case NevvOp: + case PowvvOp: + case SignOp: + case SinOp: + case SinhOp: + case SqrtOp: + case StvvOp: + case SubvvOp: + case TanOp: + case TanhOp: + case ZmulvvOp: + break; + + // cases where first and second arguments are parameters + case EqppOp: + case LeppOp: + case LtppOp: + case NeppOp: + CPPAD_ASSERT_UNKNOWN( 2 <= NumArg(op) ) + par_usage[arg[0]] = true; + par_usage[arg[1]] = true; + break; + + + // cases where only first argument is a parameter + case CSumOp: + case EqpvOp: + case DivpvOp: + case LepvOp: + case LtpvOp: + case MulpvOp: + case NepvOp: + case ParOp: + case PowpvOp: + case ZmulpvOp: + CPPAD_ASSERT_UNKNOWN( 1 <= NumArg(op) || op == CSumOp ) + par_usage[arg[0]] = true; + break; + + // cases where only second argument is a parameter + case DivvpOp: + case LevpOp: + case LdpOp: + case LtvpOp: + case PowvpOp: + case StpvOp: + case ZmulvpOp: + CPPAD_ASSERT_UNKNOWN( 2 <= NumArg(op) ) + par_usage[arg[1]] = true; + break; + + // cases where second and thrid arguments are parameters + case ErfOp: + case ErfcOp: + case StppOp: + CPPAD_ASSERT_UNKNOWN( 3 <= NumArg(op) ) + par_usage[arg[1]] = true; + par_usage[arg[2]] = true; + break; + + // cases where only third argument is a parameter + case StvpOp: + CPPAD_ASSERT_UNKNOWN( 3 <= NumArg(op) ) + par_usage[arg[2]] = true; + break; + + // conditional expression operator + case CExpOp: + CPPAD_ASSERT_UNKNOWN( 6 == NumArg(op) ) + if( (arg[1] & 1) == 0 ) + par_usage[arg[2]] = true; + if( (arg[1] & 2) == 0 ) + par_usage[arg[3]] = true; + if( (arg[1] & 4) == 0 ) + par_usage[arg[4]] = true; + if( (arg[1] & 8) == 0 ) + par_usage[arg[5]] = true; + break; + + // print function + case PriOp: + if( (arg[0] & 1) == 0 ) + par_usage[arg[1]] = true; + if( (arg[0] & 2) == 0 ) + par_usage[arg[3]] = true; + CPPAD_ASSERT_UNKNOWN( 5 == NumArg(op) ) + break; + + // -------------------------------------------------------------- + // atomic function calls + case AFunOp: + if( atom_state == start_atom ) + { atom_index = size_t(arg[0]); + atom_old = size_t(arg[1]); + atom_n = size_t(arg[2]); + atom_m = size_t(arg[3]); + atom_j = 0; + atom_i = 0; + atom_state = arg_atom; + // ------------------------------------------------------- + parameter_x.resize( atom_n ); + type_x.resize( atom_n ); + atom_ix.resize( atom_n ); + // + depend_y.resize( atom_m ); + depend_x.resize( atom_n ); + } + else + { CPPAD_ASSERT_UNKNOWN( atom_state == end_atom ); + CPPAD_ASSERT_UNKNOWN( atom_n == size_t(arg[2]) ); + CPPAD_ASSERT_UNKNOWN( atom_m == size_t(arg[3]) ); + CPPAD_ASSERT_UNKNOWN( atom_j == atom_n ); + CPPAD_ASSERT_UNKNOWN( atom_i == atom_m ); + atom_state = start_atom; + // + // call atomic function for this operation + sweep::call_atomic_rev_depend( + atom_index, atom_old, parameter_x, type_x, depend_x, depend_y + ); + for(size_t j = 0; j < atom_n; j++) + if( depend_x[j] && type_x[j] != variable_enum ) + { // This user argument is a parameter that is needed + + CPPAD_ASSERT_UNKNOWN( atom_ix[j] > 0 ); + par_usage[ atom_ix[j] ] = true; + } + } + break; + + case FunavOp: + // this argument is a variable + CPPAD_ASSERT_UNKNOWN( atom_state == arg_atom ); + atom_ix[atom_j] = 0; + parameter_x[atom_j] = all_par_vec[0]; // variables get value nan + type_x[atom_j] = variable_enum; + ++atom_j; + if( atom_j == atom_n ) + atom_state = ret_atom; + break; + + case FunapOp: + // this argument is a parameter + CPPAD_ASSERT_UNKNOWN( atom_state == arg_atom ); + atom_ix[atom_j] = size_t( arg[0] ); + parameter_x[atom_j] = all_par_vec[arg[0]]; // parameter value + if( dyn_par_is[arg[0]] ) + type_x[atom_j] = dynamic_enum; + else + type_x[atom_j] = dynamic_enum; + ++atom_j; + if( atom_j == atom_n ) + atom_state = ret_atom; + break; + + case FunrpOp: + // this result is a parameter + CPPAD_ASSERT_UNKNOWN( atom_state == ret_atom ); + depend_y[atom_i] = op_usage[i_op] != usage_t(no_usage); + ++atom_i; + if( atom_i == atom_m ) + atom_state = end_atom; + break; + + case FunrvOp: + // this result is a variable + CPPAD_ASSERT_UNKNOWN( atom_state == ret_atom ); + depend_y[atom_i] = op_usage[i_op] != usage_t(no_usage); + ++atom_i; + if( atom_i == atom_m ) + atom_state = end_atom; + break; + // -------------------------------------------------------------- + + + default: + CPPAD_ASSERT_UNKNOWN(false); + } + } + // ----------------------------------------------------------------------- + // reverse pass to determine which dynamic parameters are necessary + // ----------------------------------------------------------------------- + size_t i_arg = dyn_par_arg.size(); // index in dyn_par_arg + size_t i_dyn = num_dynamic_par; // index in dyn_ind2par_ind + while(i_dyn) + { // next dynamic parameter in reverse order + --i_dyn; + op_code_dyn op = op_code_dyn( dyn_par_op[i_dyn] ); + while( op == result_dyn ) + { --i_dyn; + op = op_code_dyn( dyn_par_op[i_dyn] ); + CPPAD_ASSERT_UNKNOWN( op == result_dyn || op == atom_dyn ); + } + if( op == atom_dyn ) + { // number of arguments for this operator + size_t n_arg = size_t( dyn_par_arg[i_arg - 1] ); + // + // index of first argument for this operation + i_arg -= n_arg; + // + atom_index = size_t( dyn_par_arg[i_arg + 0] ); + size_t n = size_t( dyn_par_arg[i_arg + 1] ); + size_t m = size_t( dyn_par_arg[i_arg + 2] ); + CPPAD_ASSERT_UNKNOWN( n_arg == 5 + n + m ); + // + // parameter_x, type_x + parameter_x.resize(n); + type_x.resize(n); + for(size_t j = 0; j < n; ++j) + { // parameter index zero is used for variable + CPPAD_ASSERT_UNKNOWN( isnan( all_par_vec[0] ) ); + addr_t arg_j = dyn_par_arg[i_arg + 4 + j]; + parameter_x[j] = all_par_vec[arg_j]; + if( arg_j == 0 ) + type_x[j] = variable_enum; + else if( dyn_par_is[arg_j] ) + type_x[j] = dynamic_enum; + else + type_x[j] = constant_enum; + } + // + // depend_y + depend_y.resize(m); + for(size_t i = 0; i < m; ++i) + { // a constant prameter cannot depend on a dynamic parameter + // so do not worry about constant parameters in depend_y + size_t i_par = size_t( dyn_par_arg[i_arg + 4 + n + i] ); + depend_y[i] = par_usage[i_par]; + } + // + // call back to atomic function for this operation + depend_x.resize(n); + atom_old = 0; // not used with dynamic parameters + sweep::call_atomic_rev_depend( + atom_index, atom_old, parameter_x, type_x, depend_x, depend_y + ); + // + // transfer depend_x to par_usage + for(size_t j = 0; j < n; ++j) + { size_t i_par = size_t( dyn_par_arg[i_arg + 4 + j] ); + par_usage[i_par] = par_usage[i_par] | depend_x[j]; + } + } + else + { // corresponding parameter index + size_t i_par = size_t( dyn_ind2par_ind[i_dyn] ); + CPPAD_ASSERT_UNKNOWN( dyn_par_is[i_par] ); + // + // number of argumens to this operator + size_t n_arg = num_arg_dyn(op); + // + // index of first argument for this operator + CPPAD_ASSERT_UNKNOWN( op != atom_dyn ); + i_arg -= n_arg; + // + // if this dynamic parameter is needed + if( par_usage[i_par] ) + { // need dynamic parameters that are used to generate this one + size_t offset = num_non_par_arg_dyn(op); + for(size_t i = offset; i < n_arg; ++i) + par_usage[ dyn_par_arg[i_arg + i] ] = true; + } + } + } + CPPAD_ASSERT_UNKNOWN( i_arg == 0 ); + // + return; +} + +} } } // END_CPPAD_LOCAL_OPTIMIZE_NAMESPACE + +# endif diff --git a/build-config/cppad/include/cppad/local/optimize/hash_code.hpp b/build-config/cppad/include/cppad/local/optimize/hash_code.hpp new file mode 100644 index 00000000..812ca4bc --- /dev/null +++ b/build-config/cppad/include/cppad/local/optimize/hash_code.hpp @@ -0,0 +1,57 @@ +# ifndef CPPAD_LOCAL_OPTIMIZE_HASH_CODE_HPP +# define CPPAD_LOCAL_OPTIMIZE_HASH_CODE_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ +/*! +\file local/optimize/hash_code.hpp +CppAD hashing utility. +*/ + + +// BEGIN_CPPAD_LOCAL_OPTIMIZE_NAMESPACE +namespace CppAD { namespace local { namespace optimize { +/*! +Specialized hash code for a CppAD operator and its arguments +(used during optimization). + +\param op +is the operator that we are computing a hash code for. + +\param num_arg +number of elements of arg to include in the hash code. + +\param arg +is a vector of length num_arg +containing the corresponding argument indices for this operator. + +\return +is a hash code that is between zero and CPPAD_HASH_TABLE_SIZE - 1. +*/ + +inline size_t optimize_hash_code( + opcode_t op , + size_t num_arg , + const addr_t* arg ) +{ CPPAD_ASSERT_UNKNOWN( num_arg < 4 ); + size_t prime = 1; + size_t sum = prime * size_t(op); + for(size_t i = 0; i < num_arg; i++) + { prime = prime + 2; // 3, 5, 7 in that order + sum += prime * size_t(arg[i]); + } + // + return sum % CPPAD_HASH_TABLE_SIZE; +} + +} } } // END_CPPAD_LOCAL_OPTIMIZE_NAMESPACE + +# endif diff --git a/build-config/cppad/include/cppad/local/optimize/match_op.hpp b/build-config/cppad/include/cppad/local/optimize/match_op.hpp new file mode 100644 index 00000000..b053e279 --- /dev/null +++ b/build-config/cppad/include/cppad/local/optimize/match_op.hpp @@ -0,0 +1,292 @@ +# ifndef CPPAD_LOCAL_OPTIMIZE_MATCH_OP_HPP +# define CPPAD_LOCAL_OPTIMIZE_MATCH_OP_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ +# include +// BEGIN_CPPAD_LOCAL_OPTIMIZE_NAMESPACE +namespace CppAD { namespace local { namespace optimize { +/* +$begin optimize_match_op$$ + +$section Search for a Previous Operator that Matches Current Operator$$ +$spell + op + itr + bool + addr + erf + erfc + iterator +$$ + +$head Syntax$$ +$codei%exceed_collision_limit% = match_op( + %collision_limit%, + %random_itr%, + %op_previous%, + %current%, + %hash_tape_op%, + %work_bool%, + %work_addr_t% +)%$$ + +$head Prototype$$ +$srcthisfile% + 0%// BEGIN_PROTOTYPE%// END_PROTOTYPE%1 +%$$ + +$head Operator Arguments$$ +If an argument for the current operator is a variable, +and the argument has previous match, +the previous match for the argument is used when checking for a match +for the current operator. + +$head collision_limit$$ +is the maximum number of collisions (matches) allowed for one +expression hash code value. + +$head random_itr$$ +is a random iterator for the old operation sequence. + +$head op_previous$$ +Mapping from operator index to previous operator that can replace this one. +The input value of +$codei% + %previous% = %op_previous%[%current%] +%$$ +is assumed to be zero. If a match if found, the output value of +$icode previous$$ is set to the matching operator index, +otherwise it is left as is. Note that $icode%previous% < %current%$$ +and $icode%op_previous[%previous%]%$$ is zero. + +$head current$$ +is the index of the current operator which cannot be any of the +operators in the list below: +$srcthisfile% + 0%// BEGIN_INVALID_OP%// END_INVALID_OP%1 +%$$ +After this initialization, the value of $icode current$$ +increases with each call to match_op. + +$subhead erf$$ +The operators $code ErfOp$$ and $code ErfcOp$$ have +three arguments, but only one true argument (the others are always the same). + + +$head hash_table_op$$ +is assumed to be initialized as a vector of empty sets before the +first call to match_op (for a pass of the operation sequence). +$codei% + %hash_table_op%.n_set() == CPPAD_HASH_TABLE_SIZE + %hash_table_op%.end() == %op_previous%.size() +%$$ +If $icode i_op$$ is an element of the j-th set, +then the operation $icode%op_previous%[%i_op%]%$$ has hash code j, +and does not match any other element of the j-th set. +An entry to j-th set for the current operator is added each time +match_op is called and a match for the current operator is not found. + +$head work_bool$$ +work space that is used by match_op between calls to increase speed. +Should be empty on first call for this forward pass of the operation +sequence and not modified until forward pass is done + +$head work_addr_t$$ +work space that is used by match_op between calls to increase speed. +Should be empty on first call for this forward pass of the operation +sequence and not modified until forward pass is done + +$head exceed_collision_limit$$ +If the $icode collision_limit$$ is exceeded (is not exceeded), +the return value is true (false). + +$end +*/ +// BEGIN_PROTOTYPE +template +bool match_op( + size_t collision_limit , + const play::const_random_iterator& random_itr , + pod_vector& op_previous , + size_t current , + sparse::list_setvec& hash_table_op , + pod_vector& work_bool , + pod_vector& work_addr_t ) +// END_PROTOTYPE +{ +# ifndef NDEBUG + switch( random_itr.get_op(current) ) + { + // BEGIN_INVALID_OP + case BeginOp: + case CExpOp: + case CSkipOp: + case CSumOp: + case EndOp: + case InvOp: + case LdpOp: + case LdvOp: + case ParOp: + case PriOp: + case StppOp: + case StpvOp: + case StvpOp: + case StvvOp: + case AFunOp: + case FunapOp: + case FunavOp: + case FunrpOp: + case FunrvOp: + // END_INVALID_OP + CPPAD_ASSERT_UNKNOWN(false); + break; + + default: + break; + } +# endif + // initialize return value + bool exceed_collision_limit = false; + // num_op + size_t num_op = random_itr.num_op(); + // + // num_var + size_t num_var = random_itr.num_var(); + // + // variable is a reference to, and better name for, work_bool + pod_vector& variable(work_bool); + // + // var2previous_var is a reference to, and better name for, work_addr_t + pod_vector& var2previous_var(work_addr_t); + if( var2previous_var.size() == 0 ) + { var2previous_var.resize(num_var); + for(size_t i = 0; i < num_var; ++i) + var2previous_var[i] = addr_t(i); + } + // + CPPAD_ASSERT_UNKNOWN( var2previous_var.size() == num_var ); + CPPAD_ASSERT_UNKNOWN( num_op == op_previous.size() ); + CPPAD_ASSERT_UNKNOWN( op_previous[current] == 0 ); + CPPAD_ASSERT_UNKNOWN( + hash_table_op.n_set() == CPPAD_HASH_TABLE_SIZE + ); + CPPAD_ASSERT_UNKNOWN( hash_table_op.end() == num_op ); + CPPAD_ASSERT_UNKNOWN( current < num_op ); + // + // op, arg, i_var + OpCode op; + const addr_t* arg; + size_t i_var; + random_itr.op_info(current, op, arg, i_var); + // + // num_arg + size_t num_arg = NumArg(op); + CPPAD_ASSERT_UNKNOWN( 0 < num_arg ); + CPPAD_ASSERT_UNKNOWN( + (num_arg < 3) | ( (num_arg == 3) & (op == ErfOp || op == ErfcOp) ) + ); + // + arg_is_variable(op, arg, variable); + CPPAD_ASSERT_UNKNOWN( variable.size() == num_arg ); + // + // If j-th argument to this operator is a variable, and a previous + // variable will be used in its place, use the previous variable for + // hash coding and matching. + addr_t arg_match[] = { + // Invalid value that will not be used. This initialization avoid + // a wraning on some compilers + std::numeric_limits::max(), + std::numeric_limits::max(), + std::numeric_limits::max() + }; + if( (op == AddvvOp) | (op == MulvvOp ) ) + { // in special case where operator is commutative and operands are variables, + // put lower index first so hash code does not depend on operator order + CPPAD_ASSERT_UNKNOWN( num_arg == 2 ); + arg_match[0] = var2previous_var[ arg[0] ]; + arg_match[1] = var2previous_var[ arg[1] ]; + if( arg_match[1] < arg_match[0] ) + std::swap( arg_match[0], arg_match[1] ); + } + else for(size_t j = 0; j < num_arg; ++j) + { arg_match[j] = arg[j]; + if( variable[j] ) + arg_match[j] = var2previous_var[ arg[j] ]; + } + + // + size_t code = optimize_hash_code(opcode_t(op), num_arg, arg_match); + // + // iterator for the set with this hash code + sparse::list_setvec_const_iterator itr(hash_table_op, code); + // + // check for a match + size_t count = 0; + while( *itr != num_op ) + { ++count; + // + // candidate previous for current operator + size_t candidate = *itr; + CPPAD_ASSERT_UNKNOWN( candidate < current ); + CPPAD_ASSERT_UNKNOWN( op_previous[candidate] == 0 ); + // + OpCode op_c; + const addr_t* arg_c; + size_t i_var_c; + random_itr.op_info(candidate, op_c, arg_c, i_var_c); + // + // check for a match + bool match = op == op_c; + size_t j = 0; + while( match & (j < num_arg) ) + { if( variable[j] ) + match &= arg_match[j] == var2previous_var[ arg_c[j] ]; + else + match &= arg_match[j] == arg_c[j]; + ++j; + } + if( (! match) & ( (op == AddvvOp) | (op == MulvvOp) ) ) + { // communative so check for reverse order match + match = op == op_c; + match &= arg_match[0] == var2previous_var[ arg_c[1] ]; + match &= arg_match[1] == var2previous_var[ arg_c[0] ]; + } + if( match ) + { op_previous[current] = static_cast( candidate ); + if( NumRes(op) > 0 ) + { CPPAD_ASSERT_UNKNOWN( i_var_c < i_var ); + var2previous_var[i_var] = addr_t( i_var_c ); + } + return exceed_collision_limit; + } + ++itr; + } + + // see print (that is commented out) at bottom of get_op_previous.hpp + CPPAD_ASSERT_UNKNOWN( count <= collision_limit ); + if( count == collision_limit ) + { // restart the list + hash_table_op.clear(code); + // limit has been exceeded + exceed_collision_limit = true; + } + // No match was found. Add this operator to the set for this hash code + // Not using post_element becasue we need to iterate for + // this code before adding another element for this code. + hash_table_op.add_element(code, current); + // + return exceed_collision_limit; +} + +} } } // END_CPPAD_LOCAL_OPTIMIZE_NAMESPACE + +# endif diff --git a/build-config/cppad/include/cppad/local/optimize/optimize_run.hpp b/build-config/cppad/include/cppad/local/optimize/optimize_run.hpp new file mode 100644 index 00000000..48aab64d --- /dev/null +++ b/build-config/cppad/include/cppad/local/optimize/optimize_run.hpp @@ -0,0 +1,1351 @@ +# ifndef CPPAD_LOCAL_OPTIMIZE_OPTIMIZE_RUN_HPP +# define CPPAD_LOCAL_OPTIMIZE_OPTIMIZE_RUN_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-21 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include + +// BEGIN_CPPAD_LOCAL_OPTIMIZE_NAMESPACE +namespace CppAD { namespace local { namespace optimize { + +/*! +$begin optimize_run$$ +$spell + dep_taddr + Addr + const + iterator + PriOp + optimizer +$$ + +$section Convert a player object to an optimized recorder object $$ + +$head Syntax$$ +$codei%exceed_collision_limit% = local::optimize::optimize_run( + %options%, %n%, %dep_taddr%, %play%, %rec% +)%$$ + +$head Prototype$$ +$srcthisfile% + 0%// BEGIN_PROTOTYPE%// END_PROTOTYPE%1 +%$$ + +$head Addr$$ +Type to use for array elements in $code const_random_iterator$$. + +$head Base$$ +Base type for the operator; i.e., this operation was recorded +using $codei%AD<%Base%>%$$ +and computations by this routine are done using type $icode Base$$. + +$head options$$ + +$subhead no_conditional_skip$$ +If this sub-string appears, +conditional skip operations will not be generated. +This may make the optimize routine use significantly less memory +and take significantly less time. + +$subhead no_compare_op$$ +If this sub-string appears, +then comparison operators will be removed from the optimized tape. +These operators are necessary for the $cref compare_change$$ feature to be +meaningful in the resulting recording. +On the other hand, they are not necessary and take extra time +when this feature is not needed. + +$subhead no_print_for_op$$ +If this sub-string appears, +then $cref printfor$$ operators $code PriOp$$ +will be removed from the optimized tape. +These operators are useful for reporting problems evaluating derivatives +at independent variable values different from those used to record a function. + +$subhead no_cumulative_sum_op$$ +If this sub-string appears, +no cumulative sum operations will be generated during the optimization; see +$cref optimize_cumulative_sum.cpp$$. + +$subhead collision_limit=value$$ +If this substring appears, +where $icode value$$ is a sequence of decimal digits, +the optimizer's hash code collision limit will be set to $icode value$$. +When the collision limit is exceeded, the expressions with that hash code +are removed and a new lists of expressions with that has code is started. +The larger $icode value$$, the more identical expressions the optimizer +can recognize, but the slower the optimizer may run. +The default for $icode value$$ is $code 10$$. + +$head n$$ +is the number of independent variables on the tape. + +$head dep_taddr$$ +On input this vector contains the indices for each of the dependent +variable values in the operation sequence corresponding to $icode play$$. +Upon return it contains the indices for the same variables but in +the operation sequence corresponding to $icode rec$$. + +$head play$$ +This is the operation sequence that we are optimizing. +It is $code const$$ except for the fact that +$icode%play%->setup_random ()%$$is called. + +$head rec$$ +The input contents of this recording must be empty; i.e., +it corresponds to directly after the default constructor. +Upon return, it contains an optimized version of the +operation sequence corresponding to $icode play$$. + +$head exceed_collision_limit$$ +If the $icode collision_limit$$ is exceeded (is not exceeded), +the return value is true (false). + +$childtable% + include/cppad/local/optimize/cexp_info.hpp% + include/cppad/local/optimize/get_cexp_info.hpp% + include/cppad/local/optimize/get_op_usage.hpp% + include/cppad/local/optimize/get_par_usage.hpp% + include/cppad/local/optimize/record_csum.hpp% + include/cppad/local/optimize/match_op.hpp% + include/cppad/local/optimize/get_op_previous.hpp +%$$ + +$end +*/ + +// BEGIN_PROTOTYPE +template +bool optimize_run( + const std::string& options , + size_t n , + pod_vector& dep_taddr , + player* play , + recorder* rec ) +// END_PROTOTYPE +{ bool exceed_collision_limit = false; + // + // check that recorder is empty + CPPAD_ASSERT_UNKNOWN( rec->num_op_rec() == 0 ); + // + // get a random iterator for this player + play->template setup_random(); + local::play::const_random_iterator random_itr = + play->template get_random(); + + bool conditional_skip = true; + bool compare_op = true; + bool print_for_op = true; + bool cumulative_sum_op = true; + size_t collision_limit = 10; + size_t index = 0; + while( index < options.size() ) + { while( index < options.size() && options[index] == ' ' ) + ++index; + std::string option; + while( index < options.size() && options[index] != ' ' ) + option += options[index++]; + if( option != "" ) + { if( option == "no_conditional_skip" ) + conditional_skip = false; + else if( option == "no_compare_op" ) + compare_op = false; + else if( option == "no_print_for_op" ) + print_for_op = false; + else if( option == "no_cumulative_sum_op" ) + cumulative_sum_op = false; + else if( option.substr(0, 16) == "collision_limit=" ) + { std::string value = option.substr(16, option.size()); + bool value_ok = value.size() > 0; + for(size_t i = 0; i < value.size(); ++i) + { value_ok &= '0' <= value[i]; + value_ok &= value[i] <= '9'; + } + if( ! value_ok ) + { option += " value is not a sequence of decimal digits"; + CPPAD_ASSERT_KNOWN( false , option.c_str() ); + } + collision_limit = size_t( std::atoi( value.c_str() ) ); + if( collision_limit < 1 ) + { option += " value must be greater than zero"; + CPPAD_ASSERT_KNOWN( false , option.c_str() ); + } + } + else + { option += " is not a valid optimize option"; + CPPAD_ASSERT_KNOWN( false , option.c_str() ); + } + } + } + // number of operators in the player + const size_t num_op = play->num_op_rec(); + CPPAD_ASSERT_UNKNOWN( + num_op < size_t( (std::numeric_limits::max)() ) + ); + + // number of variables in the player +# ifndef NDEBUG + const size_t num_var = play->num_var_rec(); +# endif + + // number of parameter in the player + const size_t num_par = play->num_par_rec(); + + // number of VecAD indices + size_t num_vecad_ind = play->num_var_vecad_ind_rec(); + + // number of VecAD vectors + size_t num_vecad_vec = play->num_var_vecad_rec(); + + // number of independent dynamic parameters + size_t num_dynamic_ind = play->num_dynamic_ind(); + + // number of dynamic parameters + size_t num_dynamic_par = play->num_dynamic_par(); + + // mapping from dynamic parameter index to paramemter index + const pod_vector& dyn_ind2par_ind( play->dyn_ind2par_ind() ); + + // number of dynamic parameters + CPPAD_ASSERT_UNKNOWN( num_dynamic_ind <= play->num_dynamic_par () ); + + // ----------------------------------------------------------------------- + // operator information + pod_vector cexp2op; + sparse::list_setvec cexp_set; + pod_vector vecad_used; + pod_vector op_usage; + get_op_usage( + conditional_skip, + compare_op, + print_for_op, + cumulative_sum_op, + play, + random_itr, + dep_taddr, + cexp2op, + cexp_set, + vecad_used, + op_usage + ); + pod_vector op_previous; + exceed_collision_limit |= get_op_previous( + collision_limit, + play, + random_itr, + cexp_set, + op_previous, + op_usage + ); + size_t num_cexp = cexp2op.size(); + CPPAD_ASSERT_UNKNOWN( conditional_skip || num_cexp == 0 ); + vector cexp_info; // struct_cexp_info not POD + sparse::list_setvec skip_op_true; + sparse::list_setvec skip_op_false; + // + if( cexp2op.size() > 0 ) get_cexp_info( + play, + random_itr, + op_previous, + op_usage, + cexp2op, + cexp_set, + cexp_info, + skip_op_true, + skip_op_false + ); + + // We no longer need cexp_set, and cexp2op, so free their memory + cexp_set.resize(0, 0); + cexp2op.clear(); + // ----------------------------------------------------------------------- + // dynamic parameter information + pod_vector par_usage; + get_par_usage( + play, + random_itr, + op_usage, + vecad_used, + par_usage + ); + pod_vector dyn_previous; + get_dyn_previous( + play , + random_itr , + par_usage , + dyn_previous + ); + // ----------------------------------------------------------------------- + + // conditional expression information + // + // Size of the conditional expression information structure. + // This is equal to the number of conditional expressions when + // conditional_skip is true, otherwise it is zero. + // + // sort the conditional expression information by max_left_right + // this is the conditional skip order + vector cskip_order(num_cexp); + if( num_cexp > 0 ) + { vector keys(num_cexp); + for(size_t i = 0; i < num_cexp; i++) + keys[i] = size_t( cexp_info[i].max_left_right ); + CppAD::index_sort(keys, cskip_order); + } + // initial index in conditional skip order + size_t cskip_order_next = 0; + // + // initialize index in conditional expression order + size_t cexp_next = 0; + + // mapping from conditional expression index to conditional skip + // information on new tape + pod_vector cskip_new(num_cexp); + // + // flag used to indicate that there is no conditional skip + // for this conditional expression + for(size_t i = 0; i < num_cexp; i++) + cskip_new[i].i_arg = 0; + // ======================================================================= + // Create new recording + // ======================================================================= + // + // dynamic parameter information in player + const pod_vector& dyn_par_is( play->dyn_par_is() ); + const pod_vector& dyn_par_op( play->dyn_par_op() ); + const pod_vector& dyn_par_arg( play->dyn_par_arg() ); + // + // start mapping from old parameter indices to new parameter indices + // for all parameters that get used. + pod_vector new_par( num_par ); + addr_t addr_t_max = (std::numeric_limits::max)(); + for(size_t i_par = 0; i_par < num_par; ++i_par) + new_par[i_par] = addr_t_max; // initialize as not used + // + // start new recording + CPPAD_ASSERT_UNKNOWN( rec->num_op_rec() == 0 ); + rec->set_num_dynamic_ind(num_dynamic_ind); + rec->set_abort_op_index(0); + rec->set_record_compare( compare_op ); + + // copy parameters with index 0 + CPPAD_ASSERT_UNKNOWN( ! dyn_par_is[0] && isnan( play->GetPar(0) ) ); + rec->put_con_par( play->GetPar(0) ); + new_par[0] = 0; + + // set new_par for the independent dynamic parameters + for(size_t i_par = 1; i_par <= num_dynamic_ind; i_par++) + { CPPAD_ASSERT_UNKNOWN( dyn_par_is[i_par] ); + addr_t i = rec->put_dyn_par(play->GetPar(i_par), ind_dyn); + CPPAD_ASSERT_UNKNOWN( size_t(i) == i_par ); + new_par[i_par] = i; + } + + // set new_par for the constant parameters that are used + for(size_t i_par = num_dynamic_ind + 1; i_par < num_par; ++i_par) + if( ! dyn_par_is[i_par] ) + { CPPAD_ASSERT_UNKNOWN( i_par == 0 || num_dynamic_ind < i_par ); + if( par_usage[i_par] ) + { // value of this parameter + Base par = play->GetPar(i_par); + new_par[i_par] = rec->put_con_par(par); + } + } + + // index corresponding to the parameter zero + addr_t zero_par_index = rec->put_con_par( Base(0) ); + + // set new_par for the dependent dynamic parameters + size_t i_dyn = num_dynamic_ind; // dynamic parmaeter index + size_t i_arg = 0; // dynamic parameter argument index + pod_vector arg_vec; + for(size_t i_par = num_dynamic_ind + 1; i_par < num_par; ++i_par) + if( dyn_par_is[i_par] ) + { // operator for this dynamic parameter + op_code_dyn op = op_code_dyn( dyn_par_op[i_dyn] ); + // + // number of arguments for this dynamic parameter + size_t n_arg = num_arg_dyn(op); + // + // number of dynamic parameter results for this operator + size_t n_dyn = 1; + // + if( op == atom_dyn ) + { size_t atom_index = size_t( dyn_par_arg[i_arg + 0] ); + size_t atom_n = size_t( dyn_par_arg[i_arg + 1] ); + size_t atom_m = size_t( dyn_par_arg[i_arg + 2] ); + n_dyn = size_t( dyn_par_arg[i_arg + 3] ); + n_arg = 5 + atom_n + atom_m; + // + // check if any dynamic parameter result for this operator is used + bool call_used = false; +# ifndef NDEBUG + bool found_i_par = false; + for(size_t i = 0; i < atom_m; ++i) + { size_t j_par = size_t( dyn_par_arg[i_arg + 4 + atom_n + i] ); + if( dyn_par_is[j_par] ) + { call_used |= par_usage[j_par]; + CPPAD_ASSERT_UNKNOWN( j_par == i_par || found_i_par ); + // j_par > i_par corresponds to result_dyn operator + CPPAD_ASSERT_UNKNOWN( j_par >= i_par ); + found_i_par |= j_par == i_par; + } + } + CPPAD_ASSERT_UNKNOWN( found_i_par ); +# else + for(size_t i = 0; i < atom_m; ++i) + { size_t j_par = size_t( dyn_par_arg[i_arg + 4 + atom_n + i] ); + if( dyn_par_is[j_par] ) + call_used |= par_usage[j_par]; + } +# endif + if( call_used ) + { arg_vec.resize(0); + arg_vec.push_back( addr_t( atom_index ) ); + arg_vec.push_back( addr_t( atom_n ) ); + arg_vec.push_back( addr_t( atom_m ) ); + arg_vec.push_back( addr_t( n_dyn ) ); + for(size_t j = 0; j < atom_n; ++j) + { addr_t arg_j = dyn_par_arg[i_arg + 4 + j]; + if( arg_j > 0 && par_usage[arg_j] ) + arg_vec.push_back( new_par[ arg_j ] ); + else + arg_vec.push_back(0); + } + bool first_dynamic_result = true; + for(size_t i = 0; i < atom_m; ++i) + { addr_t res_i = dyn_par_arg[i_arg + 4 + atom_n + i]; + CPPAD_ASSERT_UNKNOWN( dyn_par_is[res_i] || res_i == 0 ); + // + if( dyn_par_is[res_i] ) + { Base par = play->GetPar( size_t(res_i) ); + if( first_dynamic_result ) + { first_dynamic_result = false; + new_par[res_i] = rec->put_dyn_par(par, atom_dyn); + } + else + new_par[res_i] = rec->put_dyn_par(par, result_dyn); + arg_vec.push_back( new_par[res_i] ); + } + else + { // this result is a constant parameter + if( new_par[res_i] != addr_t_max ) + arg_vec.push_back( new_par[res_i] ); + else + { // this constant parameter is not used + arg_vec.push_back(0); // phantom parameter + } + } + } + arg_vec.push_back( addr_t(5 + atom_n + atom_m ) ); + rec->put_dyn_arg_vec( arg_vec ); + } + } + else if( par_usage[i_par] & (op != result_dyn) ) + { size_t j_dyn = size_t( dyn_previous[i_dyn] ); + if( j_dyn != num_dynamic_par ) + { size_t j_par = size_t( dyn_ind2par_ind[j_dyn] ); + CPPAD_ASSERT_UNKNOWN( j_par < i_par ); + new_par[i_par] = new_par[j_par]; + } + else + { + // value of this parameter + Base par = play->GetPar(i_par); + // + if( op == cond_exp_dyn ) + { // cond_exp_dyn + CPPAD_ASSERT_UNKNOWN( num_dynamic_ind <= i_par ); + CPPAD_ASSERT_UNKNOWN( n_arg == 5 ); + new_par[i_par] = rec->put_dyn_cond_exp( + par , // par + CompareOp( dyn_par_arg[i_arg + 0] ), // cop + new_par[ dyn_par_arg[i_arg + 1] ] , // left + new_par[ dyn_par_arg[i_arg + 2] ] , // right + new_par[ dyn_par_arg[i_arg + 3] ] , // if_true + new_par[ dyn_par_arg[i_arg + 4] ] // if_false + ); + } + else if( op == dis_dyn ) + { // dis_dyn + CPPAD_ASSERT_UNKNOWN( n_arg == 2 ); + new_par[i_par] = rec->put_dyn_par( + par , // par + op , // op + dyn_par_arg[i_arg + 0] , // index + new_par[ dyn_par_arg[i_arg + 1] ] // parameter + ); + } + else if( n_arg == 1 ) + { // cases with one argument + CPPAD_ASSERT_UNKNOWN( num_non_par_arg_dyn(op) == 0 ); + CPPAD_ASSERT_UNKNOWN( num_dynamic_ind <= i_par ); + new_par[i_par] = rec->put_dyn_par( par, op, + new_par[ dyn_par_arg[i_arg + 0] ] + ); + } + else if( n_arg == 2 ) + { // cases with two arguments + CPPAD_ASSERT_UNKNOWN( num_dynamic_ind <= i_par ); + CPPAD_ASSERT_UNKNOWN( num_non_par_arg_dyn(op) == 0 ); + new_par[i_par] = rec->put_dyn_par( par, op, + new_par[ dyn_par_arg[i_arg + 0] ], + new_par[ dyn_par_arg[i_arg + 1] ] + ); + } + else + { // independent dynamic parmaeter case + CPPAD_ASSERT_UNKNOWN( op == ind_dyn ) + CPPAD_ASSERT_UNKNOWN( i_par <= num_dynamic_ind ); + CPPAD_ASSERT_UNKNOWN( n_arg == 0 ); + new_par[i_par] = rec->put_dyn_par( par, op); + } + } + } + ++i_dyn; + i_arg += n_arg; + } + // ----------------------------------------------------------------------- + // There is an additional constant parameter for each cumulative summation + // (that does not have a corresponding old parameter index). + // ------------------------------------------------------------------------ + // initialize mapping from old VecAD index to new VecAD index + CPPAD_ASSERT_UNKNOWN( + size_t( (std::numeric_limits::max)() ) >= num_vecad_ind + ); + pod_vector new_vecad_ind(num_vecad_ind); + for(size_t i = 0; i < num_vecad_ind; i++) + new_vecad_ind[i] = addr_t( num_vecad_ind ); // invalid index + { + size_t j = 0; // index into the old set of indices + for(size_t i = 0; i < num_vecad_vec; i++) + { // length of this VecAD + size_t length = play->GetVecInd(j); + if( vecad_used[i] ) + { // Put this VecAD vector in new recording + CPPAD_ASSERT_UNKNOWN(length < num_vecad_ind); + new_vecad_ind[j] = rec->put_var_vecad_ind( addr_t(length) ); + for(size_t k = 1; k <= length; k++) new_vecad_ind[j+k] = + rec->put_var_vecad_ind( + new_par[ play->GetVecInd(j+k) ] + ); + } + // start of next VecAD + j += length + 1; + } + CPPAD_ASSERT_UNKNOWN( j == num_vecad_ind ); + } + + // temporary buffer for new argument values + addr_t new_arg[6]; + + // temporary work space used by record_csum + // (decalared here to avoid realloaction of memory) + struct_csum_stacks csum_work; + + // tempory used to hold a size_pair + struct_size_pair size_pair; + // + // Mapping from old operator index to new variable index, + // zero is invalid except for new_var[0]. + pod_vector new_var(num_op); + // + // Mapping from old operator index to new operator index will share + // memory with op_previous. Must get op_previous[i_op] for this operator + // before over writting it with new_op[i_op]. + pod_vector& new_op( op_previous ); + CPPAD_ASSERT_UNKNOWN( new_op.size() == num_op ); + // ------------------------------------------------------------- + // information for current operator + size_t i_op; // index + OpCode op; // operator + const addr_t* arg; // arguments + size_t i_var; // variable index of primary (last) result + // + // information about atomic function + enum_atom_state atom_state = start_atom; + size_t atom_i = 0; + size_t atom_j = 0; + // + i_var = 0; + for(i_op = 0; i_op < num_op; ++i_op) + { // if non-zero, use previous result in place of this operator. + // Must get this information before writing new_op[i_op]. + size_t previous = size_t( op_previous[i_op] ); + // + // zero is invalid except for new_op[0]. + new_op[i_op] = 0; + // + // Zero is invalid except for new_var[0] and previous is zero unless + // this operator is replace by a previous operator. + new_var[i_op] = 0; + if( op_usage[i_op] == usage_t(yes_usage) ) + new_var[i_op] = new_var[previous]; + // + // temporary used in some switch cases + addr_t mask; + // + // this operator information + size_t i_tmp; + random_itr.op_info(i_op, op, arg, i_tmp); + if( NumRes(op) > 0 ) + i_var = i_tmp; + // + // is this new result the top of a cummulative summation + bool top_csum; + // + // determine if we should insert a conditional skip here + bool skip = conditional_skip; + if( skip ) + { skip &= cskip_order_next < num_cexp; + skip &= op != BeginOp; + skip &= op != InvOp; + skip &= atom_state == start_atom; + if( skip ) + { size_t j = cskip_order[cskip_order_next]; + if( NumRes(op) > 0 ) + skip &= size_t( cexp_info[j].max_left_right ) < i_var; + else + skip &= size_t( cexp_info[j].max_left_right ) <= i_var; + } + if( skip ) + { size_t j = cskip_order[cskip_order_next]; + cskip_order_next++; + size_t n_true = skip_op_true.number_elements(j); + size_t n_false = skip_op_false.number_elements(j); + skip &= n_true > 0 || n_false > 0; + if( skip ) + { CPPAD_ASSERT_UNKNOWN( NumRes(CSkipOp) == 0 ); + size_t n_arg = 7 + size_t(n_true) + size_t(n_false); + // reserve space for the arguments to this operator but + // delay setting them until we have all the new addresses + cskip_new[j].i_arg = rec->ReserveArg(n_arg); + // i_arg == 0 is used to check if conditional expression + // has been skipped. + CPPAD_ASSERT_UNKNOWN( cskip_new[j].i_arg > 0 ); + // There is no corresponding old operator in this case + rec->PutOp(CSkipOp); + } + } + } + // + CPPAD_ASSERT_UNKNOWN( + size_t( (std::numeric_limits::max)() ) >= rec->num_op_rec() + ); + // + // For each call, first and second AFunOp will have same op_usage + skip = op_usage[i_op] != usage_t( yes_usage ); + skip &= atom_state != arg_atom && atom_state != ret_atom; + if( skip ) + { if( op == CExpOp ) + ++cexp_next; + // + if( op == AFunOp ) + { if( atom_state == start_atom ) + atom_state = end_atom; + else + { CPPAD_ASSERT_UNKNOWN( atom_state == end_atom ); + atom_state = start_atom; + } + } + } + else switch( op ) + { // op_usage[i_op] == usage_t(yes_usage) + + case BeginOp: + CPPAD_ASSERT_UNKNOWN( previous == 0 ); + CPPAD_ASSERT_NARG_NRES(op, 1, 1); + // Put BeginOp at beginning of recording + new_op[i_op] = addr_t( rec->num_op_rec() ); + new_var[i_op] = rec->PutOp(BeginOp); + rec->PutArg(arg[0]); + break; + + // -------------------------------------------------------------- + // Unary operators, argument a variable, one result + case AbsOp: + case AcosOp: + case AcoshOp: + case AsinOp: + case AsinhOp: + case AtanOp: + case AtanhOp: + case CosOp: + case CoshOp: + case ErfOp: + case ErfcOp: + case ExpOp: + case Expm1Op: + case LogOp: + case Log1pOp: + case SignOp: + case SinOp: + case SinhOp: + case SqrtOp: + case TanOp: + case TanhOp: + if( previous == 0 ) + { // + new_arg[0] = new_var[ random_itr.var2op(size_t(arg[0])) ]; + rec->PutArg( new_arg[0] ); + // + new_op[i_op] = addr_t( rec->num_op_rec() ); + new_var[i_op] = rec->PutOp(op); + CPPAD_ASSERT_UNKNOWN( + new_arg[0] < new_var[random_itr.var2op(i_var)] + ); + if( op == ErfOp || op == ErfcOp ) + { CPPAD_ASSERT_NARG_NRES(op, 3, 5); + // Error function is a special case + // second argument is always the parameter 0 + // third argument is always the parameter 2 / sqrt(pi) + CPPAD_ASSERT_UNKNOWN( NumArg(ErfOp) == 3 ); + rec->PutArg( rec->put_con_par( Base(0.0) ) ); + rec->PutArg( rec->put_con_par( + Base( 1.0 / std::sqrt( std::atan(1.0) ) ) + ) ); + } + else + { // some of these operators have an auxillary result; + // e.g. sine and cosine are computed together. + CPPAD_ASSERT_UNKNOWN( NumArg(op) == 1 ); + CPPAD_ASSERT_UNKNOWN( NumRes(op) ==1 || NumRes(op) == 2 ); + } + } + break; + // --------------------------------------------------- + // Binary operators, left variable, right parameter, one result + case SubvpOp: + // check if this is the top of a csum connection + i_tmp = random_itr.var2op(size_t(arg[0])); + top_csum = op_usage[i_tmp] == usage_t(csum_usage); + if( top_csum ) + { CPPAD_ASSERT_UNKNOWN( previous == 0 ); + // + // convert to a sequence of summation operators + size_pair = record_csum( + play , + random_itr , + op_usage , + new_par , + new_var , + i_var , + rec , + csum_work + ); + new_op[i_op] = addr_t( size_pair.i_op ); + new_var[i_op] = addr_t( size_pair.i_var ); + // abort rest of this case + break; + } + case DivvpOp: + case PowvpOp: + case ZmulvpOp: + if( previous == 0 ) + { // + size_pair = record_vp( + play , + random_itr , + new_par , + new_var , + i_op , + rec + ); + new_op[i_op] = addr_t( size_pair.i_op ); + new_var[i_op] = addr_t( size_pair.i_var ); + } + break; + // --------------------------------------------------- + // Binary operators, left index, right variable, one result + case DisOp: + CPPAD_ASSERT_NARG_NRES(op, 2, 1); + if( previous == 0 ) + { // + new_arg[0] = arg[0]; + new_arg[1] = new_var[ random_itr.var2op(size_t(arg[1])) ]; + rec->PutArg( new_arg[0], new_arg[1] ); + // + new_op[i_op] = addr_t( rec->num_op_rec() ); + new_var[i_op] = rec->PutOp(op); + CPPAD_ASSERT_UNKNOWN( + new_arg[1] < new_var[random_itr.var2op(i_var)] + ); + } + break; + + // --------------------------------------------------- + // Binary operators, left parameter, right variable, one result + case SubpvOp: + case AddpvOp: + // check if this is the top of a csum connection + i_tmp = random_itr.var2op(size_t(arg[1])); + top_csum = op_usage[i_tmp] == usage_t(csum_usage); + if( top_csum ) + { CPPAD_ASSERT_UNKNOWN( previous == 0 ); + // + // convert to a sequence of summation operators + size_pair = record_csum( + play , + random_itr , + op_usage , + new_par , + new_var , + i_var , + rec , + csum_work + ); + new_op[i_op] = addr_t( size_pair.i_op ); + new_var[i_op] = addr_t( size_pair.i_var ); + // abort rest of this case + break; + } + case DivpvOp: + case MulpvOp: + case PowpvOp: + case ZmulpvOp: + if( previous == 0 ) + { // + size_pair = record_pv( + play , + random_itr , + new_par , + new_var , + i_op , + rec + ); + new_op[i_op] = addr_t( size_pair.i_op ); + new_var[i_op] = addr_t( size_pair.i_var ); + } + break; + // --------------------------------------------------- + // Binary operator, left and right variables, one result + case AddvvOp: + case SubvvOp: + // check if this is the top of a csum connection + i_tmp = random_itr.var2op(size_t(arg[0])); + top_csum = op_usage[i_tmp] == usage_t(csum_usage); + i_tmp = random_itr.var2op(size_t(arg[1])); + top_csum |= op_usage[i_tmp] == usage_t(csum_usage); + if( top_csum ) + { CPPAD_ASSERT_UNKNOWN( previous == 0 ); + // + // convert to a sequence of summation operators + size_pair = record_csum( + play , + random_itr , + op_usage , + new_par , + new_var , + i_var , + rec , + csum_work + ); + new_op[i_op] = addr_t( size_pair.i_op ); + new_var[i_op] = addr_t( size_pair.i_var ); + // abort rest of this case + break; + } + case DivvvOp: + case MulvvOp: + case PowvvOp: + case ZmulvvOp: + if( previous == 0 ) + { // + size_pair = record_vv( + play , + random_itr , + new_var , + i_op , + rec + ); + new_op[i_op] = addr_t( size_pair.i_op ); + new_var[i_op] = addr_t( size_pair.i_var ); + } + break; + // --------------------------------------------------- + // Conditional expression operators + case CExpOp: + CPPAD_ASSERT_UNKNOWN( previous == 0 ); + CPPAD_ASSERT_NARG_NRES(op, 6, 1); + new_arg[0] = arg[0]; + new_arg[1] = arg[1]; + mask = 1; + for(size_t i = 2; i < 6; i++) + { if( arg[1] & mask ) + { new_arg[i] = new_var[ random_itr.var2op(size_t(arg[i])) ]; + CPPAD_ASSERT_UNKNOWN( + size_t(new_arg[i]) < num_var + ); + } + else + new_arg[i] = new_par[ arg[i] ]; + mask = mask << 1; + } + rec->PutArg( + new_arg[0] , + new_arg[1] , + new_arg[2] , + new_arg[3] , + new_arg[4] , + new_arg[5] + ); + new_op[i_op] = addr_t( rec->num_op_rec() ); + new_var[i_op] = rec->PutOp(op); + // + // The new addresses for left and right are used during + // fill in the arguments for the CSkip operations. This does not + // affect max_left_right which is used during this sweep. + if( conditional_skip ) + { CPPAD_ASSERT_UNKNOWN( cexp_next < num_cexp ); + CPPAD_ASSERT_UNKNOWN( + size_t( cexp_info[cexp_next].i_op ) == i_op + ); + cskip_new[ cexp_next ].left = size_t( new_arg[2] ); + cskip_new[ cexp_next ].right = size_t( new_arg[3] ); + ++cexp_next; + } + break; + // --------------------------------------------------- + // Operations with no arguments and no results + case EndOp: + CPPAD_ASSERT_UNKNOWN( previous == 0 ); + CPPAD_ASSERT_NARG_NRES(op, 0, 0); + new_op[i_op] = addr_t( rec->num_op_rec() ); + rec->PutOp(op); + break; + // --------------------------------------------------- + // Comparison operations: two arguments and no results + case LepvOp: + case LtpvOp: + case EqpvOp: + case NepvOp: + CPPAD_ASSERT_UNKNOWN( compare_op ); + CPPAD_ASSERT_NARG_NRES(op, 2, 0); + if( previous == 0 ) + { new_arg[0] = new_par[ arg[0] ]; + new_arg[1] = new_var[ random_itr.var2op(size_t(arg[1])) ]; + rec->PutArg(new_arg[0], new_arg[1]); + new_op[i_op] = addr_t( rec->num_op_rec() ); + rec->PutOp(op); + } + break; + // + case LevpOp: + case LtvpOp: + CPPAD_ASSERT_UNKNOWN( compare_op ); + CPPAD_ASSERT_NARG_NRES(op, 2, 0); + if( previous == 0 ) + { new_arg[0] = new_var[ random_itr.var2op(size_t(arg[0])) ]; + new_arg[1] = new_par[ arg[1] ]; + rec->PutArg(new_arg[0], new_arg[1]); + new_op[i_op] = addr_t( rec->num_op_rec() ); + rec->PutOp(op); + } + break; + // + case LevvOp: + case LtvvOp: + case EqvvOp: + case NevvOp: + CPPAD_ASSERT_UNKNOWN( compare_op ); + CPPAD_ASSERT_NARG_NRES(op, 2, 0); + if( previous == 0 ) + { new_arg[0] = new_var[ random_itr.var2op(size_t(arg[0])) ]; + new_arg[1] = new_var[ random_itr.var2op(size_t(arg[1])) ]; + rec->PutArg(new_arg[0], new_arg[1]); + new_op[i_op] = addr_t( rec->num_op_rec() ); + rec->PutOp(op); + } + break; + + // --------------------------------------------------- + // Operations with no arguments and one result + case InvOp: + CPPAD_ASSERT_UNKNOWN( previous == 0 ); + CPPAD_ASSERT_NARG_NRES(op, 0, 1); + new_op[i_op] = addr_t( rec->num_op_rec() ); + new_var[i_op] = rec->PutOp(op); + break; + + // --------------------------------------------------- + // Unary operators, argument a parameter, one result + case ParOp: + CPPAD_ASSERT_UNKNOWN( previous == 0 ); + CPPAD_ASSERT_NARG_NRES(op, 1, 1); + new_arg[0] = new_par[ arg[0] ]; + rec->PutArg( new_arg[0] ); + // + new_op[i_op] = addr_t( rec->num_op_rec() ); + new_var[i_op] = rec->PutOp(op); + break; + + // --------------------------------------------------- + // print forward operator + case PriOp: + CPPAD_ASSERT_UNKNOWN( previous == 0 ); + CPPAD_ASSERT_NARG_NRES(op, 5, 0); + // arg[0] + new_arg[0] = arg[0]; + // + // arg[1] + if( arg[0] & 1 ) + { new_arg[1] = new_var[ random_itr.var2op(size_t(arg[1])) ]; + CPPAD_ASSERT_UNKNOWN( size_t(new_arg[1]) < num_var ); + } + else + { new_arg[1] = new_par[ arg[1] ]; + } + // + // arg[3] + if( arg[0] & 2 ) + { new_arg[3] = new_var[ random_itr.var2op(size_t(arg[3])) ]; + CPPAD_ASSERT_UNKNOWN( size_t(new_arg[3]) < num_var ); + } + else + { new_arg[3] = new_par[ arg[3] ]; + } + new_arg[2] = rec->PutTxt( play->GetTxt(size_t(arg[2])) ); + new_arg[4] = rec->PutTxt( play->GetTxt(size_t(arg[4])) ); + // + rec->PutArg( + new_arg[0] , + new_arg[1] , + new_arg[2] , + new_arg[3] , + new_arg[4] + ); + // new operator + new_op[i_op] = addr_t( rec->num_op_rec() ); + // no new variable + rec->PutOp(op); + break; + + // --------------------------------------------------- + // VecAD operators + + // Load using a parameter index + case LdpOp: + CPPAD_ASSERT_UNKNOWN( previous == 0 ); + CPPAD_ASSERT_NARG_NRES(op, 3, 1); + new_arg[0] = new_vecad_ind[ arg[0] ]; + new_arg[1] = new_par[ arg[1] ]; + CPPAD_ASSERT_UNKNOWN( + size_t( (std::numeric_limits::max)() ) >= rec->num_var_load_rec() + ); + new_arg[2] = addr_t( rec->num_var_load_rec() ); + CPPAD_ASSERT_UNKNOWN( size_t(new_arg[0]) < num_vecad_ind ); + rec->PutArg( + new_arg[0], + new_arg[1], + new_arg[2] + ); + new_op[i_op] = addr_t( rec->num_op_rec() ); + new_var[i_op] = rec->PutLoadOp(op); + break; + + // Load using a variable index + case LdvOp: + CPPAD_ASSERT_UNKNOWN( previous == 0 ); + CPPAD_ASSERT_NARG_NRES(op, 3, 1); + new_arg[0] = new_vecad_ind[ arg[0] ]; + new_arg[1] = new_var[ random_itr.var2op(size_t(arg[1])) ]; + CPPAD_ASSERT_UNKNOWN( + size_t( (std::numeric_limits::max)() ) >= rec->num_var_load_rec() + ); + new_arg[2] = addr_t( rec->num_var_load_rec() ); + CPPAD_ASSERT_UNKNOWN( size_t(new_arg[0]) < num_vecad_ind ); + CPPAD_ASSERT_UNKNOWN( size_t(new_arg[1]) < num_var ); + rec->PutArg( + new_arg[0], + new_arg[1], + new_arg[2] + ); + new_op[i_op] = addr_t( rec->num_op_rec() ); + new_var[i_op] = rec->PutLoadOp(op); + break; + + // Store a parameter using a parameter index + case StppOp: + CPPAD_ASSERT_UNKNOWN( previous == 0 ); + CPPAD_ASSERT_NARG_NRES(op, 3, 0); + new_arg[0] = new_vecad_ind[ arg[0] ]; + new_arg[1] = new_par[ arg[1] ]; + new_arg[2] = new_par[ arg[2] ]; + CPPAD_ASSERT_UNKNOWN( size_t(new_arg[0]) < num_vecad_ind ); + rec->PutArg( + new_arg[0], + new_arg[1], + new_arg[2] + ); + new_op[i_op] = addr_t( rec->num_op_rec() ); + rec->PutOp(op); + break; + + // Store a parameter using a variable index + case StvpOp: + CPPAD_ASSERT_UNKNOWN( previous == 0 ); + CPPAD_ASSERT_NARG_NRES(op, 3, 0); + new_arg[0] = new_vecad_ind[ arg[0] ]; + new_arg[1] = new_var[ random_itr.var2op(size_t(arg[1])) ]; + new_arg[2] = new_par[ arg[2] ]; + CPPAD_ASSERT_UNKNOWN( size_t(new_arg[0]) < num_vecad_ind ); + CPPAD_ASSERT_UNKNOWN( size_t(new_arg[1]) < num_var ); + rec->PutArg( + new_arg[0], + new_arg[1], + new_arg[2] + ); + new_op[i_op] = addr_t( rec->num_op_rec() ); + rec->PutOp(op); + break; + + // Store a variable using a parameter index + case StpvOp: + CPPAD_ASSERT_UNKNOWN( previous == 0 ); + CPPAD_ASSERT_NARG_NRES(op, 3, 0); + new_arg[0] = new_vecad_ind[ arg[0] ]; + new_arg[1] = new_par[ arg[1] ]; + new_arg[2] = new_var[ random_itr.var2op(size_t(arg[2])) ]; + CPPAD_ASSERT_UNKNOWN( size_t(new_arg[0]) < num_vecad_ind ); + CPPAD_ASSERT_UNKNOWN( size_t(new_arg[2]) < num_var ); + rec->PutArg( + new_arg[0], + new_arg[1], + new_arg[2] + ); + new_op[i_op] = addr_t( rec->num_op_rec() ); + rec->PutOp(op); + break; + + // Store a variable using a variable index + case StvvOp: + CPPAD_ASSERT_UNKNOWN( previous == 0 ); + CPPAD_ASSERT_NARG_NRES(op, 3, 0); + new_arg[0] = new_vecad_ind[ arg[0] ]; + new_arg[1] = new_var[ random_itr.var2op(size_t(arg[1])) ]; + new_arg[2] = new_var[ random_itr.var2op(size_t(arg[2])) ]; + CPPAD_ASSERT_UNKNOWN( size_t(new_arg[0]) < num_vecad_ind ); + CPPAD_ASSERT_UNKNOWN( size_t(new_arg[1]) < num_var ); + CPPAD_ASSERT_UNKNOWN( size_t(new_arg[2]) < num_var ); + rec->PutArg( + new_arg[0], + new_arg[1], + new_arg[2] + ); + new_op[i_op] = addr_t( rec->num_op_rec() ); + rec->PutOp(op); + break; + + // ----------------------------------------------------------- + // atomic function call operators + + case AFunOp: + CPPAD_ASSERT_UNKNOWN( previous == 0 ); + CPPAD_ASSERT_NARG_NRES(op, 4, 0); + // atom_index, atom_old, atom_n, atom_m + rec->PutArg(arg[0], arg[1], arg[2], arg[3]); + new_op[i_op] = addr_t( rec->num_op_rec() ); + rec->PutOp(AFunOp); + if( atom_state == start_atom ) + { atom_state = arg_atom; + atom_j = size_t( arg[2] ); // just for counting arguments + atom_i = size_t( arg[3] ); // just for counting results + CPPAD_ASSERT_UNKNOWN( atom_j > 0 ); + CPPAD_ASSERT_UNKNOWN( atom_i > 0 ); + } + else + { CPPAD_ASSERT_UNKNOWN( atom_state == end_atom ); + atom_state = start_atom; + } + break; + + case FunapOp: + CPPAD_ASSERT_UNKNOWN( previous == 0 ); + CPPAD_ASSERT_NARG_NRES(op, 1, 0); + new_arg[0] = new_par[ arg[0] ]; + if( new_arg[0] == addr_t_max ) + new_arg[0] = zero_par_index; + rec->PutArg(new_arg[0]); + new_op[i_op] = addr_t( rec->num_op_rec() ); + rec->PutOp(FunapOp); + CPPAD_ASSERT_UNKNOWN( atom_state == arg_atom ); + --atom_j; + if( atom_j == 0 ) + atom_state = ret_atom; + break; + + case FunavOp: + CPPAD_ASSERT_UNKNOWN( previous == 0 ); + CPPAD_ASSERT_NARG_NRES(op, 1, 0); + new_arg[0] = new_var[ random_itr.var2op(size_t(arg[0])) ]; + CPPAD_ASSERT_UNKNOWN( size_t(new_arg[0]) < num_var ); + if( new_arg[0] != 0 ) + { rec->PutArg(new_arg[0]); + new_op[i_op] = addr_t( rec->num_op_rec() ); + rec->PutOp(FunavOp); + } + else + { // This argument does not affect the result and + // has been optimized out so use nan in its place. + new_arg[0] = zero_par_index; + rec->PutArg(new_arg[0]); + new_op[i_op] = addr_t( rec->num_op_rec() ); + rec->PutOp(FunapOp); + } + CPPAD_ASSERT_UNKNOWN( atom_state == arg_atom ); + --atom_j; + if( atom_j == 0 ) + atom_state = ret_atom; + break; + + case FunrpOp: + CPPAD_ASSERT_UNKNOWN( previous == 0 ); + CPPAD_ASSERT_NARG_NRES(op, 1, 0); + new_arg[0] = new_par[ arg[0] ]; + if( new_arg[0] == addr_t_max ) + { // This parameter is not used here or anywhere. + CPPAD_ASSERT_UNKNOWN( op_usage[i_op] == usage_t(no_usage) ); + new_arg[0] = zero_par_index; + } + rec->PutArg(new_arg[0]); + // + new_op[i_op] = addr_t( rec->num_op_rec() ); + rec->PutOp(FunrpOp); + CPPAD_ASSERT_UNKNOWN( atom_state == ret_atom ); + --atom_i; + if( atom_i == 0 ) + atom_state = end_atom; + break; + + case FunrvOp: + CPPAD_ASSERT_UNKNOWN( previous == 0 ); + CPPAD_ASSERT_NARG_NRES(op, 0, 1); + new_op[i_op] = addr_t( rec->num_op_rec() ); + if( op_usage[i_op] == usage_t(yes_usage) ) + new_var[i_op] = rec->PutOp(FunrvOp); + else + { // change FunrvOp -> FunrpOp to avoid creating new variable + CPPAD_ASSERT_UNKNOWN( op_usage[i_op] == usage_t(no_usage) ); + CPPAD_ASSERT_NARG_NRES(FunrpOp, 1, 0); + rec->PutArg( zero_par_index ); + rec->PutOp(FunrpOp); + } + + --atom_i; + if( atom_i == 0 ) + atom_state = end_atom; + break; + // --------------------------------------------------- + case CSumOp: + // --------------------------------------------------- + CPPAD_ASSERT_UNKNOWN( previous == 0 ); + // + // check if more entries can be included in this summation + size_pair = record_csum( + play , + random_itr , + op_usage , + new_par , + new_var , + i_var , + rec , + csum_work + ); + new_op[i_op] = addr_t( size_pair.i_op ); + new_var[i_op] = addr_t( size_pair.i_var ); + break; + // --------------------------------------------------- + + // all cases should be handled above + default: + CPPAD_ASSERT_UNKNOWN(false); + } + } + // modify the dependent variable vector to new indices + for(size_t i = 0; i < dep_taddr.size(); i++ ) + { dep_taddr[i] = size_t(new_var[ random_itr.var2op(dep_taddr[i]) ]); + CPPAD_ASSERT_UNKNOWN( size_t(dep_taddr[i]) < num_var ); + } + +# ifndef NDEBUG + for(i_op = 0; i_op < num_op; i_op++) + { random_itr.op_info(i_op, op, arg, i_var); + if( NumRes(op) > 0 ) + CPPAD_ASSERT_UNKNOWN( + size_t(new_op[i_op]) < rec->num_op_rec() + ); + } +# endif + // make sure that all the conditional expressions have been + // checked to see if they are still present + CPPAD_ASSERT_UNKNOWN( cskip_order_next == num_cexp ); + // fill in the arguments for the CSkip operations + for(size_t i = 0; i < num_cexp; i++) + { // if cskip_new[i].i_arg == 0, this conditional expression was skipped + if( cskip_new[i].i_arg > 0 ) + { // size_t i_arg + struct_cexp_info info = cexp_info[i]; + addr_t n_true = addr_t( skip_op_true.number_elements(i) ); + addr_t n_false = addr_t( skip_op_false.number_elements(i) ); + i_arg = cskip_new[i].i_arg; + addr_t left = addr_t( cskip_new[i].left ); + addr_t right = addr_t( cskip_new[i].right ); + rec->ReplaceArg(i_arg++, addr_t(info.cop) ); + rec->ReplaceArg(i_arg++, addr_t(info.flag) ); + rec->ReplaceArg(i_arg++, left ); + rec->ReplaceArg(i_arg++, right ); + rec->ReplaceArg(i_arg++, n_true ); + rec->ReplaceArg(i_arg++, n_false ); + sparse::list_setvec::const_iterator itr_true(skip_op_true, i); + while( *itr_true != skip_op_true.end() ) + { i_op = *itr_true; + // op_usage[i_op] == usage_t(yes_usage) + CPPAD_ASSERT_UNKNOWN( new_op[i_op] != 0 ); + rec->ReplaceArg(i_arg++, new_op[i_op] ); + // + ++itr_true; + } + sparse::list_setvec::const_iterator itr_false(skip_op_false, i); + while( *itr_false != skip_op_false.end() ) + { i_op = *itr_false; + // op_usage[i_op] == usage_t(yes_usage) + CPPAD_ASSERT_UNKNOWN( new_op[i_op] != 0 ); + rec->ReplaceArg(i_arg++, new_op[i_op] ); + // + ++itr_false; + } + rec->ReplaceArg(i_arg++, n_true + n_false); +# ifndef NDEBUG + size_t n_arg = 7 + size_t(n_true) + size_t(n_false); + CPPAD_ASSERT_UNKNOWN( cskip_new[i].i_arg + n_arg == i_arg ); +# endif + } + } + return exceed_collision_limit; +} + +} } } // END_CPPAD_LOCAL_OPTIMIZE_NAMESPACE + +# endif diff --git a/build-config/cppad/include/cppad/local/optimize/record_csum.hpp b/build-config/cppad/include/cppad/local/optimize/record_csum.hpp new file mode 100644 index 00000000..5f986579 --- /dev/null +++ b/build-config/cppad/include/cppad/local/optimize/record_csum.hpp @@ -0,0 +1,386 @@ +# ifndef CPPAD_LOCAL_OPTIMIZE_RECORD_CSUM_HPP +# define CPPAD_LOCAL_OPTIMIZE_RECORD_CSUM_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +// BEGIN_CPPAD_LOCAL_OPTIMIZE_NAMESPACE +namespace CppAD { namespace local { namespace optimize { + +/*! +$begin optimize_record_csum$$ +$spell + iutr + iterator + op + var + itr + NumRes + csum + Addpv + Addvv + Subpv + Subvp + Subvv +$$ + +$section Recording a Cumulative Summation Operator$$ + +$head Prototype$$ +$srcthisfile% + 0%// BEGIN_RECORD_CSUM%// END_PROROTYPE%1 +%$$ + +$head play$$ +player object corresponding to the old recording. + +$head random_itr$$ +is a random iterator corresponding to the old operation sequence. + +$head op_usage$$ +mapping from old operator index to how it is used. + +$head new_par$$ +mapping from old parameter index to parameter index in new recording. + +$head new_var$$ +mapping from old operator index to variable index in new recording. + +$head current$$ +is the index in the old operation sequence for +the variable corresponding to the result for the current operator. +We use the notation $icode%i_op% = %random_itr%.var2op(%current%)%$$. +It follows that NumRes( random_itr.get_op[i_op] ) > 0. +If 0 < j_op < i_op, either op_usage[j_op] == usage_t(csum_usage), +op_usage[j_op] = usage_t(no_usage), or new_var[j_op] != 0. + +$head rec$$ +is the object that will record the new operations. + +$head return$$ +is the operator and variable indices in the new operation sequence. + +$head stack$$ +Is temporary work space. On input and output, +stack.op_info, stack.add_var, and stack.sub_var, are all empty. +These stacks are passed in so that they are created once +and then be reused with calls to $code record_csum$$. + +$head Assumptions$$ +$list number$$ +random_itr.get_op[i_op] must be one of the following: +CSumOp, AddpvOp, AddvvOp, SubpvOp, SubvpOp, SubvvOp. +$lnext +op_usage[i_op] == usage_t(yes_usage). +$lnext +Either this is a CSumOp, or +op_usage[j_op] == usage_t(csum_usage) is true from some +j_op that corresponds to a variable that is an argument to +random_itr.get_op[i_op]. +$lend + +$end +*/ + +// BEGIN_RECORD_CSUM +template +struct_size_pair record_csum( + const player* play , + const play::const_random_iterator& random_itr , + const pod_vector& op_usage , + const pod_vector& new_par , + const pod_vector& new_var , + size_t current , + recorder* rec , + // local information passed so stacks need not be allocated for every call + struct_csum_stacks& stack ) +// END_PROROTYPE +{ +# ifndef NDEBUG + // number of parameters corresponding to the old operation sequence. + size_t npar = play->num_par_rec(); +# endif + + // vector of length npar containing the parameters the old operation + // sequence; i.e., given a parameter index i < npar, the corresponding + // parameter value is par[i]. + const Base* par = play->GetPar(); + + // which parameters are dynamic + const pod_vector& dyn_par_is( play->dyn_par_is() ); + + // check assumption about work space + CPPAD_ASSERT_UNKNOWN( stack.op_info.empty() ); + CPPAD_ASSERT_UNKNOWN( stack.add_var.empty() ); + CPPAD_ASSERT_UNKNOWN( stack.sub_var.empty() ); + // + // this operator is not csum connected to some other result + size_t i_op = random_itr.var2op(current); + CPPAD_ASSERT_UNKNOWN( ! ( op_usage[i_op] == usage_t(csum_usage) ) ); + // + // information corresponding to the root node in the cummulative summation + struct struct_csum_op_info info; + size_t not_used; + random_itr.op_info(i_op, info.op, info.arg, not_used); + info.add = true; // was parrent operator positive or negative + // + // initialize stack as containing this one operator + stack.op_info.push( info ); + // + // initialize sum of parameter values as zero + Base sum_par(0); + // +# ifndef NDEBUG + // one argument of this operator must have been csum connected to it + bool ok = info.op == CSumOp; + if( (! ok) & (info.op != SubpvOp) & (info.op != AddpvOp) ) + { // first argument is a varialbe being added + i_op = random_itr.var2op(size_t(info.arg[0])); + ok |= op_usage[i_op] == usage_t(csum_usage); + } + if( (! ok) & (info.op != SubvpOp) ) + { // second argument is a varialbe being added or subtracted + i_op = random_itr.var2op(size_t(info.arg[1])); + ok |= op_usage[i_op] == usage_t(csum_usage); + } + CPPAD_ASSERT_UNKNOWN( ok ); +# endif + // + // while there are operators left on the stack + while( ! stack.op_info.empty() ) + { // get this summation operator + info = stack.op_info.top(); + stack.op_info.pop(); + OpCode op = info.op; + const addr_t* arg = info.arg; + bool add = info.add; + CPPAD_ASSERT_UNKNOWN( NumRes(op) == 1 ); + // + if( op == CSumOp ) + { // --------------------------------------------------------------- + // Begin op == CSumOp + // + // arg[0] is constant parameter that initializes the sum + CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) < npar ); + CPPAD_ASSERT_UNKNOWN( ! dyn_par_is[ arg[0] ] ); + if( add ) + sum_par += par[arg[0]]; + else + sum_par -= par[arg[0]]; + // + // stack entries for addition variable + size_t var_start = 5; // start addition variables + size_t var_end = size_t( arg[1] ); // end addition variables + bool add_var = add; // addition variables + for(size_t j = 0; j < 2; ++j) + { for(size_t i = var_start; i < var_end; ++i) + { // + // check if the i-th argument has csum usage + i_op = random_itr.var2op(size_t(arg[i])); + if( op_usage[i_op] == usage_t(csum_usage) ) + { // there is no result corresponding to i-th argument + CPPAD_ASSERT_UNKNOWN( size_t( new_var[i_op]) == 0 ); + + // push operator corresponding to the i-th argument + random_itr.op_info(i_op, info.op, info.arg, not_used); + info.add = add; + stack.op_info.push( info ); + } + else + { // there are no nodes below this one + CPPAD_ASSERT_UNKNOWN( size_t(arg[i]) < current ); + if( add_var ) + stack.add_var.push(arg[i]); + else + stack.sub_var.push(arg[i]); + } + } + var_start = var_end; // start subtraction variables + var_end = size_t( arg[2] ); // end subtraction variables + add_var = ! add; // subtraction variables + } + // + // stack entries for addition dynamic parameters + size_t dyn_start = var_end; // start addition dynamics + size_t dyn_end = size_t( arg[3] ); // end addition dynamics + bool dny_add = add; // addition dynamics + for(size_t j = 0; j < 2; ++j) + { for(size_t i = dyn_start; i < dyn_end; ++i) + { // i-th argument is a dynamic parameter + // (can't yet be a result, so no nodes below) + CPPAD_ASSERT_UNKNOWN( dyn_par_is[ arg[i] ] ); + if( dny_add ) + stack.add_dyn.push(arg[i]); + else + stack.sub_dyn.push(arg[i]); + } + dyn_start = dyn_end; // start subtraction dynamics + dyn_end = size_t( arg[4] ); // end subtraction dynamics + dny_add = ! add; // subtraction dynamics + } + // End op == CSumOp + // --------------------------------------------------------------- + } + else + { // --------------------------------------------------------------- + // Begin op != CSumOp + // + // is this a subtraction operator + bool subtract = (op==SubpvOp) | (op==SubvpOp) | (op==SubvvOp); + // + // is the i-th arguemnt a parameter + CPPAD_ASSERT_UNKNOWN( NumArg(op) == 2 ); + bool par_arg[2]; + switch(op) + { case SubpvOp: + case AddpvOp: + par_arg[0] = true; + par_arg[1] = false; + break; + // + case SubvpOp: + par_arg[0] = false; + par_arg[1] = true; + break; + // + default: + par_arg[0] = false; + par_arg[1] = false; + break; + } + // + // loop over the arguments to this operator + for(size_t i = 0; i < 2; ++i) + { if( subtract & (i == 1) ) + add = ! add; + if( par_arg[i] ) + { // case where i-th argument is a parameter + CPPAD_ASSERT_UNKNOWN( size_t(arg[i]) < npar ); + // + if( dyn_par_is[ arg[i] ] ) + { // i-th argument is a dynamic parameter + // (can't yet be a result, so no nodes below) + if( add ) + stack.add_dyn.push(arg[i]); + else + stack.sub_dyn.push(arg[i]); + } + else + { // i-th argument is constant parameter + if( add ) + sum_par += par[arg[i]]; + else + sum_par -= par[arg[i]]; + } + } + else + { // case where i-th argument is a variable + // + // check if the i-th argument has csum usage + i_op = random_itr.var2op(size_t(arg[i])); + if( op_usage[i_op] == usage_t(csum_usage) ) + { // there is no result corresponding to i-th argument + CPPAD_ASSERT_UNKNOWN( size_t( new_var[i_op]) == 0 ); + + // push operator corresponding to the i-th argument + random_itr.op_info(i_op, info.op, info.arg, not_used); + info.add = add; + stack.op_info.push( info ); + } + else + { // there are no nodes below this one + CPPAD_ASSERT_UNKNOWN( size_t(arg[i]) < current ); + if( add ) + stack.add_var.push(arg[i]); + else + stack.sub_var.push(arg[i]); + } + } + } + // End op != CSumOp + // --------------------------------------------------------------- + } + } + // number of variables to add in this cummulative sum operator + size_t n_add_var = stack.add_var.size(); + + // number of variables to subtract in this cummulative sum operator + size_t n_sub_var = stack.sub_var.size(); + + // number of dynamics to add in this cummulative sum operator + size_t n_add_dyn = stack.add_dyn.size(); + + // number of dynamics to subtract in this cummulative sum operator + size_t n_sub_dyn = stack.sub_dyn.size(); + + // first five arguments to cumulative sum operator + addr_t new_arg = rec->put_con_par(sum_par); + rec->PutArg(new_arg); // arg[0]: initial sum + size_t end = n_add_var + 5; + rec->PutArg( addr_t(end) ); // arg[1]: end for add variables + end += n_sub_var; + rec->PutArg( addr_t(end) ); // arg[2]: end for sub variables + end += n_add_dyn; + rec->PutArg( addr_t(end) ); // arg[3]: end for add dynamics + end += n_sub_dyn; + rec->PutArg( addr_t(end) ); // arg[4]: end for sub dynamics + + // addition variable arguments + for(size_t i = 0; i < n_add_var; i++) + { CPPAD_ASSERT_UNKNOWN( ! stack.add_var.empty() ); + addr_t old_arg = stack.add_var.top(); + new_arg = new_var[ random_itr.var2op(size_t(old_arg)) ]; + CPPAD_ASSERT_UNKNOWN( 0 < new_arg && size_t(new_arg) < current ); + rec->PutArg(new_arg); // arg[5+i] + stack.add_var.pop(); + } + + // subtraction variable arguments + for(size_t i = 0; i < n_sub_var; i++) + { CPPAD_ASSERT_UNKNOWN( ! stack.sub_var.empty() ); + addr_t old_arg = stack.sub_var.top(); + new_arg = new_var[ random_itr.var2op(size_t(old_arg)) ]; + CPPAD_ASSERT_UNKNOWN( 0 < new_arg && size_t(new_arg) < current ); + rec->PutArg(new_arg); // arg[arg[1] + i] + stack.sub_var.pop(); + } + + // addition dynamic arguments + for(size_t i = 0; i < n_add_dyn; ++i) + { addr_t old_arg = stack.add_dyn.top(); + new_arg = new_par[ old_arg ]; + rec->PutArg(new_arg); // arg[arg[2] + i] + stack.add_dyn.pop(); + } + + // subtraction dynamic arguments + for(size_t i = 0; i < n_sub_dyn; ++i) + { addr_t old_arg = stack.sub_dyn.top(); + new_arg = new_par[ old_arg ]; + rec->PutArg(new_arg); // arg[arg[3] + i] + stack.sub_dyn.pop(); + } + + // number of additions plus number of subtractions + rec->PutArg( addr_t(end) ); // arg[arg[4]] = arg[4] + // + // return value + struct_size_pair ret; + ret.i_op = rec->num_op_rec(); + ret.i_var = size_t(rec->PutOp(CSumOp)); + // + return ret; +} + +} } } // END_CPPAD_LOCAL_OPTIMIZE_NAMESPACE + + +# endif diff --git a/build-config/cppad/include/cppad/local/optimize/record_pv.hpp b/build-config/cppad/include/cppad/local/optimize/record_pv.hpp new file mode 100644 index 00000000..a0809aa2 --- /dev/null +++ b/build-config/cppad/include/cppad/local/optimize/record_pv.hpp @@ -0,0 +1,102 @@ +# ifndef CPPAD_LOCAL_OPTIMIZE_RECORD_PV_HPP +# define CPPAD_LOCAL_OPTIMIZE_RECORD_PV_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-18 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ +/*! +\file record_pv.hpp +Record an operation of the form (parameter op variable). +*/ +// BEGIN_CPPAD_LOCAL_OPTIMIZE_NAMESPACE +namespace CppAD { namespace local { namespace optimize { + +/*! +Record an operation of the form (parameter op variable). + +\param play +player object corresponding to the old recroding. + +\param random_itr +random iterator corresponding to old recording. + +\param new_par +mapping from old parameter index to parameter index in new recording. + +\param new_var +mapping from old operator index to variable index in new recording. + +\param i_op +is the index in the old operation sequence for this operator. +The operator must be one of the following: +AddpvOp, DivpvOp, MulpvOp, PowpvOp, SubpvOp, ZmulpvOp. + +\param rec +is the object that will record the new operations. + +\return +is the operator and variable indices in the new operation sequence. +*/ +template +struct_size_pair record_pv( + const player* play , + const play::const_random_iterator& random_itr , + const pod_vector& new_par , + const pod_vector& new_var , + size_t i_op , + recorder* rec ) +{ + // get_op_info + OpCode op; + const addr_t* arg; + size_t i_var; + random_itr.op_info(i_op, op, arg, i_var); + // +# ifndef NDEBUG + switch(op) + { case AddpvOp: + case DivpvOp: + case MulpvOp: + case PowpvOp: + case SubpvOp: + case ZmulpvOp: + break; + + default: + CPPAD_ASSERT_UNKNOWN(false); + } + // number of parameters corresponding to the old operation sequence. + size_t npar = play->num_par_rec(); +# endif + // + // vector of length npar containing the parameters the old operation + // sequence; i.e., given a parameter index i < npar, the corresponding + // parameter value is par[i]. + // + CPPAD_ASSERT_UNKNOWN( NumRes(op) > 0 ); + CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) < npar ); + CPPAD_ASSERT_UNKNOWN( size_t(arg[1]) < i_var ); // DAG condition + // + addr_t new_arg[2]; + new_arg[0] = new_par[ arg[0] ]; + new_arg[1] = new_var[ random_itr.var2op(size_t(arg[1])) ]; + rec->PutArg( new_arg[0], new_arg[1] ); + // + struct_size_pair ret; + ret.i_op = rec->num_op_rec(); + ret.i_var = size_t(rec->PutOp(op)); + CPPAD_ASSERT_UNKNOWN( 0 < new_arg[1] && size_t(new_arg[1]) < ret.i_var ); + return ret; +} + +} } } // END_CPPAD_LOCAL_OPTIMIZE_NAMESPACE + + +# endif diff --git a/build-config/cppad/include/cppad/local/optimize/record_vp.hpp b/build-config/cppad/include/cppad/local/optimize/record_vp.hpp new file mode 100644 index 00000000..ca784bb1 --- /dev/null +++ b/build-config/cppad/include/cppad/local/optimize/record_vp.hpp @@ -0,0 +1,101 @@ +# ifndef CPPAD_LOCAL_OPTIMIZE_RECORD_VP_HPP +# define CPPAD_LOCAL_OPTIMIZE_RECORD_VP_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-18 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ +/*! +\file record_vp.hpp +Record an operation of the form (variable op parameter). +*/ +// BEGIN_CPPAD_LOCAL_OPTIMIZE_NAMESPACE +namespace CppAD { namespace local { namespace optimize { + + +/*! +Record an operation of the form (variable op parameter). + +\param play +player object corresponding to the old recroding. + +\param random_itr +is a random iterator corresponding to the old recording. + +\param new_par +mapping from old parameter index to parameter index in new recording. + +\param new_var +mapping from old operator index to variable index in new recording. + +\param i_op +is the index in the old operation sequence for this operator. +the must be one of the following: +DivvpOp, PowvpOp, SubvpOp, ZmulvpOp. + +\param rec +is the object that will record the new operations. + +\return +is the operator and variable indices in the new operation sequence. +*/ +template +struct_size_pair record_vp( + const player* play , + const play::const_random_iterator& random_itr , + const pod_vector& new_par , + const pod_vector& new_var , + size_t i_op , + recorder* rec ) +{ + // get_op_info + OpCode op; + const addr_t* arg; + size_t i_var; + random_itr.op_info(i_op, op, arg, i_var); + // +# ifndef NDEBUG + switch(op) + { case DivvpOp: + case PowvpOp: + case SubvpOp: + case ZmulvpOp: + break; + + default: + CPPAD_ASSERT_UNKNOWN(false); + } + // number of parameters corresponding to the old operation sequence. + size_t npar = play->num_par_rec(); +# endif + + // vector of length npar containing the parameters the old operation + // sequence; i.e., given a parameter index i < npar, the corresponding + // parameter value is par[i]. + // + CPPAD_ASSERT_UNKNOWN( NumRes(op) > 0 ); + CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) < i_var ); // DAG condition + CPPAD_ASSERT_UNKNOWN( size_t(arg[1]) < npar ); + // + addr_t new_arg[2]; + new_arg[0] = new_var[ random_itr.var2op(size_t(arg[0])) ]; + new_arg[1] = new_par[ arg[1] ]; + rec->PutArg( new_arg[0], new_arg[1] ); + // + struct_size_pair ret; + ret.i_op = rec->num_op_rec(); + ret.i_var = size_t(rec->PutOp(op)); + CPPAD_ASSERT_UNKNOWN( 0 < new_arg[0] && size_t(new_arg[0]) < ret.i_var ); + return ret; +} + +} } } // END_CPPAD_LOCAL_OPTIMIZE_NAMESPACE + + +# endif diff --git a/build-config/cppad/include/cppad/local/optimize/record_vv.hpp b/build-config/cppad/include/cppad/local/optimize/record_vv.hpp new file mode 100644 index 00000000..1f6ab735 --- /dev/null +++ b/build-config/cppad/include/cppad/local/optimize/record_vv.hpp @@ -0,0 +1,91 @@ +# ifndef CPPAD_LOCAL_OPTIMIZE_RECORD_VV_HPP +# define CPPAD_LOCAL_OPTIMIZE_RECORD_VV_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-18 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ +/*! +\file record_vv.hpp +Record an operation of the form (variable op variable). +*/ +// BEGIN_CPPAD_LOCAL_OPTIMIZE_NAMESPACE +namespace CppAD { namespace local { namespace optimize { +/*! +Record an operation of the form (variable op variable). + +\param play +player object corresponding to the old recroding. + +\param random_itr +random iterator corresponding to the old recording. + +\param new_var +mapping from old operator index to variable index in new recording. + +\param i_op +is the index in the old operation sequence for this operator. +the must be one of the following: +AddvvOp, DivvvOp, MulvvOp, PowvvOp, SubvvOp, ZmulvvOp. + +\param rec +is the object that will record the new operations. + +\return +is the operator and variable indices in the new operation sequence. +*/ +template +struct_size_pair record_vv( + const player* play , + const play::const_random_iterator& random_itr , + const pod_vector& new_var , + size_t i_op , + recorder* rec ) +{ + // get_op_info + OpCode op; + const addr_t* arg; + size_t i_var; + random_itr.op_info(i_op, op, arg, i_var); + // +# ifndef NDEBUG + switch(op) + { case AddvvOp: + case DivvvOp: + case MulvvOp: + case PowvvOp: + case SubvvOp: + case ZmulvvOp: + break; + + default: + CPPAD_ASSERT_UNKNOWN(false); + } +# endif + CPPAD_ASSERT_UNKNOWN( NumRes(op) > 0 ); + CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) < i_var ); // DAG condition + CPPAD_ASSERT_UNKNOWN( size_t(arg[1]) < i_var ); // DAG condition + // + addr_t new_arg[2]; + new_arg[0] = new_var[ random_itr.var2op(size_t(arg[0])) ]; + new_arg[1] = new_var[ random_itr.var2op(size_t(arg[1])) ]; + rec->PutArg( new_arg[0], new_arg[1] ); + // + struct_size_pair ret; + ret.i_op = rec->num_op_rec(); + ret.i_var = size_t(rec->PutOp(op)); + CPPAD_ASSERT_UNKNOWN( 0 < new_arg[0] && size_t(new_arg[0]) < ret.i_var ); + CPPAD_ASSERT_UNKNOWN( 0 < new_arg[1] && size_t(new_arg[1]) < ret.i_var ); + return ret; +} + +} } } // END_CPPAD_LOCAL_OPTIMIZE_NAMESPACE + + +# endif diff --git a/build-config/cppad/include/cppad/local/optimize/size_pair.hpp b/build-config/cppad/include/cppad/local/optimize/size_pair.hpp new file mode 100644 index 00000000..96d33921 --- /dev/null +++ b/build-config/cppad/include/cppad/local/optimize/size_pair.hpp @@ -0,0 +1,32 @@ +# ifndef CPPAD_LOCAL_OPTIMIZE_SIZE_PAIR_HPP +# define CPPAD_LOCAL_OPTIMIZE_SIZE_PAIR_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-16 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ +/*! +\file size_pair.hpp +Information for one variable and one operation sequence. +*/ +// BEGIN_CPPAD_LOCAL_OPTIMIZE_NAMESPACE +namespace CppAD { namespace local { namespace optimize { + +/*! +\file size_pair.hpp +Information for one variable in one operation sequence. +*/ +struct struct_size_pair { + size_t i_op; /// operator index for this variable + size_t i_var; /// variable index for this variable +}; + +} } } // END_CPPAD_LOCAL_OPTIMIZE_NAMESPACE + +# endif diff --git a/build-config/cppad/include/cppad/local/optimize/usage.hpp b/build-config/cppad/include/cppad/local/optimize/usage.hpp new file mode 100644 index 00000000..8eb2f5e0 --- /dev/null +++ b/build-config/cppad/include/cppad/local/optimize/usage.hpp @@ -0,0 +1,39 @@ +# ifndef CPPAD_LOCAL_OPTIMIZE_USAGE_HPP +# define CPPAD_LOCAL_OPTIMIZE_USAGE_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-18 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ +# include + +// BEGIN_CPPAD_LOCAL_OPTIMIZE_NAMESPACE +namespace CppAD { namespace local { namespace optimize { + +typedef CPPAD_VEC_ENUM_TYPE usage_t; + +enum enum_usage { + /// This operator is not used. + no_usage, + + /// This operator is used one or more times. + yes_usage, + + /*! + This operator is only used once, it is a summation operator, + and its parrent is a summation operator. Furthermore, its result is not + a dependent variable. Hence case it can be removed as part of a + cumulative summation starting at its parent or above. + */ + csum_usage +}; + + +} } } // END_CPPAD_LOCAL_OPTIMIZE_NAMESPACE +# endif diff --git a/build-config/cppad/include/cppad/local/parameter_op.hpp b/build-config/cppad/include/cppad/local/parameter_op.hpp new file mode 100644 index 00000000..f8617f0c --- /dev/null +++ b/build-config/cppad/include/cppad/local/parameter_op.hpp @@ -0,0 +1,89 @@ +# ifndef CPPAD_LOCAL_PARAMETER_OP_HPP +# define CPPAD_LOCAL_PARAMETER_OP_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-16 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + + +namespace CppAD { namespace local { // BEGIN_CPPAD_LOCAL_NAMESPACE +/*! +\file parameter_op.hpp +Zero order forward mode for ParOp +*/ + + +/*! +Compute zero order forward mode Taylor coefficient for result of op = ParOp. + +The C++ source code corresponding to this operation is one of the following +\verbatim + ADFun f(x, y) + f.Dependent(x, y) +\endverbatim +where some of the components of the vector y are parameters. + +\tparam Base +base type for the operator; i.e., this operation was recorded +using AD< Base > and computations by this routine are done using type + Base . + +\param i_z +variable index corresponding to the result for this operation; +i.e. the row index in taylor corresponding to the component of y +that is a parameter. + +\param arg + arg[0] +\n +index corresponding to the parameter value for this operator. + +\param num_par +is the number of parameters in parameter. + +\param parameter +\b Input: parameter[ arg[0] ] is the value of a component +of y that is a parameter. + +\param cap_order +number of colums in the matrix containing all the Taylor coefficients. + +\param taylor +\b Output: taylor [ i_z * cap_order + 0 ] +is the zero order Taylor coefficient corresponding to z. + +\par Checked Assertions where op is the unary operator with one result: +\li NumArg(op) == 1 +\li NumRes(op) == 1 +\li size_t(arg[0]) < num_par +\li 0 < cap_order +*/ +template +void forward_par_op_0( + size_t i_z , + const addr_t* arg , + size_t num_par , + const Base* parameter , + size_t cap_order , + Base* taylor ) +{ + // check assumptions + CPPAD_ASSERT_UNKNOWN( NumArg(ParOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( NumRes(ParOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) < num_par ); + CPPAD_ASSERT_UNKNOWN( 0 < cap_order ); + + Base* z = taylor + i_z * cap_order; + + z[0] = parameter[ arg[0] ]; +} + +} } // END_CPPAD_LOCAL_NAMESPACE +# endif diff --git a/build-config/cppad/include/cppad/local/play/addr_enum.hpp b/build-config/cppad/include/cppad/local/play/addr_enum.hpp new file mode 100644 index 00000000..5286cac7 --- /dev/null +++ b/build-config/cppad/include/cppad/local/play/addr_enum.hpp @@ -0,0 +1,30 @@ +# ifndef CPPAD_LOCAL_PLAY_ADDR_ENUM_HPP +# define CPPAD_LOCAL_PLAY_ADDR_ENUM_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-18 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +// BEGIN_CPPAD_LOCAL_PLAY_NAMESPACE +namespace CppAD { namespace local { namespace play { + +/*! +\file addr_enum.hpp +*/ +/// enum corresponding to type used for addressing iterators for a player +enum addr_enum { + unsigned_short_enum , + unsigned_int_enum , + size_t_enum +}; + +} } } // BEGIN_CPPAD_LOCAL_PLAY_NAMESPACE + +# endif diff --git a/build-config/cppad/include/cppad/local/play/atom_op_info.hpp b/build-config/cppad/include/cppad/local/play/atom_op_info.hpp new file mode 100644 index 00000000..264055bf --- /dev/null +++ b/build-config/cppad/include/cppad/local/play/atom_op_info.hpp @@ -0,0 +1,89 @@ +# ifndef CPPAD_LOCAL_PLAY_ATOM_OP_INFO_HPP +# define CPPAD_LOCAL_PLAY_ATOM_OP_INFO_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +// BEGIN_CPPAD_LOCAL_PLAY_NAMESPACE +namespace CppAD { namespace local { namespace play { + +/*! +\file atom_op_info.hpp +*/ + +/*! +\brief +Unpack extra information corresponding to a AFunOp + +\param op [in] +must be a AFunOp + +\param op_arg [in] +is the arguments for this operator + +\param atom_old [out] +is the extra information passed to the old style atomic functions. + +\param atom_index [out] +is the index in local::atomic_index corresponding to this atomic functions. + +\param atom_m [out] +is the number of results for this user atmoic function. + +\param atom_n [out] +is the number of arguments for this user atmoic function. + +\return +Is a pointer to this atomic function. +*/ +// MUSTDO: change return to void once all sweeps switch to use call_atomic. +template +atomic_base* atom_op_info( + const OpCode op , + const addr_t* op_arg , + size_t& atom_index , + size_t& atom_old , + size_t& atom_m , + size_t& atom_n ) +{ atomic_base* atom_fun; + // + CPPAD_ASSERT_UNKNOWN( op == AFunOp ); + CPPAD_ASSERT_NARG_NRES(op, 4, 0); + // + atom_index = size_t(op_arg[0]); + atom_old = size_t(op_arg[1]); + atom_n = size_t(op_arg[2]); + atom_m = size_t(op_arg[3]); + CPPAD_ASSERT_UNKNOWN( atom_n > 0 ); + // + bool set_null = false; + size_t type = 0; // set to avoid warning + std::string* name_ptr = nullptr; + void* v_ptr = nullptr; // set to avoid warning + local::atomic_index(set_null, atom_index, type, name_ptr, v_ptr); + if( type == 3 ) + return nullptr; +# ifndef NDEBUG + if( v_ptr == nullptr ) + { // atom_fun is null so cannot use atom_fun->atomic_name() + std::string msg = atomic_base::class_name(atom_index) + + ": atomic_base function has been deleted"; + CPPAD_ASSERT_KNOWN(false, msg.c_str() ); + } +# endif + // the atomic_base object corresponding to this atomic function + atom_fun = reinterpret_cast< atomic_base* >( v_ptr ); + return atom_fun; +} + +} } } // END_CPPAD_LOCAL_PLAY_NAMESPACE + +# endif diff --git a/build-config/cppad/include/cppad/local/play/player.hpp b/build-config/cppad/include/cppad/local/play/player.hpp new file mode 100644 index 00000000..b3f3386f --- /dev/null +++ b/build-config/cppad/include/cppad/local/play/player.hpp @@ -0,0 +1,853 @@ +# ifndef CPPAD_LOCAL_PLAY_PLAYER_HPP +# define CPPAD_LOCAL_PLAY_PLAYER_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +# include +# include +# include +# include +# include +# include + +namespace CppAD { namespace local { // BEGIN_CPPAD_LOCAL_NAMESPACE +/*! +\file player.hpp +File used to define the player class. +*/ + +/*! +Class used to store and play back an operation sequence recording. + +\tparam Base +These were AD< Base > operations when recorded. Operations during playback +are done using the type Base . +*/ + +template +class player { + // player must be a friend of player< AD > for base2ad to work + template friend class player; +private: + // ---------------------------------------------------------------------- + // information that defines the recording + + /// Number of independent dynamic parameters + size_t num_dynamic_ind_; + + /// Number of variables in the recording. + size_t num_var_rec_; + + /// number of vecad load opeations in the reconding + size_t num_var_load_rec_; + + /// Number of VecAD vectors in the recording + size_t num_var_vecad_rec_; + + /// The operators in the recording. + pod_vector op_vec_; + + /// The operation argument indices in the recording + pod_vector arg_vec_; + + /// Character strings ('\\0' terminated) in the recording. + pod_vector text_vec_; + + /// The VecAD indices in the recording. + pod_vector all_var_vecad_ind_; + + /// All of the parameters in the recording. + /// Use pod_maybe because Base may not be plain old data. + pod_vector_maybe all_par_vec_; + + /// Which elements of all_par_vec_ are dynamic parameters + /// (size equal number of parametrers) + pod_vector dyn_par_is_; + + /// mapping from dynamic parameter index to parameter index + /// 1: size equal to number of dynamic parameters + /// 2: dyn_ind2par_ind_[j] < dyn_ind2par_ind_[j+1] + pod_vector dyn_ind2par_ind_; + + /// operators for just the dynamic parameters + /// (size equal number of dynamic parameters) + pod_vector dyn_par_op_; + + /// arguments for the dynamic parameter operators + pod_vector dyn_par_arg_; + + // ---------------------------------------------------------------------- + // Information needed to use member functions that begin with random_ + // and for using const_subgraph_iterator. + + /// index in arg_vec_ corresonding to the first argument for each operator + pod_vector op2arg_vec_; + + /*! + Index of the result variable for each operator. If the operator has + no results, this is not defined. The invalid index num_var_rec_ is used + when NDEBUG is not defined. If the operator has more than one result, this + is the primary result; i.e., the last result. Auxillary are only used by + the operator and not used by other operators. + */ + pod_vector op2var_vec_; + + /// Mapping from primary variable index to corresponding operator index. + /// This is used to traverse sub-graphs of the operation sequence. + /// This value is valid (invalid) for primary (auxillary) variables. + pod_vector var2op_vec_; + +public: + // ================================================================= + /// default constructor + // set all scalars to zero to avoid valgraind warning when ani assignment + // occures before values get set. + player(void) : + num_dynamic_ind_(0) , + num_var_rec_(0) , + num_var_load_rec_(0) , + num_var_vecad_rec_(0) + { } + // move semantics constructor + // (none of the default constructor values matter to the destructor) + player(player& play) + { swap(play); } + // ================================================================= + /// destructor + ~player(void) + { } + // ====================================================================== + /// type used for addressing iterators for this player + play::addr_enum address_type(void) const + { + // required + size_t required = 0; + required = std::max(required, num_var_rec_ ); // number variables + required = std::max(required, op_vec_.size() ); // number operators + required = std::max(required, arg_vec_.size() ); // number arguments + // + // unsigned short + if( required <= std::numeric_limits::max() ) + return play::unsigned_short_enum; + // + // unsigned int + if( required <= std::numeric_limits::max() ) + return play::unsigned_int_enum; + // + // unsigned size_t + CPPAD_ASSERT_UNKNOWN( + required <= std::numeric_limits::max() + ); + return play::size_t_enum; + } + // =============================================================== + /*! + Moving an operation sequence from a recorder to this player + + \param rec + the object that was used to record the operation sequence. After this + operation, the state of the recording is no longer defined. For example, + the pod_vector member variables in this have been swapped with rec. + + \param n_ind + the number of independent variables (only used for error checking + when NDEBUG is not defined). + + \par + Use an assert to check that the length of the following vectors is + less than the maximum possible value for addr_t; i.e., that an index + in these vectors can be represented using the type addr_t: + op_vec_, all_var_vecad_ind_, arg_vec_, test_vec_, all_par_vec_, text_vec_, + dyn_par_arg_. + */ + void get_recording(recorder& rec, size_t n_ind) + { +# ifndef NDEBUG + size_t addr_t_max = size_t( std::numeric_limits::max() ); +# endif + // just set size_t values + num_dynamic_ind_ = rec.num_dynamic_ind_; + num_var_rec_ = rec.num_var_rec_; + num_var_load_rec_ = rec.num_var_load_rec_; + + // op_vec_ + op_vec_.swap(rec.op_vec_); + CPPAD_ASSERT_UNKNOWN(op_vec_.size() < addr_t_max ); + + // op_arg_vec_ + arg_vec_.swap(rec.arg_vec_); + CPPAD_ASSERT_UNKNOWN(arg_vec_.size() < addr_t_max ); + + // all_par_vec_ + all_par_vec_.swap(rec.all_par_vec_); + CPPAD_ASSERT_UNKNOWN(all_par_vec_.size() < addr_t_max ); + + // dyn_par_is_, dyn_par_op_, dyn_par_arg_ + dyn_par_is_.swap( rec.dyn_par_is_ ); + dyn_par_op_.swap( rec.dyn_par_op_ ); + dyn_par_arg_.swap( rec.dyn_par_arg_ ); + CPPAD_ASSERT_UNKNOWN(dyn_par_arg_.size() < addr_t_max ); + + // text_rec_ + text_vec_.swap(rec.text_vec_); + CPPAD_ASSERT_UNKNOWN(text_vec_.size() < addr_t_max ); + + // all_var_vecad_ind_ + all_var_vecad_ind_.swap(rec.all_var_vecad_ind_); + CPPAD_ASSERT_UNKNOWN(all_var_vecad_ind_.size() < addr_t_max ); + + // num_var_vecad_rec_ + num_var_vecad_rec_ = 0; + { // all_var_vecad_ind_ contains size of each VecAD followed by + // the parameter indices used to inialize it. + size_t i = 0; + while( i < all_var_vecad_ind_.size() ) + { num_var_vecad_rec_++; + i += size_t( all_var_vecad_ind_[i] ) + 1; + } + CPPAD_ASSERT_UNKNOWN( i == all_var_vecad_ind_.size() ); + } + + // mapping from dynamic parameter index to parameter index + dyn_ind2par_ind_.resize( dyn_par_op_.size() ); + size_t i_dyn = 0; + for(size_t i_par = 0; i_par < all_par_vec_.size(); ++i_par) + { if( dyn_par_is_[i_par] ) + { dyn_ind2par_ind_[i_dyn] = addr_t( i_par ); + ++i_dyn; + } + } + CPPAD_ASSERT_UNKNOWN( i_dyn == dyn_ind2par_ind_.size() ); + + // random access information + clear_random(); + + // some checks + check_inv_op(n_ind); + check_variable_dag(); + check_dynamic_dag(); + } + // ---------------------------------------------------------------------- + /*! + Check that InvOp operators start with second operator and are contiguous, + and there are n_ind of them. + */ +# ifdef NDEBUG + void check_inv_op(size_t n_ind) const + { return; } +# else + void check_inv_op(size_t n_ind) const + { play::const_sequential_iterator itr = begin(); + OpCode op; + const addr_t* op_arg; + size_t var_index; + itr.op_info(op, op_arg, var_index); + CPPAD_ASSERT_UNKNOWN( op == BeginOp ); + size_t i_op = 0; + while( op != EndOp ) + { // start at second operator + (++itr).op_info(op, op_arg, var_index); + ++i_op; + CPPAD_ASSERT_UNKNOWN( (op == InvOp) == (i_op <= n_ind) ); + } + return; + } +# endif + // ---------------------------------------------------------------------- + /*! + Check variable graph to make sure arguments have value less + than or equal to the previously created variable. This is the directed + acyclic graph condition (DAG). + */ +# ifdef NDEBUG + void check_variable_dag(void) const + { return; } +# else + void check_variable_dag(void) const + { play::const_sequential_iterator itr = begin(); + OpCode op; + const addr_t* op_arg; + size_t var_index; + itr.op_info(op, op_arg, var_index); + CPPAD_ASSERT_UNKNOWN( op == BeginOp ); + // + addr_t arg_var_bound = 0; + while( op != EndOp ) + { (++itr).op_info(op, op_arg, var_index); + switch(op) + { + // cases where nothing to do + case BeginOp: + case EndOp: + case EqppOp: + case InvOp: + case LdpOp: + case LeppOp: + case LtppOp: + case NeppOp: + case ParOp: + case AFunOp: + case FunapOp: + case FunrpOp: + case FunrvOp: + case StppOp: + break; + + // only first argument is a variable + case AbsOp: + case AcosOp: + case AcoshOp: + case AsinOp: + case AsinhOp: + case AtanOp: + case AtanhOp: + case CosOp: + case CoshOp: + case DivvpOp: + case ErfOp: + case ErfcOp: + case ExpOp: + case Expm1Op: + case LevpOp: + case LogOp: + case Log1pOp: + case LtvpOp: + case PowvpOp: + case SignOp: + case SinOp: + case SinhOp: + case SqrtOp: + case SubvpOp: + case TanOp: + case TanhOp: + case FunavOp: + case ZmulvpOp: + CPPAD_ASSERT_UNKNOWN(op_arg[0] <= arg_var_bound ); + break; + + // only second argument is a variable + case AddpvOp: + case DisOp: + case DivpvOp: + case EqpvOp: + case LdvOp: + case LepvOp: + case LtpvOp: + case MulpvOp: + case NepvOp: + case PowpvOp: + case StvpOp: + case SubpvOp: + case ZmulpvOp: + CPPAD_ASSERT_UNKNOWN(op_arg[1] <= arg_var_bound ); + break; + + // only first and second arguments are variables + case AddvvOp: + case DivvvOp: + case EqvvOp: + case LevvOp: + case LtvvOp: + case MulvvOp: + case NevvOp: + case PowvvOp: + case SubvvOp: + case ZmulvvOp: + CPPAD_ASSERT_UNKNOWN(op_arg[0] <= arg_var_bound ); + CPPAD_ASSERT_UNKNOWN(op_arg[1] <= arg_var_bound ); + break; + + // StpvOp + case StpvOp: + CPPAD_ASSERT_UNKNOWN(op_arg[2] <= arg_var_bound ); + break; + + // StvvOp + case StvvOp: + CPPAD_ASSERT_UNKNOWN(op_arg[1] <= arg_var_bound ); + CPPAD_ASSERT_UNKNOWN(op_arg[2] <= arg_var_bound ); + break; + + // CSumOp + case CSumOp: + { CPPAD_ASSERT_UNKNOWN( 5 < op_arg[2] ); + for(addr_t j = 5; j < op_arg[2]; j++) + CPPAD_ASSERT_UNKNOWN(op_arg[j] <= arg_var_bound); + } + itr.correct_before_increment(); + break; + + // CExpOp + case CExpOp: + if( op_arg[1] & 1 ) + CPPAD_ASSERT_UNKNOWN( op_arg[2] <= arg_var_bound); + if( op_arg[1] & 2 ) + CPPAD_ASSERT_UNKNOWN( op_arg[3] <= arg_var_bound); + if( op_arg[1] & 4 ) + CPPAD_ASSERT_UNKNOWN( op_arg[4] <= arg_var_bound); + if( op_arg[1] & 8 ) + CPPAD_ASSERT_UNKNOWN( op_arg[5] <= arg_var_bound); + break; + + // PriOp + case PriOp: + if( op_arg[0] & 1 ) + CPPAD_ASSERT_UNKNOWN( op_arg[1] <= arg_var_bound); + if( op_arg[0] & 2 ) + CPPAD_ASSERT_UNKNOWN( op_arg[3] <= arg_var_bound); + break; + + // CSkipOp + case CSkipOp: + if( op_arg[1] & 1 ) + CPPAD_ASSERT_UNKNOWN( op_arg[2] <= arg_var_bound); + if( op_arg[1] & 2 ) + CPPAD_ASSERT_UNKNOWN( op_arg[3] <= arg_var_bound); + itr.correct_before_increment(); + break; + + default: + CPPAD_ASSERT_UNKNOWN(false); + break; + + + } + if( NumRes(op) > 0 ) + { if( var_index > 0 ) + { CPPAD_ASSERT_UNKNOWN(size_t(arg_var_bound) < var_index); + } + else + { CPPAD_ASSERT_UNKNOWN(size_t(arg_var_bound) == var_index); + } + // + arg_var_bound = addr_t(var_index); + } + } + return; + } +# endif + // ---------------------------------------------------------------------- + /*! + Check dynamic parameter graph to make sure arguments have value less + than or equal to the previously created dynamic parameter. + This is the directed acyclic graph condition (DAG). + */ +# ifdef NDEBUG + void check_dynamic_dag(void) const + { return; } +# else + void check_dynamic_dag(void) const + { // number of dynamic parameters + size_t num_dyn = dyn_par_op_.size(); + // + size_t i_arg = 0; // initialize dynamic parameter argument index + for(size_t i_dyn = 0; i_dyn < num_dyn; ++i_dyn) + { // i_par is parameter index + addr_t i_par = dyn_ind2par_ind_[i_dyn]; + CPPAD_ASSERT_UNKNOWN( dyn_par_is_[i_par] ); + // + // operator for this dynamic parameter + op_code_dyn op = op_code_dyn( dyn_par_op_[i_dyn] ); + // + // number of arguments for this dynamic parameter + size_t n_arg = num_arg_dyn(op); + if( op == atom_dyn ) + { size_t n = size_t( dyn_par_arg_[i_arg + 1] ); + size_t m = size_t( dyn_par_arg_[i_arg + 2] ); + n_arg = 5 + n + m; + CPPAD_ASSERT_UNKNOWN( + n_arg == size_t( dyn_par_arg_[i_arg + 4 + n + m] ) + ); + for(size_t i = 4; i < n - 1; ++i) + CPPAD_ASSERT_UNKNOWN( dyn_par_arg_[i_arg + i] < i_par ); +# ifndef NDEBUG + for(size_t i = 4+n; i < 4+n+m; ++i) + { addr_t j_par = dyn_par_arg_[i_arg + i]; + CPPAD_ASSERT_UNKNOWN( (j_par == 0) || (j_par >= i_par) ); + } +# endif + } + else + { size_t num_non_par = num_non_par_arg_dyn(op); + for(size_t i = num_non_par; i < n_arg; ++i) + CPPAD_ASSERT_UNKNOWN( dyn_par_arg_[i_arg + i] < i_par); + } + // + // next dynamic parameter + i_arg += n_arg; + } + return; + } +# endif + // =============================================================== + /*! + Copy a player to another player + + \param play + object that contains the operatoion sequence to copy. + */ + void operator=(const player& play) + { + // size_t objects + num_dynamic_ind_ = play.num_dynamic_ind_; + num_var_rec_ = play.num_var_rec_; + num_var_load_rec_ = play.num_var_load_rec_; + num_var_vecad_rec_ = play.num_var_vecad_rec_; + // + // pod_vectors + op_vec_ = play.op_vec_; + arg_vec_ = play.arg_vec_; + text_vec_ = play.text_vec_; + all_var_vecad_ind_ = play.all_var_vecad_ind_; + dyn_par_is_ = play.dyn_par_is_; + dyn_ind2par_ind_ = play.dyn_ind2par_ind_; + dyn_par_op_ = play.dyn_par_op_; + dyn_par_arg_ = play.dyn_par_arg_; + op2arg_vec_ = play.op2arg_vec_; + op2var_vec_ = play.op2var_vec_; + var2op_vec_ = play.var2op_vec_; + // + // pod_maybe_vectors + all_par_vec_ = play.all_par_vec_; + } + // =============================================================== + /// Create a player< AD > from this player + player< AD > base2ad(void) const + { player< AD > play; + // + // size_t objects + play.num_dynamic_ind_ = num_dynamic_ind_; + play.num_var_rec_ = num_var_rec_; + play.num_var_load_rec_ = num_var_load_rec_; + play.num_var_vecad_rec_ = num_var_vecad_rec_; + // + // pod_vectors + play.op_vec_ = op_vec_; + play.arg_vec_ = arg_vec_; + play.text_vec_ = text_vec_; + play.all_var_vecad_ind_ = all_var_vecad_ind_; + play.dyn_par_is_ = dyn_par_is_; + play.dyn_ind2par_ind_ = dyn_ind2par_ind_; + play.dyn_par_op_ = dyn_par_op_; + play.dyn_par_arg_ = dyn_par_arg_; + play.op2arg_vec_ = op2arg_vec_; + play.op2var_vec_ = op2var_vec_; + play.var2op_vec_ = var2op_vec_; + // + // pod_maybe_vector< AD > = pod_maybe_vector + play.all_par_vec_.resize( all_par_vec_.size() ); + for(size_t i = 0; i < all_par_vec_.size(); ++i) + play.all_par_vec_[i] = all_par_vec_[i]; + // + return play; + } + // =============================================================== + /// swap this recording with another recording + /// (used for move semantics version of ADFun assignment operation) + void swap(player& other) + { // size_t objects + std::swap(num_dynamic_ind_, other.num_dynamic_ind_); + std::swap(num_var_rec_, other.num_var_rec_); + std::swap(num_var_load_rec_, other.num_var_load_rec_); + std::swap(num_var_vecad_rec_, other.num_var_vecad_rec_); + // + // pod_vectors + op_vec_.swap( other.op_vec_); + arg_vec_.swap( other.arg_vec_); + text_vec_.swap( other.text_vec_); + all_var_vecad_ind_.swap( other.all_var_vecad_ind_); + dyn_par_is_.swap( other.dyn_par_is_); + dyn_ind2par_ind_.swap( other.dyn_ind2par_ind_); + dyn_par_op_.swap( other.dyn_par_op_); + dyn_par_arg_.swap( other.dyn_par_arg_); + op2arg_vec_.swap( other.op2arg_vec_); + op2var_vec_.swap( other.op2var_vec_); + var2op_vec_.swap( other.var2op_vec_); + // + // pod_maybe_vectors + all_par_vec_.swap( other.all_par_vec_); + } + // move semantics assignment + void operator=(player&& play) + { swap(play); } + // ================================================================= + /// Enable use of const_subgraph_iterator and member functions that begin + // with random_(no work if already setup). + template + void setup_random(void) + { play::random_setup( + num_var_rec_ , + op_vec_ , + arg_vec_ , + op2arg_vec_.pod_vector_ptr() , + op2var_vec_.pod_vector_ptr() , + var2op_vec_.pod_vector_ptr() + ); + } + /// Free memory used for functions that begin with random_ + /// and random iterators and subgraph iterators + void clear_random(void) + { + op2arg_vec_.clear(); + op2var_vec_.clear(); + var2op_vec_.clear(); + CPPAD_ASSERT_UNKNOWN( op2arg_vec_.size() == 0 ); + CPPAD_ASSERT_UNKNOWN( op2var_vec_.size() == 0 ); + CPPAD_ASSERT_UNKNOWN( var2op_vec_.size() == 0 ); + } + /// get non-const version of all_par_vec + pod_vector_maybe& all_par_vec(void) + { return all_par_vec_; } + /// get non-const version of all_par_vec + const pod_vector_maybe& all_par_vec(void) const + { return all_par_vec_; } + // ================================================================ + // const functions that retrieve infromation from this player + // ================================================================ + /// const version of dynamic parameter flag + const pod_vector& dyn_par_is(void) const + { return dyn_par_is_; } + /// const version of dynamic parameter index to parameter index + const pod_vector& dyn_ind2par_ind(void) const + { return dyn_ind2par_ind_; } + /// const version of dynamic parameter operator + const pod_vector& dyn_par_op(void) const + { return dyn_par_op_; } + /// const version of dynamic parameter arguments + const pod_vector& dyn_par_arg(void) const + { return dyn_par_arg_; } + /*! + \brief + fetch an operator from the recording. + + \return + the i-th operator in the recording. + + \param i + the index of the operator in recording + */ + OpCode GetOp (size_t i) const + { return OpCode(op_vec_[i]); } + + /*! + \brief + Fetch a VecAD index from the recording. + + \return + the i-th VecAD index in the recording. + + \param i + the index of the VecAD index in recording + */ + size_t GetVecInd (size_t i) const + { return size_t( all_var_vecad_ind_[i] ); } + + /*! + \brief + Fetch a parameter from the recording. + + \return + the i-th parameter in the recording. + + \param i + the index of the parameter in recording + */ + Base GetPar(size_t i) const + { return all_par_vec_[i]; } + + /*! + \brief + Fetch entire parameter vector from the recording. + + \return + the entire parameter vector. + + */ + const Base* GetPar(void) const + { return all_par_vec_.data(); } + + /*! + \brief + Fetch a '\\0' terminated string from the recording. + + \return + the beginning of the string. + + \param i + the index where the string begins. + */ + const char *GetTxt(size_t i) const + { CPPAD_ASSERT_UNKNOWN(i < text_vec_.size() ); + return text_vec_.data() + i; + } + + /// Fetch number of independent dynamic parameters in the recording + size_t num_dynamic_ind(void) const + { return num_dynamic_ind_; } + + /// Fetch number of dynamic parameters in the recording + size_t num_dynamic_par(void) const + { return dyn_par_op_.size(); } + + /// Fetch number of dynamic parameters operator arguments in the recording + size_t num_dynamic_arg(void) const + { return dyn_par_arg_.size(); } + + /// Fetch number of variables in the recording. + size_t num_var_rec(void) const + { return num_var_rec_; } + + /// Fetch number of vecad load operations + size_t num_var_load_rec(void) const + { return num_var_load_rec_; } + + /// Fetch number of operators in the recording. + size_t num_op_rec(void) const + { return op_vec_.size(); } + + /// Fetch number of VecAD indices in the recording. + size_t num_var_vecad_ind_rec(void) const + { return all_var_vecad_ind_.size(); } + + /// Fetch number of VecAD vectors in the recording + size_t num_var_vecad_rec(void) const + { return num_var_vecad_rec_; } + + /// Fetch number of argument indices in the recording. + size_t num_op_arg_rec(void) const + { return arg_vec_.size(); } + + /// Fetch number of parameters in the recording. + size_t num_par_rec(void) const + { return all_par_vec_.size(); } + + /// Fetch number of characters (representing strings) in the recording. + size_t num_text_rec(void) const + { return text_vec_.size(); } + + /// A measure of amount of memory used to store + /// the operation sequence, just lengths, not capacities. + /// In user api as f.size_op_seq(); see the file seq_property.omh. + size_t size_op_seq(void) const + { // check assumptions made by ad_fun::size_op_seq() + CPPAD_ASSERT_UNKNOWN( op_vec_.size() == num_op_rec() ); + CPPAD_ASSERT_UNKNOWN( arg_vec_.size() == num_op_arg_rec() ); + CPPAD_ASSERT_UNKNOWN( all_par_vec_.size() == num_par_rec() ); + CPPAD_ASSERT_UNKNOWN( text_vec_.size() == num_text_rec() ); + CPPAD_ASSERT_UNKNOWN( all_var_vecad_ind_.size() == num_var_vecad_ind_rec() ); + return op_vec_.size() * sizeof(opcode_t) + + arg_vec_.size() * sizeof(addr_t) + + all_par_vec_.size() * sizeof(Base) + + dyn_par_is_.size() * sizeof(bool) + + dyn_ind2par_ind_.size() * sizeof(addr_t) + + dyn_par_op_.size() * sizeof(opcode_t) + + dyn_par_arg_.size() * sizeof(addr_t) + + text_vec_.size() * sizeof(char) + + all_var_vecad_ind_.size() * sizeof(addr_t) + ; + } + /// A measure of amount of memory used for random access routine + /// In user api as f.size_random(); see the file seq_property.omh. + size_t size_random(void) const + { +# ifndef NDEBUG + if( op2arg_vec_.size() == 0 ) + { CPPAD_ASSERT_UNKNOWN( op2var_vec_.size() == 0 ); + CPPAD_ASSERT_UNKNOWN( var2op_vec_.size() == 0 ); + } + else + { size_t size = 0; + switch( address_type() ) + { case play::unsigned_short_enum: + size = sizeof(unsigned short); + break; + // + case play::unsigned_int_enum: + size = sizeof(unsigned int); + break; + // + case play::size_t_enum: + size = sizeof(size_t); + break; + + default: + CPPAD_ASSERT_UNKNOWN(false); + break; + } + CPPAD_ASSERT_UNKNOWN( op2arg_vec_.size()/size == num_op_rec() ); + CPPAD_ASSERT_UNKNOWN( op2var_vec_.size()/size == num_op_rec() ); + CPPAD_ASSERT_UNKNOWN( var2op_vec_.size()/size == num_var_rec() ); + } +# endif + CPPAD_ASSERT_UNKNOWN( sizeof(unsigned char) == 1 ); + return op2arg_vec_.size() + + op2var_vec_.size() + + var2op_vec_.size() + ; + } + // ----------------------------------------------------------------------- + /// const sequential iterator begin + play::const_sequential_iterator begin(void) const + { size_t op_index = 0; + size_t num_var = num_var_rec_; + return play::const_sequential_iterator( + num_var, &op_vec_, &arg_vec_, op_index + ); + } + /// const sequential iterator end + play::const_sequential_iterator end(void) const + { size_t op_index = op_vec_.size() - 1; + size_t num_var = num_var_rec_; + return play::const_sequential_iterator( + num_var, &op_vec_, &arg_vec_, op_index + ); + } + // ----------------------------------------------------------------------- + /// const subgraph iterator begin + play::const_subgraph_iterator begin_subgraph( + const play::const_random_iterator& random_itr , + const pod_vector* subgraph ) const + { size_t subgraph_index = 0; + return play::const_subgraph_iterator( + random_itr, + subgraph, + subgraph_index + ); + } + /// const subgraph iterator end + template + play::const_subgraph_iterator end_subgraph( + const play::const_random_iterator& random_itr , + const pod_vector* subgraph ) const + { size_t subgraph_index = subgraph->size() - 1; + return play::const_subgraph_iterator( + random_itr, + subgraph, + subgraph_index + ); + } + // ----------------------------------------------------------------------- + /// const random iterator + template + play::const_random_iterator get_random(void) const + { return play::const_random_iterator( + op_vec_, + arg_vec_, + op2arg_vec_.pod_vector_ptr(), + op2var_vec_.pod_vector_ptr(), + var2op_vec_.pod_vector_ptr() + ); + } +}; + +} } // END_CPPAD_lOCAL_NAMESPACE +# endif diff --git a/build-config/cppad/include/cppad/local/play/random_iterator.hpp b/build-config/cppad/include/cppad/local/play/random_iterator.hpp new file mode 100644 index 00000000..fa9e4da1 --- /dev/null +++ b/build-config/cppad/include/cppad/local/play/random_iterator.hpp @@ -0,0 +1,152 @@ +# ifndef CPPAD_LOCAL_PLAY_RANDOM_ITERATOR_HPP +# define CPPAD_LOCAL_PLAY_RANDOM_ITERATOR_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +// BEGIN_CPPAD_LOCAL_PLAY_NAMESPACE +namespace CppAD { namespace local { namespace play { + +/*! +\file random_iterator.hpp +*/ + +/*! +Constant random iterator for a player object. + +\tparam Addr +An integer type capable of representing the largest value in the vectors +arg_vec, op2arg_vec, op2var_vec, var2op_vec. +*/ +template +class const_random_iterator { +private: + /// vector of operators on the tape + const pod_vector* op_vec_; + + /// vector of arguments for all the operators + /// (note that this is same type as used in recorder; i.e., addr_t) + const pod_vector* arg_vec_; + + /// mapping from operator index to index of first argument in arg_vec_ + const pod_vector* op2arg_vec_; + + /// mapping from operator index to index of primary (last) result + const pod_vector* op2var_vec_; + + /// mapping from primary variable index to operator index + /// (only specified for primary variables) + const pod_vector* var2op_vec_; + +public: + /// default constructor + const_random_iterator(void) : + op_vec_(nullptr) , + arg_vec_(nullptr) , + op2arg_vec_(nullptr) , + op2var_vec_(nullptr) , + var2op_vec_(nullptr) + { } + /// default assignment operator + void operator=(const const_random_iterator& rhs) + { + op_vec_ = rhs.op_vec_; + op2arg_vec_ = rhs.op2arg_vec_; + op2var_vec_ = rhs.op2var_vec_; + var2op_vec_ = rhs.var2op_vec_; + return; + } + /*! + Create a random iterator + + \par var2op_vec + This variable is not needed and can be null if the var2op member + function is not used. + */ + const_random_iterator( + const pod_vector& op_vec , ///< op_vec_ + const pod_vector& arg_vec , ///< arg_vec_ + const pod_vector* op2arg_vec , ///< op2ar_vec_ + const pod_vector* op2var_vec , ///< op2var_vec_ + const pod_vector* var2op_vec ) ///< var2op_vec_ + : + op_vec_ ( &op_vec ) , + arg_vec_ ( &arg_vec ) , + op2arg_vec_ ( op2arg_vec ) , + op2var_vec_ ( op2var_vec ) , + var2op_vec_ ( var2op_vec ) + { } + /*! + \brief + fetch the information corresponding to an operator + + \param op_index + index for this operator [in] + + \param op [out] + op code for this operator. + + \param op_arg [out] + pointer to the first arguement to this operator. + + \param var_index [out] + index of the last variable (primary variable) for this operator. + If there is no primary variable for this operator, i_var not sepcified + and could have any value. + */ + void op_info( + size_t op_index , + OpCode& op , + const addr_t*& op_arg , + size_t& var_index ) const + { op = OpCode( (*op_vec_)[op_index] ); + op_arg = (*op2arg_vec_)[op_index] + arg_vec_->data(); + var_index = (*op2var_vec_)[op_index]; + return; + } + /*! + \brief + map variable index to operator index. + + \param var_index + must be the index of a primary variable. + + \return + is the index of the operator corresponding to this primary variable. + */ + size_t var2op(size_t var_index) const + { // check that var2op_vec was not null in constructor + CPPAD_ASSERT_UNKNOWN( var2op_vec_ != nullptr ); + // + // operator index + size_t op_index = size_t( (*var2op_vec_)[var_index] ); + // + // check that var_index is a primary variable index (see random_setup) + CPPAD_ASSERT_UNKNOWN( op_index < op_vec_->size() ); + // + return op_index; + } + /// get operator corresponding to operator index + OpCode get_op(size_t op_index) const + { return OpCode( (*op_vec_)[op_index] ); + } + /// number of operators + size_t num_op(void) const + { return op_vec_->size(); } + // + /// number of variables + size_t num_var(void) const + { return var2op_vec_->size(); } +}; + +} } } // BEGIN_CPPAD_LOCAL_PLAY_NAMESPACE + +# endif diff --git a/build-config/cppad/include/cppad/local/play/random_setup.hpp b/build-config/cppad/include/cppad/local/play/random_setup.hpp new file mode 100644 index 00000000..75570ebe --- /dev/null +++ b/build-config/cppad/include/cppad/local/play/random_setup.hpp @@ -0,0 +1,144 @@ +# ifndef CPPAD_LOCAL_PLAY_RANDOM_SETUP_HPP +# define CPPAD_LOCAL_PLAY_RANDOM_SETUP_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-18 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +// BEGIN_CPPAD_LOCAL_PLAY_NAMESPACE +namespace CppAD { namespace local { namespace play { + +/*! +\file random_setup.hpp +*/ + +/*! +Set up random access to a player object. + +\tparam Addr +An integer type capable of representing the largest value in the vectors +arg_vec, op2arg_vec, op2var_vec, var2op_vec. + +\param num_var +num_var is the number of variables in this operation sequence. + +\param op_vec +The mapping +op = OpCode[ op_vec[op_index] ] +maps from operator index op_index to the operator op. + +\param arg_vec +is a vector of all the arguments for all the operators. +The mapping op2arg_vec will map from operator indices +to index in this vector. + +\param op2arg_vec +On input, op2arg_vec is either the empty vector +(or contains the proper result from a previous call to random_setup). +Upon return it maps each operator index to the index in op_arg_vec of its +first argument for the operator. + +\param op2var_vec +On input, op2var_vec is either the empty vector +(or contains the proper result from a previous call to random_setup). +Upon return it maps each operator index to the primary (last) +result for the operator. If there are no results for the operator, +the return value map value is not specified. + +\param var2op_vec +On input, var2op_vec is either the empty vector +(or contains the proper result from a previous call to random_setup). +Upon return it maps each primary variable index to the corresponding +operator index. The value of the map is only specifed for primary variable +indices. +*/ +template +void random_setup( + size_t num_var , + const pod_vector& op_vec , + const pod_vector& arg_vec , + pod_vector* op2arg_vec , + pod_vector* op2var_vec , + pod_vector* var2op_vec ) +{ + if( op2arg_vec->size() != 0 ) + { CPPAD_ASSERT_UNKNOWN( op2arg_vec->size() == op_vec.size() ); + CPPAD_ASSERT_UNKNOWN( op2var_vec->size() == op_vec.size() ); + CPPAD_ASSERT_UNKNOWN( var2op_vec->size() == num_var ); + return; + } + CPPAD_ASSERT_UNKNOWN( op2var_vec->size() == 0 ); + CPPAD_ASSERT_UNKNOWN( op2var_vec->size() == 0 ); + CPPAD_ASSERT_UNKNOWN( var2op_vec->size() == 0 ); + CPPAD_ASSERT_UNKNOWN( OpCode( op_vec[0] ) == BeginOp ); + CPPAD_ASSERT_NARG_NRES(BeginOp, 1, 1); + // + size_t num_op = op_vec.size(); + size_t var_index = 0; + size_t arg_index = 0; + // + op2arg_vec->resize( num_op ); + op2var_vec->resize( num_op ); + var2op_vec->resize( num_var ); +# ifndef NDEBUG + // value of var2op for auxillary variables is num_op (invalid) + for(size_t i_var = 0; i_var < num_var; ++i_var) + (*var2op_vec)[i_var] = Addr( num_op ); + // value of op2var is num_var (invalid) when NumRes(op) = 0 + for(size_t i_op = 0; i_op < num_op; ++i_op) + (*op2var_vec)[i_op] = Addr( num_var ); +# endif + for(size_t i_op = 0; i_op < num_op; ++i_op) + { OpCode op = OpCode( op_vec[i_op] ); + // + // index of first argument for this operator + (*op2arg_vec)[i_op] = Addr( arg_index ); + arg_index += NumArg(op); + // + // index of first result for next operator + var_index += NumRes(op); + if( NumRes(op) > 0 ) + { // index of last (primary) result for this operator + (*op2var_vec)[i_op] = Addr( var_index - 1 ); + // + // mapping from primary variable to its operator + (*var2op_vec)[var_index - 1] = Addr( i_op ); + } + // CSumOp + if( op == CSumOp ) + { CPPAD_ASSERT_UNKNOWN( NumArg(CSumOp) == 0 ); + // + // pointer to first argument for this operator + const addr_t* op_arg = arg_vec.data() + arg_index; + // + // The actual number of arugments for this operator is + // op_arg[4] + 1 + // Correct index of first argument for next operator + arg_index += size_t(op_arg[4] + 1); + } + // + // CSkip + if( op == CSkipOp ) + { CPPAD_ASSERT_UNKNOWN( NumArg(CSumOp) == 0 ); + // + // pointer to first argument for this operator + const addr_t* op_arg = arg_vec.data() + arg_index; + // + // The actual number of arugments for this operator is + // 7 + op_arg[4] + op_arg[5]. + // Correct index of first argument for next operator. + arg_index += size_t(7 + op_arg[4] + op_arg[5]); + } + } +} + +} } } // BEGIN_CPPAD_LOCAL_PLAY_NAMESPACE + +# endif diff --git a/build-config/cppad/include/cppad/local/play/sequential_iterator.hpp b/build-config/cppad/include/cppad/local/play/sequential_iterator.hpp new file mode 100644 index 00000000..2fba394f --- /dev/null +++ b/build-config/cppad/include/cppad/local/play/sequential_iterator.hpp @@ -0,0 +1,290 @@ +# ifndef CPPAD_LOCAL_PLAY_SEQUENTIAL_ITERATOR_HPP +# define CPPAD_LOCAL_PLAY_SEQUENTIAL_ITERATOR_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +// BEGIN_CPPAD_LOCAL_PLAY_NAMESPACE +namespace CppAD { namespace local { namespace play { + +/*! +\file sequential_iterator.hpp +*/ + +/*! +Constant sequential iterator for a player object. + +\tparam Addr +An integer type capable of representing the largest value in the vectors +arg_vec, op2arg_vec, op2var_vec, var2op_vec. + +\par +Except for constructor, the public API for this class is the same as +for the subgraph_iterator class. +*/ +class const_sequential_iterator { +private: + /// pointer to the first operator in the player, BeginOp = *op_begin_ + const opcode_t* op_begin_; + + /// pointer one past last operator in the player, EndOp = *(op_end_ - 1) + const opcode_t* op_end_; + + /// pointer to the first argument for the first operator + const addr_t* arg_begin_; + + /// pointer on past last argumemnt for last operator + const addr_t* arg_end_; + + /// pointer to current operator + const opcode_t* op_cur_; + + /// pointer to first argument for current operator + const addr_t* arg_; + + /// number of variables in tape (not const for assignment operator) + size_t num_var_; + + /// index of last result for current operator + size_t var_index_; + + /// value of current operator; i.e. op_ = *op_cur_ + OpCode op_; +public: + /// default constructor + const_sequential_iterator(void) : + op_begin_(nullptr) , + op_end_(nullptr) , + arg_begin_(nullptr) , + arg_end_(nullptr) , + op_cur_(nullptr) , + arg_(nullptr) , + num_var_(0) , + var_index_(0) , + op_(NumberOp) + { } + /// assignment operator + void operator=(const const_sequential_iterator& rhs) + { + op_begin_ = rhs.op_begin_; + op_end_ = rhs.op_end_; + arg_begin_ = rhs.arg_begin_; + arg_end_ = rhs.arg_end_; + op_cur_ = rhs.op_cur_; + arg_ = rhs.arg_; + num_var_ = rhs.num_var_; + var_index_ = rhs.var_index_; + op_ = rhs.op_; + return; + } + /*! + Create a sequential iterator starting either at beginning or end of tape + + \param num_var + is the number of variables in the tape. + + \param op_vec + is the vector of operators on the tape. + + \param arg_vec + is the vector of arguments for all the operators + + \param op_index + is the operator index that iterator will start at. + It must be zero or op_vec_->size() - 1. + + \par Assumptions + - OpCode(op_vec_[0]) == BeginOp + - OpCode(op_vec_[op_vec_->size() - 1]) == EndOp + */ + const_sequential_iterator( + size_t num_var , + const pod_vector* op_vec , + const pod_vector* arg_vec , + size_t op_index ) + : + op_begin_ ( op_vec->data() ) , + op_end_ ( op_vec->data() + op_vec->size() ) , + arg_begin_ ( arg_vec->data() ) , + arg_end_ ( arg_vec->data() + arg_vec->size() ), + num_var_ ( num_var ) + { if( op_index == 0 ) + { + // index of last result for BeginOp + var_index_ = 0; + // + // first argument to BeginOp + arg_ = arg_vec->data(); + // + // BeginOp + op_cur_ = op_begin_; + op_ = OpCode( *op_cur_ ); + CPPAD_ASSERT_UNKNOWN( op_ == BeginOp ); + CPPAD_ASSERT_NARG_NRES(op_, 1, 1); + } + else + { CPPAD_ASSERT_UNKNOWN(op_index == op_vec->size()-1); + // + // index of last result for EndOp + var_index_ = num_var - 1; + // + // first argument to EndOp (has no arguments) + arg_ = arg_vec->data() + arg_vec->size(); + // + // EndOp + op_cur_ = op_end_ - 1; + op_ = OpCode( *op_cur_ ); + CPPAD_ASSERT_UNKNOWN( op_ == EndOp ); + CPPAD_ASSERT_NARG_NRES(op_, 0, 0); + } + } + /*! + Advance iterator to next operator + */ + const_sequential_iterator& operator++(void) + { + // first argument for next operator + arg_ += NumArg(op_); + // + // next operator + ++op_cur_; + op_ = OpCode( *op_cur_ ); + // + // last result for next operator + var_index_ += NumRes(op_); + // + return *this; + } + /*! + Correction applied before ++ operation when current operator + is CSumOp or CSkipOp. + */ + void correct_before_increment(void) + { // number of arguments for this operator depends on argument data + CPPAD_ASSERT_UNKNOWN( NumArg(op_) == 0 ); + const addr_t* arg = arg_; + // + // CSumOp + if( op_ == CSumOp ) + { // add actual number of arguments to arg_ + arg_ += arg[4] + 1; + } + // + // CSkip + else + { CPPAD_ASSERT_UNKNOWN( op_ == CSkipOp ); + // + CPPAD_ASSERT_UNKNOWN( arg + 5 < arg_end_ ); + addr_t n_skip = arg[4] + arg[5]; + CPPAD_ASSERT_UNKNOWN( n_skip == arg[6 + n_skip] ); + // + // add actual number of arguments to arg_ + arg_ += 7 + n_skip; + } + return; + } + /*! + Backup iterator to previous operator + */ + const_sequential_iterator& operator--(void) + { // + // last result for next operator + var_index_ -= NumRes(op_); + // + // next operator + --op_cur_; + op_ = OpCode( *op_cur_ ); + // + // first argument for next operator + arg_ -= NumArg(op_); + // + return *this; + } + /*! + Correction applied after -- operation when current operator + is CSumOp or CSkipOp. + + \param arg [out] + corrected point to arguments for this operation. + */ + void correct_after_decrement(const addr_t*& arg) + { // number of arguments for this operator depends on argument data + CPPAD_ASSERT_UNKNOWN( NumArg(op_) == 0 ); + // + // infromation for number of arguments is stored in arg_ - 1 + CPPAD_ASSERT_UNKNOWN( arg_begin_ < arg_ ); + // + // CSumOp + if( op_ == CSumOp ) + { // index of arg[4] + addr_t arg_4 = *(arg_ - 1); + // + // corrected index of first argument to this operator + arg = arg_ -= arg_4 + 1; + // + CPPAD_ASSERT_UNKNOWN( arg[arg[4] ] == arg[4] ); + } + // + // CSkip + else + { CPPAD_ASSERT_UNKNOWN( op_ == CSkipOp ); + // + // number to possibly skip is stored in last argument + addr_t n_skip = *(arg_ - 1); + // + // corrected index of frist argument to this operator + arg = arg_ -= 7 + n_skip; + // + CPPAD_ASSERT_UNKNOWN( arg[4] + arg[5] == n_skip ); + } + CPPAD_ASSERT_UNKNOWN( arg_begin_ <= arg ); + CPPAD_ASSERT_UNKNOWN( arg + NumArg(op_) <= arg_end_ ); + } + /*! + \brief + Get information corresponding to current operator. + + \param op [out] + op code for this operator. + + \param arg [out] + pointer to the first arguement to this operator. + + \param var_index [out] + index of the last variable (primary variable) for this operator. + If there is no primary variable for this operator, var_index + is not sepcified and could have any value. + */ + void op_info( + OpCode& op , + const addr_t*& arg , + size_t& var_index ) const + { // op + CPPAD_ASSERT_UNKNOWN( op_begin_ <= op_cur_ && op_cur_ < op_end_ ) + op = op_; + // + // arg + arg = arg_; + CPPAD_ASSERT_UNKNOWN( arg_begin_ <= arg ); + CPPAD_ASSERT_UNKNOWN( arg + NumArg(op) <= arg_end_ ); + // + // var_index + CPPAD_ASSERT_UNKNOWN( var_index_ < num_var_ || NumRes(op) == 0 ); + var_index = var_index_; + } + /// current operator index + size_t op_index(void) + { return size_t(op_cur_ - op_begin_); } +}; + +} } } // BEGIN_CPPAD_LOCAL_PLAY_NAMESPACE + +# endif diff --git a/build-config/cppad/include/cppad/local/play/subgraph_iterator.hpp b/build-config/cppad/include/cppad/local/play/subgraph_iterator.hpp new file mode 100644 index 00000000..036d844f --- /dev/null +++ b/build-config/cppad/include/cppad/local/play/subgraph_iterator.hpp @@ -0,0 +1,132 @@ +# ifndef CPPAD_LOCAL_PLAY_SUBGRAPH_ITERATOR_HPP +# define CPPAD_LOCAL_PLAY_SUBGRAPH_ITERATOR_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +# include + +// BEGIN_CPPAD_LOCAL_PLAY_NAMESPACE +namespace CppAD { namespace local { namespace play { + +/*! +\file random_iterator.hpp +*/ + +/*! +Constant subgraph iterator for a player object. + +\tparam Addr +An integer type capable of representing the largest value in the vectors +arg_vec, op2arg_vec, op2var_vec, var2op_vec. + +Except for constructor, the public API for this class is the same as +for the sequential iterator class. +*/ +template +class const_subgraph_iterator { +private: + /// a random iterator used to access player information + const const_random_iterator* random_itr_; + + /// sorted subset of operator indices that we will include + const pod_vector* subgraph_; + + /// index in subgraph of current operator + /// The initial value for this index must be zero or subgraph.size()-1. + size_t subgraph_index_; + +public: + /// default constructor + const_subgraph_iterator(void) : + random_itr_(nullptr) , + subgraph_(nullptr) , + subgraph_index_(0) + { } + /// default assignment operator + void operator=(const const_subgraph_iterator& rhs) + { + random_itr_ = rhs.random_itr_; + subgraph_ = rhs.subgraph_; + subgraph_index_ = rhs.subgraph_index_; + return; + } + /*! + Create a subgraph iterator starting either at beginning or end of subgraph + */ + const_subgraph_iterator( + const const_random_iterator& random_itr , ///< random_itr_ + const pod_vector* subgraph , ///< subgraph_ + size_t subgraph_index ) ///< subgraph_index_ + : + random_itr_ ( &random_itr ) , + subgraph_ ( subgraph ) , + subgraph_index_ ( subgraph_index ) + { CPPAD_ASSERT_UNKNOWN( + subgraph_index == 0 || subgraph_index == subgraph->size() - 1 + ); + } + /*! + Advance iterator to next operator + */ + const_subgraph_iterator& operator++(void) + { ++subgraph_index_; + return *this; + } + /// No correction necessary when using random access to player + void correct_before_increment(void) + { return; } + /*! + Backup iterator to previous operator + */ + const_subgraph_iterator& operator--(void) + { --subgraph_index_; + return *this; + } + /*! + No correction necessary when using random access to player. + + \param op_arg + not used or modified. + */ + void correct_after_decrement(const addr_t*& op_arg) + { return; } + /*! + \brief + Get information corresponding to current operator. + + \param op [out] + op code for this operator. + + \param op_arg [out] + pointer to the first arguement to this operator. + + \param var_index [out] + index of the last variable (primary variable) for this operator. + If there is no primary variable for this operator, var_index + is not sepcified and could have any value. + */ + void op_info( + OpCode& op , + const addr_t*& op_arg , + size_t& var_index ) const + { // op + size_t op_index = size_t( (*subgraph_)[subgraph_index_] ); + random_itr_->op_info(op_index, op, op_arg, var_index); + } + /// current operator index + size_t op_index(void) + { return size_t( (*subgraph_)[subgraph_index_] ); } +}; + +} } } // BEGIN_CPPAD_LOCAL_PLAY_NAMESPACE + +# endif diff --git a/build-config/cppad/include/cppad/local/pod_vector.hpp b/build-config/cppad/include/cppad/local/pod_vector.hpp new file mode 100644 index 00000000..3af47c6e --- /dev/null +++ b/build-config/cppad/include/cppad/local/pod_vector.hpp @@ -0,0 +1,565 @@ +# ifndef CPPAD_LOCAL_POD_VECTOR_HPP +# define CPPAD_LOCAL_POD_VECTOR_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +# if CPPAD_CSTDINT_HAS_8_TO_64 +# include +# endif +# include +# include +# include +# include +# include + +namespace CppAD { namespace local { // BEGIN_CPPAD_LOCAL_NAMESPACE +/*! +\file pod_vector.hpp +File used to define pod_vector classes +*/ +// --------------------------------------------------------------------------- +/*! +A vector class with that does not use element constructors or destructors +(elements are Plain Old Data; i.e., is_pod must be true). + +*/ +template +class pod_vector { +private: + /// maximum number of bytes current allocation can hold + size_t byte_capacity_; + + /// number of bytes currently in this vector + size_t byte_length_; + + /// pointer to the first type elements + /// (not defined and should not be used when byte_capacity_ = 0) + Type *data_; + + /// do not use the copy constructor + explicit pod_vector(const pod_vector& ) + { CPPAD_ASSERT_UNKNOWN(false); } +public: + /// default constructor sets byte_capacity_ = byte_length_ = data_ = 0 + pod_vector(void) + : byte_capacity_(0), byte_length_(0), data_(nullptr) + { CPPAD_ASSERT_UNKNOWN( is_pod() ); + } + + /// sizing constructor + pod_vector( + /// number of elements in this vector + size_t n ) + : byte_capacity_(0), byte_length_(0), data_(nullptr) + { CPPAD_ASSERT_UNKNOWN( is_pod() ); + extend(n); + } + + /// Destructor: returns allocated memory to thread_alloc; + /// see extend and resize. If this is not plain old data, + /// the destructor for each element is called. + ~pod_vector(void) + { if( byte_capacity_ > 0 ) + { + void* v_ptr = reinterpret_cast( data_ ); + thread_alloc::return_memory(v_ptr); + } + } + + /* + Return a pointer to a pod_vector with a different type of element. + + - This vector and the other share the same memory. + + - The the other vector should not be deleted. + + - The following operations work the same for this and the other vector: + swap, clear, assignment. + */ + template + pod_vector* pod_vector_ptr(void) + { return reinterpret_cast< pod_vector* >(this); + } + template + const pod_vector* pod_vector_ptr(void) const + { return reinterpret_cast< const pod_vector* >(this); + } + + /// current number of elements in this vector. + size_t size(void) const + { return byte_length_ / sizeof(Type); } + + /// current capacity (amount of allocated storage) for this vector. + size_t capacity(void) const + { return byte_capacity_ / sizeof(Type); } + + /// current data pointer is no longer valid after any of the following: + /// extend, resize, erase, clear, assignment and destructor. + Type* data(void) + { return data_; } + + /// const version of data pointer (see non-const documentation) + const Type* data(void) const + { return data_; } + + // ---------------------------------------------------------------------- + /// non-constant element access; i.e., we can change this element value + Type& operator[]( + /// element index, must be less than length + size_t i + ) + { CPPAD_ASSERT_UNKNOWN( i * sizeof(Type) < byte_length_ ); + return data_[i]; + } + /// non-constant element access; i.e., we can change this element value + template + Type& operator[]( + /// element index, must be less than length and convertable to size_t + Index i + ) + { return (*this)[size_t(i)]; } + // ---------------------------------------------------------------------- + /// constant element access; i.e., we cannot change this element value + const Type& operator[]( + /// element index, must be less than length + size_t i + ) const + { CPPAD_ASSERT_UNKNOWN( i * sizeof(Type) < byte_length_ ); + return data_[i]; + } + /// constant element access; i.e., we cannot change this element value + template + const Type& operator[]( + /// element index, must be less than length and convertable to size_t + Index i + ) const + { return (*this)[size_t(i)]; } + // ---------------------------------------------------------------------- + + /*! + Add an element to theh back of this vector + + \param e + is the element we are adding to the back of the vector. + */ + void push_back(const Type& e) + { size_t i = extend(1); + data_[i] = e; + } + + /*! + Swap all properties of this vector with another. + This is useful when moving a vector that grows after it has reached + its final size (without copying every element). + + \param other + is the other vector that we are swapping this vector with. + */ + void swap(pod_vector& other) + { std::swap(byte_capacity_, other.byte_capacity_); + std::swap(byte_length_, other.byte_length_); + std::swap(data_, other.data_); + } + // ---------------------------------------------------------------------- + /*! + Increase the number of elements the end of this vector + (existing elements are always preserved). + + \param n + is the number of elements to add to end of this vector. + + \return + is the number of elements in the vector before it was extended. + This is the index of the first new element added to the vector. + + - If Type is plain old data, new elements are not initialized; + i.e., their constructor is not called. Otherwise, the constructor + is called for each new element. + + - This and resize are the only routine that allocate memory for + pod_vector. They uses thread_alloc for this allocation. + */ + size_t extend(size_t n) + { size_t old_length = byte_length_; + byte_length_ += n * sizeof(Type); + + // check if we can use current memory + if( byte_length_ <= byte_capacity_ ) + return old_length / sizeof(Type); + + // save more old information + size_t old_capacity = byte_capacity_; + void* old_v_ptr = reinterpret_cast(data_); + + // get new memory and set capacity + void* v_ptr = thread_alloc::get_memory(byte_length_, byte_capacity_); + data_ = reinterpret_cast(v_ptr); + + // copy old data to new + if( old_length > 0 ) + std::memcpy(v_ptr, old_v_ptr, old_length); + + // return old memory to available pool + if( old_capacity > 0 ) + thread_alloc::return_memory(old_v_ptr); + + // return value for extend(n) is the old length + CPPAD_ASSERT_UNKNOWN( byte_length_ <= byte_capacity_ ); + return old_length / sizeof(Type); + } + // ---------------------------------------------------------------------- + /*! + resize the vector (existing elements preserved when n <= capacity() ). + + \param n + is the new size for this vector. + + \par + if n <= capacity(), no memory is freed or allocated, the capacity + is not changed, and existing elements are preserved. + If n > capacity(), new memory is allocates and all the + data in the vector is lost. + + - If Type is plain old data, new elements are not initialized; + i.e., their constructor is not called. Otherwise, the constructor + is called for each new element. + + - This and extend are the only routine that allocate memory for + pod_vector. They uses thread_alloc for this allocation. + */ + void resize(size_t n) + { byte_length_ = n * sizeof(Type); + + // check if we must allocate new memory + if( byte_capacity_ < byte_length_ ) + { void* v_ptr; + // + if( byte_capacity_ > 0 ) + { // return old memory to available pool + v_ptr = reinterpret_cast( data_ ); + thread_alloc::return_memory(v_ptr); + } + // + // get new memory and set capacity + v_ptr = thread_alloc::get_memory(byte_length_, byte_capacity_); + data_ = reinterpret_cast(v_ptr); + // + } + CPPAD_ASSERT_UNKNOWN( byte_length_ <= byte_capacity_ ); + } + // ---------------------------------------------------------------------- + /*! + Remove all the elements from this vector and free its memory. + */ + void clear(void) + { if( byte_capacity_ > 0 ) + { + void* v_ptr = reinterpret_cast( data_ ); + thread_alloc::return_memory(v_ptr); + } + data_ = nullptr; + byte_capacity_ = 0; + byte_length_ = 0; + } + // ----------------------------------------------------------------------- + /// vector assignment operator + void operator=( + /// right hand size of the assingment operation + const pod_vector& x + ) + { CPPAD_ASSERT_UNKNOWN( x.byte_length_ % sizeof(Type) == 0 ); + resize( x.byte_length_ / sizeof(Type) ); + if( byte_length_ > 0 ) + { + void* v_ptr = reinterpret_cast( data_ ); + void* v_ptr_x = reinterpret_cast( x.data_ ); + std::memcpy(v_ptr, v_ptr_x, byte_length_); + } + + } +}; +// --------------------------------------------------------------------------- +/*! +A vector class with that does not use element constructors or destructors +when is_pod is true. +*/ +template +class pod_vector_maybe { +private: + /// maximum number of Type elements current allocation can hold + size_t capacity_; + + /// number of elements currently in this vector + size_t length_; + + /// pointer to the first type elements + /// (not defined and should not be used when capacity_ = 0) + Type *data_; + + /// do not use the copy constructor + explicit pod_vector_maybe(const pod_vector_maybe& ) + { CPPAD_ASSERT_UNKNOWN(false); } +public: + /// default constructor sets capacity_ = length_ = data_ = 0 + pod_vector_maybe(void) + : capacity_(0), length_(0), data_(nullptr) + { CPPAD_ASSERT_UNKNOWN( is_pod() ); + } + + /// sizing constructor + pod_vector_maybe( + /// number of elements in this vector + size_t n ) + : capacity_(0), length_(0), data_(nullptr) + { extend(n); } + + + /// Destructor: returns allocated memory to thread_alloc; + /// see extend and resize. If this is not plain old data, + /// the destructor for each element is called. + ~pod_vector_maybe(void) + { if( capacity_ > 0 ) + { if( ! is_pod() ) + { // call destructor for each element + for(size_t i = 0; i < capacity_; i++) + (data_ + i)->~Type(); + } + void* v_ptr = reinterpret_cast( data_ ); + thread_alloc::return_memory(v_ptr); + } + } + + /// current number of elements in this vector. + size_t size(void) const + { return length_; } + + /// current capacity (amount of allocated storage) for this vector. + size_t capacity(void) const + { return capacity_; } + + /// current data pointer is no longer valid after any of the following: + /// extend, resize, erase, clear, assignment, and destructor. + Type* data(void) + { return data_; } + + /// const version of data pointer (see non-const documentation) + const Type* data(void) const + { return data_; } + // ---------------------------------------------------------------------- + /// non-constant element access; i.e., we can change this element value + Type& operator[]( + /// element index, must be less than length + size_t i + ) + { CPPAD_ASSERT_UNKNOWN( i < length_ ); + return data_[i]; + } + /// non-constant element access; i.e., we can change this element value + template + Type& operator[]( + /// element index, must be less than length and convertable to size_t + Index i + ) + { return (*this)[size_t(i)]; } + + // ---------------------------------------------------------------------- + /// constant element access; i.e., we cannot change this element value + const Type& operator[]( + /// element index, must be less than length + size_t i + ) const + { CPPAD_ASSERT_UNKNOWN( i < length_ ); + return data_[i]; + } + /// constant element access; i.e., we cannot change this element value + template + const Type& operator[]( + /// element index, must be less than length and convertable to size_t + Index i + ) const + { return (*this)[size_t(i)]; } + + // ---------------------------------------------------------------------- + /*! + Add an element to theh back of this vector + + \param e + is the element we are adding to the back of the vector. + */ + void push_back(const Type& e) + { size_t i = extend(1); + data_[i] = e; + } + + /*! + Swap all properties of this vector with another. + This is useful when moving a vector that grows after it has reached + its final size (without copying every element). + + \param other + is the other vector that we are swapping this vector with. + */ + void swap(pod_vector_maybe& other) + { std::swap(capacity_, other.capacity_); + std::swap(length_, other.length_); + std::swap(data_, other.data_); + } + // ---------------------------------------------------------------------- + /*! + Increase the number of elements the end of this vector + (existing elements are always preserved). + + \param n + is the number of elements to add to end of this vector. + + \return + is the number of elements in the vector before it was extended. + This is the index of the first new element added to the vector. + + - If Type is plain old data, new elements are not initialized; + i.e., their constructor is not called. Otherwise, the constructor + is called for each new element. + + - This and resize are the only routine that allocate memory for + pod_vector_maybe. They uses thread_alloc for this allocation. + */ + size_t extend(size_t n) + { size_t old_length = length_; + length_ += n; + + // check if we can use current memory + if( length_ <= capacity_ ) + return old_length; + + // save more old information + size_t old_capacity = capacity_; + Type* old_data = data_; + + // get new memory and set capacity + size_t length_bytes = length_ * sizeof(Type); + size_t capacity_bytes; + void* v_ptr = thread_alloc::get_memory(length_bytes, capacity_bytes); + capacity_ = capacity_bytes / sizeof(Type); + data_ = reinterpret_cast(v_ptr); + + if( ! is_pod() ) + { // call constructor for each new element + for(size_t i = 0; i < capacity_; i++) + new(data_ + i) Type(); + } + + // copy old data to new + for(size_t i = 0; i < old_length; i++) + data_[i] = old_data[i]; + + // return old memory to available pool + if( old_capacity > 0 ) + { if( ! is_pod() ) + { for(size_t i = 0; i < old_capacity; i++) + (old_data + i)->~Type(); + } + v_ptr = reinterpret_cast( old_data ); + thread_alloc::return_memory(v_ptr); + } + + // return value for extend(n) is the old length + CPPAD_ASSERT_UNKNOWN( length_ <= capacity_ ); + return old_length; + } + // ---------------------------------------------------------------------- + /*! + resize the vector (existing elements preserved when n <= capacity_). + + \param n + is the new size for this vector. + + \par + if n <= capacity(), no memory is freed or allocated, the capacity + is not changed, and existing elements are preserved. + If n > capacity(), new memory is allocates and all the + data in the vector is lost. + + - If Type is plain old data, new elements are not initialized; + i.e., their constructor is not called. Otherwise, the constructor + is called for each new element. + + - This and extend are the only routine that allocate memory for + pod_vector_maybe. They uses thread_alloc for this allocation. + */ + void resize(size_t n) + { length_ = n; + + // check if we must allocate new memory + if( capacity_ < length_ ) + { void* v_ptr; + // + // return old memory to available pool + if( capacity_ > 0 ) + { if( ! is_pod() ) + { // call destructor for each old element + for(size_t i = 0; i < capacity_; i++) + (data_ + i)->~Type(); + } + v_ptr = reinterpret_cast( data_ ); + thread_alloc::return_memory(v_ptr); + } + // + // get new memory and set capacity + size_t length_bytes = length_ * sizeof(Type); + size_t capacity_bytes; + v_ptr = thread_alloc::get_memory(length_bytes, capacity_bytes); + capacity_ = capacity_bytes / sizeof(Type); + data_ = reinterpret_cast(v_ptr); + // + CPPAD_ASSERT_UNKNOWN( length_ <= capacity_ ); + // + if( ! is_pod() ) + { // call constructor for each new element + for(size_t i = 0; i < capacity_; i++) + new(data_ + i) Type(); + } + } + } + // ---------------------------------------------------------------------- + /*! + Remove all the elements from this vector and free its memory. + */ + void clear(void) + { if( capacity_ > 0 ) + { if( ! is_pod() ) + { // call destructor for each element + for(size_t i = 0; i < capacity_; i++) + (data_ + i)->~Type(); + } + void* v_ptr = reinterpret_cast( data_ ); + thread_alloc::return_memory(v_ptr); + } + data_ = nullptr; + capacity_ = 0; + length_ = 0; + } + // ----------------------------------------------------------------------- + /// vector assignment operator + void operator=( + /// right hand size of the assingment operation + const pod_vector_maybe& x + ) + { resize( x.length_ ); + // + CPPAD_ASSERT_UNKNOWN( length_ == x.length_ ); + for(size_t i = 0; i < length_; i++) + { data_[i] = x.data_[i]; } + } +}; + +} } // END_CPPAD_LOCAL_NAMESPACE +# endif diff --git a/build-config/cppad/include/cppad/local/pow_op.hpp b/build-config/cppad/include/cppad/local/pow_op.hpp new file mode 100644 index 00000000..6994756f --- /dev/null +++ b/build-config/cppad/include/cppad/local/pow_op.hpp @@ -0,0 +1,672 @@ +# ifndef CPPAD_LOCAL_POW_OP_HPP +# define CPPAD_LOCAL_POW_OP_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +namespace CppAD { namespace local { // BEGIN_CPPAD_LOCAL_NAMESPACE +/*! +\file pow_op.hpp +Forward and reverse mode calculations for z = pow(x, y). +*/ + +// --------------------------- Powvv ----------------------------------------- +/*! +Compute forward mode Taylor coefficients for result of op = PowvvOp. + +In the documentation below, +this operations is for the case where both x and y are variables +and the argument parameter is not used. + +\copydetails CppAD::local::forward_pow_op +*/ + +template +void forward_powvv_op( + size_t p , + size_t q , + size_t i_z , + const addr_t* arg , + const Base* parameter , + size_t cap_order , + Base* taylor ) +{ + // convert from final result to first result + i_z -= 2; // 2 = NumRes(PowvvOp) - 1; + + // check assumptions + CPPAD_ASSERT_UNKNOWN( NumArg(PowvvOp) == 2 ); + CPPAD_ASSERT_UNKNOWN( NumRes(PowvvOp) == 3 ); + CPPAD_ASSERT_UNKNOWN( q < cap_order ); + CPPAD_ASSERT_UNKNOWN( p <= q ); + CPPAD_ASSERT_UNKNOWN( + size_t( std::numeric_limits::max() ) >= i_z + ); + + // z_0 = log(x) + forward_log_op(p, q, i_z, size_t(arg[0]), cap_order, taylor); + + // z_1 = z_0 * y + addr_t adr[2]; + adr[0] = addr_t( i_z ); + adr[1] = arg[1]; + forward_mulvv_op(p, q, i_z+1, adr, parameter, cap_order, taylor); + + // z_2 = exp(z_1) + // final result for zero order case is exactly the same as for Base + if( p == 0 ) + { // Taylor coefficients corresponding to arguments and result + Base* x = taylor + size_t(arg[0]) * cap_order; + Base* y = taylor + size_t(arg[1]) * cap_order; + Base* z_2 = taylor + (i_z+2) * cap_order; + + z_2[0] = pow(x[0], y[0]); + p++; + } + if( p <= q ) + forward_exp_op(p, q, i_z+2, i_z+1, cap_order, taylor); +} +/*! +Multiple directions forward mode Taylor coefficients for op = PowvvOp. + +The C++ source code corresponding to this operation is +\verbatim + z = pow(x, y) +\endverbatim +In the documentation below, +this operations is for the case where x is a variable and y is a parameter. + +\copydetails CppAD::local::forward_pow_op_dir +*/ + +template +void forward_powvv_op_dir( + size_t q , + size_t r , + size_t i_z , + const addr_t* arg , + const Base* parameter , + size_t cap_order , + Base* taylor ) +{ + // convert from final result to first result + i_z -= 2; // 2 = NumRes(PowvvOp) - 1 + + // check assumptions + CPPAD_ASSERT_UNKNOWN( NumArg(PowvvOp) == 2 ); + CPPAD_ASSERT_UNKNOWN( NumRes(PowvvOp) == 3 ); + CPPAD_ASSERT_UNKNOWN( 0 < q ); + CPPAD_ASSERT_UNKNOWN( q < cap_order ); + CPPAD_ASSERT_UNKNOWN( + size_t( std::numeric_limits::max() ) >= i_z + ); + + // z_0 = log(x) + forward_log_op_dir(q, r, i_z, size_t(arg[0]), cap_order, taylor); + + // z_1 = y * z_0 + addr_t adr[2]; + adr[0] = addr_t( i_z ); + adr[1] = arg[1]; + forward_mulvv_op_dir(q, r, i_z+1, adr, parameter, cap_order, taylor); + + // z_2 = exp(z_1) + forward_exp_op_dir(q, r, i_z+2, i_z+1, cap_order, taylor); +} +/*! +Compute zero order forward mode Taylor coefficients for result of op = PowvvOp. + +The C++ source code corresponding to this operation is +\verbatim + z = pow(x, y) +\endverbatim +In the documentation below, +this operations is for the case where both x and y are variables +and the argument parameter is not used. + +\copydetails CppAD::local::forward_pow_op_0 +*/ + +template +void forward_powvv_op_0( + size_t i_z , + const addr_t* arg , + const Base* parameter , + size_t cap_order , + Base* taylor ) +{ + // convert from final result to first result + i_z -= 2; // NumRes(PowvvOp) - 1; + + // check assumptions + CPPAD_ASSERT_UNKNOWN( NumArg(PowvvOp) == 2 ); + CPPAD_ASSERT_UNKNOWN( NumRes(PowvvOp) == 3 ); + + // Taylor coefficients corresponding to arguments and result + Base* x = taylor + size_t(arg[0]) * cap_order; + Base* y = taylor + size_t(arg[1]) * cap_order; + Base* z_0 = taylor + i_z * cap_order; + Base* z_1 = z_0 + cap_order; + Base* z_2 = z_1 + cap_order; + + z_0[0] = log( x[0] ); + z_1[0] = z_0[0] * y[0]; + z_2[0] = pow(x[0], y[0]); + +} + +/*! +Compute reverse mode partial derivatives for result of op = PowvvOp. + +The C++ source code corresponding to this operation is +\verbatim + z = pow(x, y) +\endverbatim +In the documentation below, +this operations is for the case where both x and y are variables +and the argument parameter is not used. + +\copydetails CppAD::local::reverse_pow_op +*/ + +template +void reverse_powvv_op( + size_t d , + size_t i_z , + const addr_t* arg , + const Base* parameter , + size_t cap_order , + const Base* taylor , + size_t nc_partial , + Base* partial ) +{ + // convert from final result to first result + i_z -= 2; // NumRes(PowvvOp) - 1; + + // check assumptions + CPPAD_ASSERT_UNKNOWN( NumArg(PowvvOp) == 2 ); + CPPAD_ASSERT_UNKNOWN( NumRes(PowvvOp) == 3 ); + CPPAD_ASSERT_UNKNOWN( d < cap_order ); + CPPAD_ASSERT_UNKNOWN( d < nc_partial ); + CPPAD_ASSERT_UNKNOWN( + size_t( std::numeric_limits::max() ) >= i_z + ); + + // z_2 = exp(z_1) + reverse_exp_op( + d, i_z+2, i_z+1, cap_order, taylor, nc_partial, partial + ); + + // z_1 = z_0 * y + addr_t adr[2]; + adr[0] = addr_t( i_z ); + adr[1] = arg[1]; + reverse_mulvv_op( + d, i_z+1, adr, parameter, cap_order, taylor, nc_partial, partial + ); + + // z_0 = log(x) + reverse_log_op( + d, i_z, size_t(arg[0]), cap_order, taylor, nc_partial, partial + ); +} + +// --------------------------- Powpv ----------------------------------------- +/*! +Compute forward mode Taylor coefficients for result of op = PowpvOp. + +The C++ source code corresponding to this operation is +\verbatim + z = pow(x, y) +\endverbatim +In the documentation below, +this operations is for the case where x is a parameter and y is a variable. + +\copydetails CppAD::local::forward_pow_op +*/ + +template +void forward_powpv_op( + size_t p , + size_t q , + size_t i_z , + const addr_t* arg , + const Base* parameter , + size_t cap_order , + Base* taylor ) +{ + // convert from final result to first result + i_z -= 2; // 2 = NumRes(PowpvOp) - 1; + + // check assumptions + CPPAD_ASSERT_UNKNOWN( NumArg(PowpvOp) == 2 ); + CPPAD_ASSERT_UNKNOWN( NumRes(PowpvOp) == 3 ); + CPPAD_ASSERT_UNKNOWN( q < cap_order ); + CPPAD_ASSERT_UNKNOWN( p <= q ); + + // Taylor coefficients corresponding to arguments and result + Base* z_0 = taylor + i_z * cap_order; + + // z_0 = log(x) + Base x = parameter[ arg[0] ]; + size_t d; + for(d = p; d <= q; d++) + { if( d == 0 ) + z_0[d] = log(x); + else + z_0[d] = Base(0.0); + } + + // 2DO: remove requirement that i_z * cap_order <= max addr_t value + CPPAD_ASSERT_KNOWN( + size_t( std::numeric_limits::max() ) >= i_z * cap_order, + "cppad_tape_addr_type maximum value has been exceeded\n" + "This is due to a kludge in the pow operation and should be fixed." + ); + + // z_1 = z_0 * y + addr_t adr[2]; + // offset of z_i in taylor (as if it were a parameter); i.e., log(x) + adr[0] = addr_t( i_z * cap_order ); + // offset of y in taylor (as a variable) + adr[1] = arg[1]; + + // Trick: use taylor both for the parameter vector and variable values + forward_mulpv_op(p, q, i_z+1, adr, taylor, cap_order, taylor); + + // z_2 = exp(z_1) + // zero order case exactly same as Base type operation + if( p == 0 ) + { Base* y = taylor + size_t(arg[1]) * cap_order; + Base* z_2 = taylor + (i_z+2) * cap_order; + z_2[0] = pow(x, y[0]); + p++; + } + if( p <= q ) + forward_exp_op(p, q, i_z+2, i_z+1, cap_order, taylor); +} +/*! +Multiple directions forward mode Taylor coefficients for op = PowpvOp. + +The C++ source code corresponding to this operation is +\verbatim + z = pow(x, y) +\endverbatim +In the documentation below, +this operations is for the case where x is a parameter and y is a variable. + +\copydetails CppAD::local::forward_pow_op_dir +*/ + +template +void forward_powpv_op_dir( + size_t q , + size_t r , + size_t i_z , + const addr_t* arg , + const Base* parameter , + size_t cap_order , + Base* taylor ) +{ + // convert from final result to first result + i_z -= 2; // 2 = NumRes(PowpvOp) - 1; + + // check assumptions + CPPAD_ASSERT_UNKNOWN( NumArg(PowpvOp) == 2 ); + CPPAD_ASSERT_UNKNOWN( NumRes(PowpvOp) == 3 ); + CPPAD_ASSERT_UNKNOWN( 0 < q ); + CPPAD_ASSERT_UNKNOWN( q < cap_order ); + + // Taylor coefficients corresponding to arguments and result + size_t num_taylor_per_var = (cap_order-1) * r + 1; + Base* z_0 = taylor + i_z * num_taylor_per_var; + + // z_0 = log(x) + size_t m = (q-1) * r + 1; + for(size_t ell = 0; ell < r; ell++) + z_0[m+ell] = Base(0.0); + + // 2DO: remove requirement i_z * num_taylor_per_var <= max addr_t value + CPPAD_ASSERT_KNOWN( + size_t( std::numeric_limits::max() ) >= i_z * num_taylor_per_var, + "cppad_tape_addr_type maximum value has been exceeded\n" + "This is due to a kludge in the pow operation and should be fixed." + ); + + // z_1 = z_0 * y + addr_t adr[2]; + // offset of z_0 in taylor (as if it were a parameter); i.e., log(x) + adr[0] = addr_t( i_z * num_taylor_per_var ); + // ofset of y in taylor (as a variable) + adr[1] = arg[1]; + + // Trick: use taylor both for the parameter vector and variable values + forward_mulpv_op_dir(q, r, i_z+1, adr, taylor, cap_order, taylor); + + // z_2 = exp(z_1) + forward_exp_op_dir(q, r, i_z+2, i_z+1, cap_order, taylor); +} +/*! +Compute zero order forward mode Taylor coefficient for result of op = PowpvOp. + +The C++ source code corresponding to this operation is +\verbatim + z = pow(x, y) +\endverbatim +In the documentation below, +this operations is for the case where x is a parameter and y is a variable. + +\copydetails CppAD::local::forward_pow_op_0 +*/ + +template +void forward_powpv_op_0( + size_t i_z , + const addr_t* arg , + const Base* parameter , + size_t cap_order , + Base* taylor ) +{ + // convert from final result to first result + i_z -= 2; // NumRes(PowpvOp) - 1; + + // check assumptions + CPPAD_ASSERT_UNKNOWN( NumArg(PowpvOp) == 2 ); + CPPAD_ASSERT_UNKNOWN( NumRes(PowpvOp) == 3 ); + + // Paraemter value + Base x = parameter[ arg[0] ]; + + // Taylor coefficients corresponding to arguments and result + Base* y = taylor + size_t(arg[1]) * cap_order; + Base* z_0 = taylor + i_z * cap_order; + Base* z_1 = z_0 + cap_order; + Base* z_2 = z_1 + cap_order; + + // z_0 = log(x) + z_0[0] = log(x); + + // z_1 = z_0 * y + z_1[0] = z_0[0] * y[0]; + + // z_2 = exp(z_1) + // zero order case exactly same as Base type operation + z_2[0] = pow(x, y[0]); +} + +/*! +Compute reverse mode partial derivative for result of op = PowpvOp. + +The C++ source code corresponding to this operation is +\verbatim + z = pow(x, y) +\endverbatim +In the documentation below, +this operations is for the case where x is a parameter and y is a variable. + +\copydetails CppAD::local::reverse_pow_op +*/ + +template +void reverse_powpv_op( + size_t d , + size_t i_z , + const addr_t* arg , + const Base* parameter , + size_t cap_order , + const Base* taylor , + size_t nc_partial , + Base* partial ) +{ + // convert from final result to first result + i_z -= 2; // NumRes(PowpvOp) - 1; + + // check assumptions + CPPAD_ASSERT_UNKNOWN( NumArg(PowvvOp) == 2 ); + CPPAD_ASSERT_UNKNOWN( NumRes(PowvvOp) == 3 ); + CPPAD_ASSERT_UNKNOWN( d < cap_order ); + CPPAD_ASSERT_UNKNOWN( d < nc_partial ); + + // z_2 = exp(z_1) + reverse_exp_op( + d, i_z+2, i_z+1, cap_order, taylor, nc_partial, partial + ); + + // 2DO: remove requirement that i_z * cap_order <= max addr_t value + CPPAD_ASSERT_KNOWN( + size_t( std::numeric_limits::max() ) >= i_z * cap_order, + "cppad_tape_addr_type maximum value has been exceeded\n" + "This is due to a kludge in the pow operation and should be fixed." + ); + + // z_1 = z_0 * y + addr_t adr[2]; + adr[0] = addr_t( i_z * cap_order ); // offset of z_0[0] in taylor + adr[1] = arg[1]; // index of y in taylor and partial + // use taylor both for parameter and variable values + reverse_mulpv_op( + d, i_z+1, adr, taylor, cap_order, taylor, nc_partial, partial + ); + + // z_0 = log(x) + // x is a parameter +} + +// --------------------------- Powvp ----------------------------------------- +/*! +Compute forward mode Taylor coefficients for result of op = PowvpOp. + +The C++ source code corresponding to this operation is +\verbatim + z = pow(x, y) +\endverbatim +In the documentation below, +this operations is for the case where x is a variable and y is a parameter. + +\copydetails CppAD::local::forward_pow_op +*/ + +template +void forward_powvp_op( + size_t p , + size_t q , + size_t i_z , + const addr_t* arg , + const Base* parameter , + size_t cap_order , + Base* taylor ) +{ + // convert from final result to first result + i_z -= 2; // 2 = NumRes(PowvpOp) - 1 + + // check assumptions + CPPAD_ASSERT_UNKNOWN( NumArg(PowvpOp) == 2 ); + CPPAD_ASSERT_UNKNOWN( NumRes(PowvpOp) == 3 ); + CPPAD_ASSERT_UNKNOWN( q < cap_order ); + CPPAD_ASSERT_UNKNOWN( p <= q ); + CPPAD_ASSERT_UNKNOWN( + size_t( std::numeric_limits::max() ) >= i_z + ); + + // z_0 = log(x) + forward_log_op(p, q, i_z, size_t(arg[0]), cap_order, taylor); + + // z_1 = y * z_0 + addr_t adr[2]; + adr[0] = arg[1]; + adr[1] = addr_t( i_z ); + forward_mulpv_op(p, q, i_z+1, adr, parameter, cap_order, taylor); + + // z_2 = exp(z_1) + // zero order case exactly same as Base type operation + if( p == 0 ) + { Base* z_2 = taylor + (i_z+2) * cap_order; + Base* x = taylor + size_t(arg[0]) * cap_order; + Base y = parameter[ arg[1] ]; + z_2[0] = pow(x[0], y); + p++; + } + if( p <= q ) + forward_exp_op(p, q, i_z+2, i_z+1, cap_order, taylor); +} +/*! +Multiple directions forward mode Taylor coefficients for op = PowvpOp. + +The C++ source code corresponding to this operation is +\verbatim + z = pow(x, y) +\endverbatim +In the documentation below, +this operations is for the case where x is a variable and y is a parameter. + +\copydetails CppAD::local::forward_pow_op_dir +*/ + +template +void forward_powvp_op_dir( + size_t q , + size_t r , + size_t i_z , + const addr_t* arg , + const Base* parameter , + size_t cap_order , + Base* taylor ) +{ + // convert from final result to first result + i_z -= 2; // 2 = NumRes(PowvpOp) - 1 + + // check assumptions + CPPAD_ASSERT_UNKNOWN( NumArg(PowvpOp) == 2 ); + CPPAD_ASSERT_UNKNOWN( NumRes(PowvpOp) == 3 ); + CPPAD_ASSERT_UNKNOWN( 0 < q ); + CPPAD_ASSERT_UNKNOWN( q < cap_order ); + CPPAD_ASSERT_UNKNOWN( + size_t( std::numeric_limits::max() ) >= i_z + ); + + // z_0 = log(x) + forward_log_op_dir(q, r, i_z, size_t(arg[0]), cap_order, taylor); + + // z_1 = y * z_0 + addr_t adr[2]; + adr[0] = arg[1]; + adr[1] = addr_t( i_z ); + forward_mulpv_op_dir(q, r, i_z+1, adr, parameter, cap_order, taylor); + + // z_2 = exp(z_1) + forward_exp_op_dir(q, r, i_z+2, i_z+1, cap_order, taylor); +} + +/*! +Compute zero order forward mode Taylor coefficients for result of op = PowvpOp. + +The C++ source code corresponding to this operation is +\verbatim + z = pow(x, y) +\endverbatim +In the documentation below, +this operations is for the case where x is a variable and y is a parameter. + +\copydetails CppAD::local::forward_pow_op_0 +*/ + +template +void forward_powvp_op_0( + size_t i_z , + const addr_t* arg , + const Base* parameter , + size_t cap_order , + Base* taylor ) +{ + // convert from final result to first result + i_z -= 2; // NumRes(PowvpOp) - 1; + + // check assumptions + CPPAD_ASSERT_UNKNOWN( NumArg(PowvpOp) == 2 ); + CPPAD_ASSERT_UNKNOWN( NumRes(PowvpOp) == 3 ); + + // Paraemter value + Base y = parameter[ arg[1] ]; + + // Taylor coefficients corresponding to arguments and result + Base* x = taylor + size_t(arg[0]) * cap_order; + Base* z_0 = taylor + i_z * cap_order; + Base* z_1 = z_0 + cap_order; + Base* z_2 = z_1 + cap_order; + + // z_0 = log(x) + z_0[0] = log(x[0]); + + // z_1 = z_0 * y + z_1[0] = z_0[0] * y; + + // z_2 = exp(z_1) + // zero order case exactly same as Base type operation + z_2[0] = pow(x[0], y); +} + +/*! +Compute reverse mode partial derivative for result of op = PowvpOp. + +The C++ source code corresponding to this operation is +\verbatim + z = pow(x, y) +\endverbatim +In the documentation below, +this operations is for the case where x is a variable and y is a parameter. + +\copydetails CppAD::local::reverse_pow_op +*/ + +template +void reverse_powvp_op( + size_t d , + size_t i_z , + const addr_t* arg , + const Base* parameter , + size_t cap_order , + const Base* taylor , + size_t nc_partial , + Base* partial ) +{ + // convert from final result to first result + i_z -= 2; // NumRes(PowvpOp) - 1; + + // check assumptions + CPPAD_ASSERT_UNKNOWN( NumArg(PowvpOp) == 2 ); + CPPAD_ASSERT_UNKNOWN( NumRes(PowvpOp) == 3 ); + CPPAD_ASSERT_UNKNOWN( d < cap_order ); + CPPAD_ASSERT_UNKNOWN( d < nc_partial ); + CPPAD_ASSERT_UNKNOWN( + size_t( std::numeric_limits::max() ) >= i_z + ); + + // z_2 = exp(z_1) + reverse_exp_op( + d, i_z+2, i_z+1, cap_order, taylor, nc_partial, partial + ); + + // z_1 = y * z_0 + addr_t adr[2]; + adr[0] = arg[1]; + adr[1] = addr_t( i_z ); + reverse_mulpv_op( + d, i_z+1, adr, parameter, cap_order, taylor, nc_partial, partial + ); + + // z_0 = log(x) + reverse_log_op( + d, i_z, size_t(arg[0]), cap_order, taylor, nc_partial, partial + ); +} + +} } // END_CPPAD_LOCAL_NAMESPACE +# endif diff --git a/build-config/cppad/include/cppad/local/print_op.hpp b/build-config/cppad/include/cppad/local/print_op.hpp new file mode 100644 index 00000000..f338ecbd --- /dev/null +++ b/build-config/cppad/include/cppad/local/print_op.hpp @@ -0,0 +1,147 @@ +# ifndef CPPAD_LOCAL_PRINT_OP_HPP +# define CPPAD_LOCAL_PRINT_OP_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + + +namespace CppAD { namespace local { // BEGIN_CPPAD_LOCAL_NAMESPACE +/*! +Print operation for parameters; i.e., op = PriOp. + +The C++ source code corresponding to this operation is +\verbatim + f.Forward(0, x) + PrintFor(before, var) + PrintFor(pos, before, var, after) +\endverbatim +The PrintFor call puts the print operation on the tape +and the print occurs during the zero order forward mode computation. + +\tparam Base +base type for the operator; i.e., this operation was recorded +using AD< Base > and computations by this routine are done using type + Base . + +\param s_out +the results are printed on this output stream. + +\param arg + arg[0] & 1 +\n +If this is zero, pos is a parameter. Otherwise it is a variable. +\n + arg[0] & 2 +\n +If this is zero, var is a parameter. Otherwise it is a variable. +\n +\n + arg[1] +\n +If pos is a parameter, parameter[arg[1]] is its value. +Othwise taylor[ size_t(arg[1]) * cap_order + 0 ] is the zero +order Taylor coefficient for pos. +\n +\n + arg[2] +\n +index of the text to be printed before var +if pos is not a positive value. +\n +\n + arg[3] +\n +If var is a parameter, parameter[arg[3]] is its value. +Othwise taylor[ size_t(arg[3]) * cap_order + 0 ] is the zero +order Taylor coefficient for var. +\n +\n + arg[4] +\n +index of the text to be printed after var +if pos is not a positive value. + +\param num_text +is the total number of text characters on the tape +(only used for error checking). + +\param text +\b Input: text[arg[1]] is the first character of the text +that will be printed. All the characters from there to (but not including) +the first '\\0' are printed. + +\param num_par +is the total number of values in the parameter vector + +\param parameter +Contains the value of parameters. + +\param cap_order +number of colums in the matrix containing all the Taylor coefficients. + +\param taylor +Contains the value of variables. + +\par Checked Assertions: +\li NumArg(PriOp) == 5 +\li NumRes(PriOp) == 0 +\li text != nullptr +\li arg[1] < num_text +\li if pos is a parameter, arg[1] < num_par +\li if var is a parameter, arg[3] < num_par +*/ +template +void forward_pri_0( + std::ostream& s_out , + const addr_t* arg , + size_t num_text , + const char* text , + size_t num_par , + const Base* parameter , + size_t cap_order , + const Base* taylor ) +{ Base pos, var; + const char* before; + const char* after; + CPPAD_ASSERT_NARG_NRES(PriOp, 5, 0); + + // pos + if( arg[0] & 1 ) + { pos = taylor[ size_t(arg[1]) * cap_order + 0 ]; + } + else + { CPPAD_ASSERT_UNKNOWN( size_t(arg[1]) < num_par ); + pos = parameter[ arg[1] ]; + } + + // before + CPPAD_ASSERT_UNKNOWN( size_t(arg[2]) < num_text ); + before = text + arg[2]; + + // var + if( arg[0] & 2 ) + { var = taylor[ size_t(arg[3]) * cap_order + 0 ]; + } + else + { CPPAD_ASSERT_UNKNOWN( size_t(arg[3]) < num_par ); + var = parameter[ arg[3] ]; + } + + // after + CPPAD_ASSERT_UNKNOWN( size_t(arg[4]) < num_text ); + after = text + arg[4]; + + if( ! GreaterThanZero( pos ) ) + s_out << before << var << after; +} + +} } // END_CPPAD_LOCAL_NAMESPACE +# endif diff --git a/build-config/cppad/include/cppad/local/prototype_op.hpp b/build-config/cppad/include/cppad/local/prototype_op.hpp new file mode 100644 index 00000000..dc93132e --- /dev/null +++ b/build-config/cppad/include/cppad/local/prototype_op.hpp @@ -0,0 +1,1458 @@ +# ifndef CPPAD_LOCAL_PROTOTYPE_OP_HPP +# define CPPAD_LOCAL_PROTOTYPE_OP_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + + +namespace CppAD { namespace local { // BEGIN_CPPAD_LOCAL_NAMESPACE +/*! +\file prototype_op.hpp +Documentation for generic cases (these generic cases are never used). +*/ + +// ==================== Unary operators with one result ==================== + + +/*! +Prototype for forward mode unary operator with one result (not used). + +\tparam Base +base type for the operator; i.e., this operation was recorded +using AD< Base > and computations by this routine are done using type + Base. + +\param p +lowest order of the Taylor coefficient that we are computing. + +\param q +highest order of the Taylor coefficient that we are computing. + +\param i_z +variable index corresponding to the result for this operation; +i.e. the row index in taylor corresponding to z. + +\param i_x +variable index corresponding to the argument for this operator; +i.e. the row index in taylor corresponding to x. + +\param cap_order +maximum number of orders that will fit in the taylor array. + +\param taylor +\b Input: taylor [ i_x * cap_order + k ], +for k = 0 , ... , q, +is the k-th order Taylor coefficient corresponding to x. +\n +\b Input: taylor [ i_z * cap_order + k ], +for k = 0 , ... , p-1, +is the k-th order Taylor coefficient corresponding to z. +\n +\b Output: taylor [ i_z * cap_order + k ], +for k = p , ... , q, +is the k-th order Taylor coefficient corresponding to z. + +\par Checked Assertions +\li NumArg(op) == 1 +\li NumRes(op) == 1 +\li q < cap_order +\li p <= q +*/ +template +void forward_unary1_op( + size_t p , + size_t q , + size_t i_z , + size_t i_x , + size_t cap_order , + Base* taylor ) +{ + // This routine is only for documentaiton, it should not be used + CPPAD_ASSERT_UNKNOWN( false ); +} + +/*! +Prototype for multiple direction forward mode unary operator with one result +(not used). + +\tparam Base +base type for the operator; i.e., this operation was recorded +using AD< Base > and computations by this routine are done using type + Base. + +\param q +order of the Taylor coefficients that we are computing. + +\param r +number of directions for Taylor coefficients that we are computing. + +\param i_z +variable index corresponding to the last (primary) result for this operation; +i.e. the row index in taylor corresponding to z. + +\param i_x +variable index corresponding to the argument for this operator; +i.e. the row index in taylor corresponding to x. + +\param cap_order +maximum number of orders that will fit in the taylor array. + +\par tpv +We use the notation +tpv = (cap_order-1) * r + 1 +which is the number of Taylor coefficients per variable + +\param taylor +\b Input: If x is a variable, +taylor [ arg[0] * tpv + 0 ], +is the zero order Taylor coefficient for all directions and +taylor [ arg[0] * tpv + (k-1)*r + ell + 1 ], +for k = 1 , ... , q, +ell = 0, ..., r-1, +is the k-th order Taylor coefficient +corresponding to x and the ell-th direction. +\n +\b Input: taylor [ i_z * tpv + 0 ], +is the zero order Taylor coefficient for all directions and +taylor [ i_z * tpv + (k-1)*r + ell + 1 ], +for k = 1 , ... , q-1, +ell = 0, ..., r-1, +is the k-th order Taylor coefficient +corresponding to z and the ell-th direction. +\n +\b Output: +taylor [ i_z * tpv + (q-1)*r + ell + 1], +ell = 0, ..., r-1, +is the q-th order Taylor coefficient +corresponding to z and the ell-th direction. + +\par Checked Assertions +\li NumArg(op) == 1 +\li NumRes(op) == 2 +\li i_x < i_z +\li 0 < q +\li q < cap_order +*/ +template +void forward_unary1_op_dir( + size_t q , + size_t r , + size_t i_z , + size_t i_x , + size_t cap_order , + Base* taylor ) +{ + // This routine is only for documentaiton, it should not be used + CPPAD_ASSERT_UNKNOWN( false ); +} + +/*! +Prototype for zero order forward mode unary operator with one result (not used). +\tparam Base +base type for the operator; i.e., this operation was recorded +using AD< Base > and computations by this routine are done using type + Base . + +\param i_z +variable index corresponding to the result for this operation; +i.e. the row index in taylor corresponding to z. + +\param i_x +variable index corresponding to the argument for this operator; +i.e. the row index in taylor corresponding to x. + +\param cap_order +maximum number of orders that will fit in the taylor array. + +\param taylor +\b Input: taylor [ i_x * cap_order + 0 ] +is the zero order Taylor coefficient corresponding to x. +\n +\b Output: taylor [ i_z * cap_order + 0 ] +is the zero order Taylor coefficient corresponding to z. + +\par Checked Assertions +\li NumArg(op) == 1 +\li NumRes(op) == 1 +\li i_x < i_z +\li 0 < cap_order +*/ +template +void forward_unary1_op_0( + size_t i_z , + size_t i_x , + size_t cap_order , + Base* taylor ) +{ + // This routine is only for documentaiton, it should not be used + CPPAD_ASSERT_UNKNOWN( false ); +} + +/*! +Prototype for reverse mode unary operator with one result (not used). + +This routine is given the partial derivatives of a function +G(z , x , w, u ... ) +and it uses them to compute the partial derivatives of +\verbatim + H( x , w , u , ... ) = G[ z(x) , x , w , u , ... ] +\endverbatim + +\tparam Base +base type for the operator; i.e., this operation was recorded +using AD< Base > and computations by this routine are done using type + Base . + +\param d +highest order Taylor coefficient that +we are computing the partial derivatives with respect to. + +\param i_z +variable index corresponding to the result for this operation; +i.e. the row index in taylor to z. + +\param i_x +variable index corresponding to the argument for this operation; +i.e. the row index in taylor corresponding to x. + +\param cap_order +maximum number of orders that will fit in the taylor array. + +\param taylor + taylor [ i_x * cap_order + k ] +for k = 0 , ... , d +is the k-th order Taylor coefficient corresponding to x. +\n + taylor [ i_z * cap_order + k ] +for k = 0 , ... , d +is the k-th order Taylor coefficient corresponding to z. + +\param nc_partial +number of colums in the matrix containing all the partial derivatives. + +\param partial +\b Input: partial [ i_x * nc_partial + k ] +for k = 0 , ... , d +is the partial derivative of G( z , x , w , u , ... ) with respect to +the k-th order Taylor coefficient for x. +\n +\b Input: partial [ i_z * nc_partial + k ] +for k = 0 , ... , d +is the partial derivative of G( z , x , w , u , ... ) with respect to +the k-th order Taylor coefficient for z. +\n +\b Output: partial [ i_x * nc_partial + k ] +for k = 0 , ... , d +is the partial derivative of H( x , w , u , ... ) with respect to +the k-th order Taylor coefficient for x. +\n +\b Output: partial [ i_z * nc_partial + k ] +for k = 0 , ... , d +may be used as work space; i.e., may change in an unspecified manner. + + +\par Checked Assumptions +\li NumArg(op) == 1 +\li NumRes(op) == 1 +\li i_x < i_z +\li d < cap_order +\li d < nc_partial +*/ +template +void reverse_unary1_op( + size_t d , + size_t i_z , + size_t i_x , + size_t cap_order , + const Base* taylor , + size_t nc_partial , + Base* partial ) +{ + // This routine is only for documentaiton, it should not be used + CPPAD_ASSERT_UNKNOWN( false ); +} + +// ==================== Unary operators with two results ==================== + +/*! +Prototype for forward mode unary operator with two results (not used). + +\tparam Base +base type for the operator; i.e., this operation was recorded +using AD< Base > and computations by this routine are done using type + Base. + +\param p +lowest order of the Taylor coefficients that we are computing. + +\param q +highest order of the Taylor coefficients that we are computing. + +\param i_z +variable index corresponding to the last (primary) result for this operation; +i.e. the row index in taylor corresponding to z. +The auxillary result is called y has index i_z - 1. + +\param i_x +variable index corresponding to the argument for this operator; +i.e. the row index in taylor corresponding to x. + +\param cap_order +maximum number of orders that will fit in the taylor array. + +\param taylor +\b Input: taylor [ i_x * cap_order + k ] +for k = 0 , ... , q, +is the k-th order Taylor coefficient corresponding to x. +\n +\b Input: taylor [ i_z * cap_order + k ] +for k = 0 , ... , p - 1, +is the k-th order Taylor coefficient corresponding to z. +\n +\b Input: taylor [ ( i_z - 1) * cap_order + k ] +for k = 0 , ... , p-1, +is the k-th order Taylor coefficient corresponding to the auxillary result y. +\n +\b Output: taylor [ i_z * cap_order + k ], +for k = p , ... , q, +is the k-th order Taylor coefficient corresponding to z. +\n +\b Output: taylor [ ( i_z - 1 ) * cap_order + k ], +for k = p , ... , q, +is the k-th order Taylor coefficient corresponding to +the autillary result y. + +\par Checked Assertions +\li NumArg(op) == 1 +\li NumRes(op) == 2 +\li i_x + 1 < i_z +\li q < cap_order +\li p <= q +*/ +template +void forward_unary2_op( + size_t p , + size_t q , + size_t i_z , + size_t i_x , + size_t cap_order , + Base* taylor ) +{ + // This routine is only for documentaiton, it should not be used + CPPAD_ASSERT_UNKNOWN( false ); +} + +/*! +Prototype for multiple direction forward mode unary operator with two results +(not used). + +\tparam Base +base type for the operator; i.e., this operation was recorded +using AD< Base > and computations by this routine are done using type + Base. + +\param q +order of the Taylor coefficients that we are computing. + +\param r +number of directions for Taylor coefficients that we are computing. + +\param i_z +variable index corresponding to the last (primary) result for this operation; +i.e. the row index in taylor corresponding to z. +The auxillary result is called y has index i_z - 1. + +\param i_x +variable index corresponding to the argument for this operator; +i.e. the row index in taylor corresponding to x. + +\param cap_order +maximum number of orders that will fit in the taylor array. + +\par tpv +We use the notation +tpv = (cap_order-1) * r + 1 +which is the number of Taylor coefficients per variable + +\param taylor +\b Input: taylor [ i_x * tpv + 0 ] +is the zero order Taylor coefficient for all directions and +taylor [ i_x * tpv + (k-1)*r + ell + 1 +for k = 1 , ... , q, +ell = 0 , ..., r-1, +is the k-th order Taylor coefficient +corresponding to x and the ell-th direction. +\n +\b Input: taylor [ i_z * tpv + 0 ], +is the zero order Taylor coefficient for all directions and +taylor [ i_z * tpv + (k-1)*r + ell + 1 ], +for k = 1 , ... , q-1, +ell = 0, ..., r-1, +is the k-th order Taylor coefficient +corresponding to z and the ell-th direction. +\n +\b Input: taylor [ (i_z-1) * tpv + 0 ], +is the zero order Taylor coefficient for all directions and +taylor [ (i_z-1) * tpv + (k-1)*r + ell + 1 ], +for k = 1 , ... , q-1, +ell = 0, ..., r-1, +is the k-th order Taylor coefficient +corresponding to the auxillary result y and the ell-th direction. +\n +\b Output: +taylor [ i_z * tpv + (q-1)*r + ell + 1], +ell = 0, ..., r-1, +is the q-th order Taylor coefficient +corresponding to z and the ell-th direction. + +\par Checked Assertions +\li NumArg(op) == 1 +\li NumRes(op) == 2 +\li i_x + 1 < i_z +\li 0 < q +\li q < cap_order +*/ +template +void forward_unary2_op_dir( + size_t q , + size_t r , + size_t i_z , + size_t i_x , + size_t cap_order , + Base* taylor ) +{ + // This routine is only for documentaiton, it should not be used + CPPAD_ASSERT_UNKNOWN( false ); +} + +/*! +Prototype for zero order forward mode unary operator with two results (not used). +\tparam Base +base type for the operator; i.e., this operation was recorded +using AD< Base > and computations by this routine are done using type + Base . + +\param i_z +variable index corresponding to the last (primary) result for this operation; +i.e. the row index in taylor corresponding to z. +The auxillary result is called y and has index i_z - 1. + +\param i_x +variable index corresponding to the argument for this operator; +i.e. the row index in taylor corresponding to x. + +\param cap_order +maximum number of orders that will fit in the taylor array. + +\param taylor +\b Input: taylor [ i_x * cap_order + 0 ] +is the zero order Taylor coefficient corresponding to x. +\n +\b Output: taylor [ i_z * cap_order + 0 ] +is the zero order Taylor coefficient corresponding to z. +\n +\b Output: taylor [ ( i_z - 1 ) * cap_order + j ] +is the j-th order Taylor coefficient corresponding to +the autillary result y. + +\par Checked Assertions +\li NumArg(op) == 1 +\li NumRes(op) == 2 +\li i_x + 1 < i_z +\li j < cap_order +*/ +template +void forward_unary2_op_0( + size_t i_z , + size_t i_x , + size_t cap_order , + Base* taylor ) +{ + // This routine is only for documentaiton, it should not be used + CPPAD_ASSERT_UNKNOWN( false ); +} + +/*! +Prototype for reverse mode unary operator with two results (not used). + +This routine is given the partial derivatives of a function +G( z , y , x , w , ... ) +and it uses them to compute the partial derivatives of +\verbatim + H( x , w , u , ... ) = G[ z(x) , y(x), x , w , u , ... ] +\endverbatim + +\tparam Base +base type for the operator; i.e., this operation was recorded +using AD< Base > and computations by this routine are done using type + Base . + +\param d +highest order Taylor coefficient that +we are computing the partial derivatives with respect to. + +\param i_z +variable index corresponding to the last (primary) result for this operation; +i.e. the row index in taylor to z. +The auxillary result is called y and has index i_z - 1. + +\param i_x +variable index corresponding to the argument for this operation; +i.e. the row index in taylor corresponding to x. + +\param cap_order +maximum number of orders that will fit in the taylor array. + +\param taylor + taylor [ i_x * cap_order + k ] +for k = 0 , ... , d +is the k-th order Taylor coefficient corresponding to x. +\n + taylor [ i_z * cap_order + k ] +for k = 0 , ... , d +is the k-th order Taylor coefficient corresponding to z. +\n + taylor [ ( i_z - 1) * cap_order + k ] +for k = 0 , ... , d +is the k-th order Taylor coefficient corresponding to +the auxillary variable y. + +\param nc_partial +number of colums in the matrix containing all the partial derivatives. + +\param partial +\b Input: partial [ i_x * nc_partial + k ] +for k = 0 , ... , d +is the partial derivative of +G( z , y , x , w , u , ... ) +with respect to the k-th order Taylor coefficient for x. +\n +\b Input: partial [ i_z * nc_partial + k ] +for k = 0 , ... , d +is the partial derivative of G( z , y , x , w , u , ... ) with respect to +the k-th order Taylor coefficient for z. +\n +\b Input: partial [ ( i_z - 1) * nc_partial + k ] +for k = 0 , ... , d +is the partial derivative of G( z , x , w , u , ... ) with respect to +the k-th order Taylor coefficient for the auxillary variable y. +\n +\b Output: partial [ i_x * nc_partial + k ] +for k = 0 , ... , d +is the partial derivative of H( x , w , u , ... ) with respect to +the k-th order Taylor coefficient for x. +\n +\b Output: partial [ ( i_z - j ) * nc_partial + k ] +for j = 0 , 1 , and for k = 0 , ... , d +may be used as work space; i.e., may change in an unspecified manner. + + +\par Checked Assumptions +\li NumArg(op) == 1 +\li NumRes(op) == 2 +\li i_x + 1 < i_z +\li d < cap_order +\li d < nc_partial +*/ +template +void reverse_unary2_op( + size_t d , + size_t i_z , + size_t i_x , + size_t cap_order , + const Base* taylor , + size_t nc_partial , + Base* partial ) +{ + // This routine is only for documentaiton, it should not be used + CPPAD_ASSERT_UNKNOWN( false ); +} +// =================== Binary operators with one result ==================== + +/*! +Prototype forward mode x op y (not used) + +\tparam Base +base type for the operator; i.e., this operation was recorded +using AD< Base > and computations by this routine are done using type + Base. + +\param p +lowest order of the Taylor coefficient that we are computing. + +\param q +highest order of the Taylor coefficient that we are computing. + +\param i_z +variable index corresponding to the result for this operation; +i.e. the row index in taylor corresponding to z. + +\param arg + arg[0] +index corresponding to the left operand for this operator; +i.e. the index corresponding to x. +\n + arg[1] +index corresponding to the right operand for this operator; +i.e. the index corresponding to y. + +\param parameter +If x is a parameter, parameter [ arg[0] ] +is the value corresponding to x. +\n +If y is a parameter, parameter [ arg[1] ] +is the value corresponding to y. + +\param cap_order +maximum number of orders that will fit in the taylor array. + +\param taylor +\b Input: If x is a variable, +taylor [ size_t(arg[0]) * cap_order + k ], +for k = 0 , ... , q, +is the k-th order Taylor coefficient corresponding to x. +\n +\b Input: If y is a variable, +taylor [ size_t(arg[1]) * cap_order + k ], +for k = 0 , ... , q, +is the k-th order Taylor coefficient corresponding to y. +\n +\b Input: taylor [ i_z * cap_order + k ], +for k = 0 , ... , p-1, +is the k-th order Taylor coefficient corresponding to z. +\n +\b Output: taylor [ i_z * cap_order + k ], +for k = p, ... , q, +is the k-th order Taylor coefficient corresponding to z. + +\par Checked Assertions +\li NumArg(op) == 2 +\li NumRes(op) == 1 +\li q < cap_order +\li p <= q +*/ +template +void forward_binary_op( + size_t p , + size_t q , + size_t i_z , + const addr_t* arg , + const Base* parameter , + size_t cap_order , + Base* taylor ) +{ + // This routine is only for documentaiton, it should not be used + CPPAD_ASSERT_UNKNOWN( false ); +} + +/*! +Prototype multiple direction forward mode x op y (not used) + +\tparam Base +base type for the operator; i.e., this operation was recorded +using AD< Base > and computations by this routine are done using type + Base. + +\param q +is the order of the Taylor coefficients that we are computing. + +\param r +number of directions for Taylor coefficients that we are computing + +\param i_z +variable index corresponding to the result for this operation; +i.e. the row index in taylor corresponding to z. + +\param arg + arg[0] +index corresponding to the left operand for this operator; +i.e. the index corresponding to x. +\n + arg[1] +index corresponding to the right operand for this operator; +i.e. the index corresponding to y. + +\param parameter +If x is a parameter, parameter [ arg[0] ] +is the value corresponding to x. +\n +If y is a parameter, parameter [ arg[1] ] +is the value corresponding to y. + +\param cap_order +maximum number of orders that will fit in the taylor array. + +\par tpv +We use the notation +tpv = (cap_order-1) * r + 1 +which is the number of Taylor coefficients per variable + +\param taylor +\b Input: If x is a variable, +taylor [ arg[0] * tpv + 0 ], +is the zero order Taylor coefficient for all directions and +taylor [ arg[0] * tpv + (k-1)*r + ell + 1 ], +for k = 1 , ... , q, +ell = 0, ..., r-1, +is the k-th order Taylor coefficient +corresponding to x and the ell-th direction. +\n +\b Input: If y is a variable, +taylor [ arg[1] * tpv + 0 ], +is the zero order Taylor coefficient for all directions and +taylor [ arg[1] * tpv + (k-1)*r + ell + 1 ], +for k = 1 , ... , q, +ell = 0, ..., r-1, +is the k-th order Taylor coefficient +corresponding to y and the ell-th direction. +\n +\b Input: taylor [ i_z * tpv + 0 ], +is the zero order Taylor coefficient for all directions and +taylor [ i_z * tpv + (k-1)*r + ell + 1 ], +for k = 1 , ... , q-1, +ell = 0, ..., r-1, +is the k-th order Taylor coefficient +corresponding to z and the ell-th direction. +\n +\b Output: +taylor [ i_z * tpv + (q-1)*r + ell + 1], +ell = 0, ..., r-1, +is the q-th order Taylor coefficient +corresponding to z and the ell-th direction. + +\par Checked Assertions +\li NumArg(op) == 2 +\li NumRes(op) == 1 +\li 0 < q < cap_order +*/ +template +void forward_binary_op_dir( + size_t q , + size_t r , + size_t i_z , + const addr_t* arg , + const Base* parameter , + size_t cap_order , + Base* taylor ) +{ + // This routine is only for documentaiton, it should not be used + CPPAD_ASSERT_UNKNOWN( false ); +} + + +/*! +Prototype zero order forward mode x op y (not used) + +\tparam Base +base type for the operator; i.e., this operation was recorded +using AD< Base > and computations by this routine are done using type + Base. + +\param i_z +variable index corresponding to the result for this operation; +i.e. the row index in taylor corresponding to z. + +\param arg + arg[0] +index corresponding to the left operand for this operator; +i.e. the index corresponding to x. +\n + arg[1] +index corresponding to the right operand for this operator; +i.e. the index corresponding to y. + +\param parameter +If x is a parameter, parameter [ arg[0] ] +is the value corresponding to x. +\n +If y is a parameter, parameter [ arg[1] ] +is the value corresponding to y. + +\param cap_order +maximum number of orders that will fit in the taylor array. + +\param taylor +\b Input: If x is a variable, taylor [ arg[0] * cap_order + 0 ] +is the zero order Taylor coefficient corresponding to x. +\n +\b Input: If y is a variable, taylor [ arg[1] * cap_order + 0 ] +is the zero order Taylor coefficient corresponding to y. +\n +\b Output: taylor [ i_z * cap_order + 0 ] +is the zero order Taylor coefficient corresponding to z. + +\par Checked Assertions +\li NumArg(op) == 2 +\li NumRes(op) == 1 +*/ +template +void forward_binary_op_0( + size_t i_z , + const addr_t* arg , + const Base* parameter , + size_t cap_order , + Base* taylor ) +{ + // This routine is only for documentaiton, it should not be used + CPPAD_ASSERT_UNKNOWN( false ); +} + +/*! +Prototype for reverse mode binary operator x op y (not used). + +This routine is given the partial derivatives of a function +G( z , y , x , w , ... ) +and it uses them to compute the partial derivatives of +\verbatim + H( y , x , w , u , ... ) = G[ z(x , y) , y , x , w , u , ... ] +\endverbatim + +\tparam Base +base type for the operator; i.e., this operation was recorded +using AD< Base > and computations by this routine are done using type + Base . + +\param d +highest order Taylor coefficient that +we are computing the partial derivatives with respect to. + +\param i_z +variable index corresponding to the result for this operation; +i.e. the row index in taylor corresponding to z. + +\param arg + arg[0] +index corresponding to the left operand for this operator; +i.e. the index corresponding to x. +\n + arg[1] +index corresponding to the right operand for this operator; +i.e. the index corresponding to y. + +\param parameter +If x is a parameter, parameter [ arg[0] ] +is the value corresponding to x. +\n +If y is a parameter, parameter [ arg[1] ] +is the value corresponding to y. + +\param cap_order +maximum number of orders that will fit in the taylor array. + +\param taylor + taylor [ i_z * cap_order + k ] +for k = 0 , ... , d +is the k-th order Taylor coefficient corresponding to z. +\n +If x is a variable, taylor [ arg[0] * cap_order + k ] +for k = 0 , ... , d +is the k-th order Taylor coefficient corresponding to x. +\n +If y is a variable, taylor [ arg[1] * cap_order + k ] +for k = 0 , ... , d +is the k-th order Taylor coefficient corresponding to y. + +\param nc_partial +number of colums in the matrix containing all the partial derivatives. + +\param partial +\b Input: partial [ i_z * nc_partial + k ] +for k = 0 , ... , d +is the partial derivative of +G( z , y , x , w , u , ... ) +with respect to the k-th order Taylor coefficient for z. +\n +\b Input: If x is a variable, partial [ arg[0] * nc_partial + k ] +for k = 0 , ... , d +is the partial derivative of G( z , y , x , w , u , ... ) with respect to +the k-th order Taylor coefficient for x. +\n +\b Input: If y is a variable, partial [ arg[1] * nc_partial + k ] +for k = 0 , ... , d +is the partial derivative of G( z , x , w , u , ... ) with respect to +the k-th order Taylor coefficient for the auxillary variable y. +\n +\b Output: If x is a variable, partial [ arg[0] * nc_partial + k ] +for k = 0 , ... , d +is the partial derivative of H( y , x , w , u , ... ) with respect to +the k-th order Taylor coefficient for x. +\n +\b Output: If y is a variable, partial [ arg[1] * nc_partial + k ] +for k = 0 , ... , d +is the partial derivative of H( y , x , w , u , ... ) with respect to +the k-th order Taylor coefficient for y. +\n +\b Output: partial [ i_z * nc_partial + k ] +for k = 0 , ... , d +may be used as work space; i.e., may change in an unspecified manner. + +\par Checked Assumptions +\li NumArg(op) == 2 +\li NumRes(op) == 1 +\li If x is a variable, arg[0] < i_z +\li If y is a variable, arg[1] < i_z +\li d < cap_order +\li d < nc_partial +*/ +template +void reverse_binary_op( + size_t d , + size_t i_z , + addr_t* arg , + const Base* parameter , + size_t cap_order , + const Base* taylor , + size_t nc_partial , + Base* partial ) +{ + // This routine is only for documentaiton, it should not be used + CPPAD_ASSERT_UNKNOWN( false ); +} +// ======================= Pow Function =================================== +/*! +Prototype for forward mode z = pow(x, y) (not used). + +\tparam Base +base type for the operator; i.e., this operation was recorded +using AD< Base > and computations by this routine are done using type + Base. + +\param p +lowest order of the Taylor coefficient that we are computing. + +\param q +highest order of the Taylor coefficient that we are computing. + +\param i_z +variable index corresponding to the last (primary) result for this operation; +i.e. the row index in taylor corresponding to z. +Note that there are three results for this operation, +below they are referred to as z_0, z_1, z_2 and correspond to +\verbatim + z_0 = log(x) + z_1 = z0 * y + z_2 = exp(z1) +\endverbatim +It follows that the final result is equal to z; i.e., z = z_2 = pow(x, y). + +\param arg + arg[0] +index corresponding to the left operand for this operator; +i.e. the index corresponding to x. +\n + arg[1] +index corresponding to the right operand for this operator; +i.e. the index corresponding to y. + +\param parameter +If x is a parameter, parameter [ arg[0] ] +is the value corresponding to x. +\n +If y is a parameter, parameter [ arg[1] ] +is the value corresponding to y. + +\param cap_order +maximum number of orders that will fit in the taylor array. + +\param taylor +\b Input: If x is a variable, +taylor [ size_t(arg[0]) * cap_order + k ] +for k = 0 , ... , q, +is the k-th order Taylor coefficient corresponding to x. +\n +\b Input: If y is a variable, +taylor [ size_t(arg[1]) * cap_order + k ] +for k = 0 , ... , q +is the k-th order Taylor coefficient corresponding to y. +\n +\b Input: taylor [ (i_z-2+j) * cap_order + k ], +for j = 0, 1, 2 , for k = 0 , ... , p-1, +is the k-th order Taylor coefficient corresponding to z_j. +\n +\b Output: taylor [ (i_z-2+j) * cap_order + k ], +is the k-th order Taylor coefficient corresponding to z_j. + +\par Checked Assertions +\li NumArg(op) == 2 +\li NumRes(op) == 3 +\li If x is a variable, arg[0] < i_z - 2 +\li If y is a variable, arg[1] < i_z - 2 +\li q < cap_order +\li p <= q +*/ +template +void forward_pow_op( + size_t p , + size_t q , + size_t i_z , + const addr_t* arg , + const Base* parameter , + size_t cap_order , + Base* taylor ) +{ + // This routine is only for documentaiton, it should not be used + CPPAD_ASSERT_UNKNOWN( false ); +} +/*! +Prototype for multiple direction forward mode z = pow(x, y) (not used). + +\tparam Base +base type for the operator; i.e., this operation was recorded +using AD< Base > and computations by this routine are done using type + Base. + +\param q +order of the Taylor coefficient that we are computing. + +\param r +is the number of Taylor coefficient directions that we are computing + +\param i_z +variable index corresponding to the last (primary) result for this operation; +i.e. the row index in taylor corresponding to z. +Note that there are three results for this operation, +below they are referred to as z_0, z_1, z_2 and correspond to +\verbatim + z_0 = log(x) + z_1 = z0 * y + z_2 = exp(z1) +\endverbatim +It follows that the final result is equal to z; i.e., z = z_2 = pow(x, y). + +\param arg + arg[0] +index corresponding to the left operand for this operator; +i.e. the index corresponding to x. +\n + arg[1] +index corresponding to the right operand for this operator; +i.e. the index corresponding to y. + +\param parameter +If x is a parameter, parameter [ arg[0] ] +is the value corresponding to x. +\n +If y is a parameter, parameter [ arg[1] ] +is the value corresponding to y. + +\param cap_order +maximum number of orders that will fit in the taylor array. + +\par tpv +We use the notation +tpv = (cap_order-1) * r + 1 +which is the number of Taylor coefficients per variable + +\param taylor +\b Input: If x is a variable, +taylor [ arg[0] * tpv + 0 ] +is the zero order coefficient corresponding to x and +taylor [ arg[0] * tpv + (k-1)*r+1+ell ] +for k = 1 , ... , q, +ell = 0 , ... , r-1, +is the k-th order Taylor coefficient corresponding to x +for the ell-th direction. +\n +\n +\b Input: If y is a variable, +taylor [ arg[1] * tpv + 0 ] +is the zero order coefficient corresponding to y and +taylor [ arg[1] * tpv + (k-1)*r+1+ell ] +for k = 1 , ... , q, +ell = 0 , ... , r-1, +is the k-th order Taylor coefficient corresponding to y +for the ell-th direction. +\n +\n +\b Input: +taylor [ (i_z-2+j) * tpv + 0 ], +is the zero order coefficient corresponding to z_j and +taylor [ (i_z-2+j) * tpv + (k-1)*r+1+ell ], +for j = 0, 1, 2 , k = 0 , ... , q-1, ell = 0, ... , r-1, +is the k-th order Taylor coefficient corresponding to z_j +for the ell-th direction. +\n +\n +\b Output: +taylor [ (i_z-2+j) * tpv + (q-1)*r+1+ell ], +for j = 0, 1, 2 , ell = 0, ... , r-1, +is the q-th order Taylor coefficient corresponding to z_j +for the ell-th direction. + +\par Checked Assertions +\li NumArg(op) == 2 +\li NumRes(op) == 3 +\li If x is a variable, arg[0] < i_z - 2 +\li If y is a variable, arg[1] < i_z - 2 +\li 0 < q +\li q < cap_order +*/ +template +void forward_pow_op_dir( + size_t q , + size_t r , + size_t i_z , + const addr_t* arg , + const Base* parameter , + size_t cap_order , + Base* taylor ) +{ + // This routine is only for documentaiton, it should not be used + CPPAD_ASSERT_UNKNOWN( false ); +} +/*! +Prototype for zero order forward mode z = pow(x, y) (not used). + +\tparam Base +base type for the operator; i.e., this operation was recorded +using AD< Base > and computations by this routine are done using type + Base. + +\param i_z +variable index corresponding to the last (primary) result for this operation; +i.e. the row index in taylor corresponding to z. +Note that there are three results for this operation, +below they are referred to as z_0, z_1, z_2 and correspond to +\verbatim + z_0 = log(x) + z_1 = z0 * y + z_2 = exp(z1) +\endverbatim +It follows that the final result is equal to z; i.e., z = z_2 = pow(x, y). + +\param arg + arg[0] +index corresponding to the left operand for this operator; +i.e. the index corresponding to x. +\n + arg[1] +index corresponding to the right operand for this operator; +i.e. the index corresponding to y. + +\param parameter +If x is a parameter, parameter [ arg[0] ] +is the value corresponding to x. +\n +If y is a parameter, parameter [ arg[1] ] +is the value corresponding to y. + +\param cap_order +maximum number of orders that will fit in the taylor array. + +\param taylor +\b Input: If x is a variable, taylor [ arg[0] * cap_order + 0 ] +is the zero order Taylor coefficient corresponding to x. +\n +\b Input: If y is a variable, taylor [ arg[1] * cap_order + 0 ] +is the k-th order Taylor coefficient corresponding to y. +\n +\b Output: taylor [ (i_z - 2 + j) * cap_order + 0 ] +is the zero order Taylor coefficient corresponding to z_j. + +\par Checked Assertions +\li NumArg(op) == 2 +\li NumRes(op) == 3 +\li If x is a variable, arg[0] < i_z - 2 +\li If y is a variable, arg[1] < i_z - 2 +*/ +template +void forward_pow_op_0( + size_t i_z , + const addr_t* arg , + const Base* parameter , + size_t cap_order , + Base* taylor ) +{ + // This routine is only for documentaiton, it should not be used + CPPAD_ASSERT_UNKNOWN( false ); +} +/*! +Prototype for reverse mode z = pow(x, y) (not used). + +This routine is given the partial derivatives of a function +G( z , y , x , w , ... ) +and it uses them to compute the partial derivatives of +\verbatim + H( y , x , w , u , ... ) = G[ pow(x , y) , y , x , w , u , ... ] +\endverbatim + +\tparam Base +base type for the operator; i.e., this operation was recorded +using AD< Base > and computations by this routine are done using type + Base . + +\param d +highest order Taylor coefficient that +we are computing the partial derivatives with respect to. + +\param i_z +variable index corresponding to the last (primary) result for this operation; +i.e. the row index in taylor corresponding to z. +Note that there are three results for this operation, +below they are referred to as z_0, z_1, z_2 and correspond to +\verbatim + z_0 = log(x) + z_1 = z0 * y + z_2 = exp(z1) +\endverbatim +It follows that the final result is equal to z; i.e., z = z_2 = pow(x, y). + +\param arg + arg[0] +index corresponding to the left operand for this operator; +i.e. the index corresponding to x. +\n + arg[1] +index corresponding to the right operand for this operator; +i.e. the index corresponding to y. + +\param parameter +If x is a parameter, parameter [ arg[0] ] +is the value corresponding to x. +\n +If y is a parameter, parameter [ arg[1] ] +is the value corresponding to y. + +\param cap_order +maximum number of orders that will fit in the taylor array. + +\param taylor + taylor [ (i_z - 2 + j) * cap_order + k ] +for j = 0, 1, 2 and k = 0 , ... , d +is the k-th order Taylor coefficient corresponding to z_j. +\n +If x is a variable, taylor [ arg[0] * cap_order + k ] +for k = 0 , ... , d +is the k-th order Taylor coefficient corresponding to x. +\n +If y is a variable, taylor [ arg[1] * cap_order + k ] +for k = 0 , ... , d +is the k-th order Taylor coefficient corresponding to y. + +\param nc_partial +number of colums in the matrix containing all the partial derivatives. + +\param partial +\b Input: partial [ (i_z - 2 + j) * nc_partial + k ] +for j = 0, 1, 2, and k = 0 , ... , d +is the partial derivative of +G( z , y , x , w , u , ... ) +with respect to the k-th order Taylor coefficient for z_j. +\n +\b Input: If x is a variable, partial [ arg[0] * nc_partial + k ] +for k = 0 , ... , d +is the partial derivative of G( z , y , x , w , u , ... ) with respect to +the k-th order Taylor coefficient for x. +\n +\b Input: If y is a variable, partial [ arg[1] * nc_partial + k ] +for k = 0 , ... , d +is the partial derivative of G( z , x , w , u , ... ) with respect to +the k-th order Taylor coefficient for the auxillary variable y. +\n +\b Output: If x is a variable, partial [ arg[0] * nc_partial + k ] +for k = 0 , ... , d +is the partial derivative of H( y , x , w , u , ... ) with respect to +the k-th order Taylor coefficient for x. +\n +\b Output: If y is a variable, partial [ arg[1] * nc_partial + k ] +for k = 0 , ... , d +is the partial derivative of H( y , x , w , u , ... ) with respect to +the k-th order Taylor coefficient for y. +\n +\b Output: partial [ ( i_z - j ) * nc_partial + k ] +for j = 0 , 1 , 2 and for k = 0 , ... , d +may be used as work space; i.e., may change in an unspecified manner. + +\par Checked Assumptions +\li NumArg(op) == 2 +\li NumRes(op) == 3 +\li If x is a variable, arg[0] < i_z - 2 +\li If y is a variable, arg[1] < i_z - 2 +\li d < cap_order +\li d < nc_partial +*/ +template +void reverse_pow_op( + size_t d , + size_t i_z , + addr_t* arg , + const Base* parameter , + size_t cap_order , + const Base* taylor , + size_t nc_partial , + Base* partial ) +{ + // This routine is only for documentaiton, it should not be used + CPPAD_ASSERT_UNKNOWN( false ); +} + +// ==================== Sparsity Calculations ============================== +/*! +Prototype for reverse mode Hessian sparsity unary operators. + +This routine is given the forward mode Jacobian sparsity patterns for x. +It is also given the reverse mode dependence of G on z. +In addition, it is given the revese mode Hessian sparsity +for the quanity of interest G(z , y , ... ) +and it uses them to compute the sparsity patterns for +\verbatim + H( x , w , u , ... ) = G[ z(x) , x , w , u , ... ] +\endverbatim + +\tparam Vector_set +is the type used for vectors of sets. It can be either +sparse::pack_setvec or sparse::list_setvec. + +\param i_z +variable index corresponding to the result for this operation; +i.e. the row index in sparsity corresponding to z. + +\param i_x +variable index corresponding to the argument for this operator; +i.e. the row index in sparsity corresponding to x. + +\param rev_jacobian + rev_jacobian[i_z] +is all false (true) if the Jacobian of G with respect to z must be zero +(may be non-zero). +\n +\n + rev_jacobian[i_x] +is all false (true) if the Jacobian with respect to x must be zero +(may be non-zero). +On input, it corresponds to the function G, +and on output it corresponds to the function H. + +\param for_jac_sparsity +The set with index i_x in for_jac_sparsity +is the forward mode Jacobian sparsity pattern for the variable x. + +\param rev_hes_sparsity +The set with index i_z in in rev_hes_sparsity +is the Hessian sparsity pattern for the fucntion G +where one of the partials derivative is with respect to z. +\n +\n +The set with index i_x in rev_hes_sparsity +is the Hessian sparsity pattern +where one of the partials derivative is with respect to x. +On input, it corresponds to the function G, +and on output it corresponds to the function H. + +\par Checked Assertions: +\li i_x < i_z +*/ + +template +void reverse_sparse_hessian_unary_op( + size_t i_z , + size_t i_x , + bool* rev_jacobian , + Vector_set& for_jac_sparsity , + Vector_set& rev_hes_sparsity ) +{ + // This routine is only for documentaiton, it should not be used + CPPAD_ASSERT_UNKNOWN( false ); +} + +/*! +Prototype for reverse mode Hessian sparsity binary operators. + +This routine is given the sparsity patterns the Hessian +of a function G(z, y, x, ... ) +and it uses them to compute the sparsity patterns for the Hessian of +\verbatim + H( y, x, w , u , ... ) = G[ z(x,y) , y , x , w , u , ... ] +\endverbatim + +\tparam Vector_set +is the type used for vectors of sets. It can be either +sparse::pack_setvec or sparse::list_setvec. + +\param i_z +variable index corresponding to the result for this operation; +i.e. the row index in sparsity corresponding to z. + +\param arg + arg[0] +variable index corresponding to the left operand for this operator; +i.e. the set with index arg[0] in var_sparsity +is the spasity pattern correspoding to x. +\n +\n arg[1] +variable index corresponding to the right operand for this operator; +i.e. the row index in sparsity patterns corresponding to y. + +\param jac_reverse + jac_reverse[i_z] +is false (true) if the Jacobian of G with respect to z is always zero +(may be non-zero). +\n +\n + jac_reverse[ arg[0] ] +is false (true) if the Jacobian with respect to x is always zero +(may be non-zero). +On input, it corresponds to the function G, +and on output it corresponds to the function H. +\n +\n + jac_reverse[ arg[1] ] +is false (true) if the Jacobian with respect to y is always zero +(may be non-zero). +On input, it corresponds to the function G, +and on output it corresponds to the function H. + +\param for_jac_sparsity +The set with index arg[0] in for_jac_sparsity for the +is the forward Jacobian sparsity pattern for x. +\n +\n +The set with index arg[1] in for_jac_sparsity +is the forward sparsity pattern for y. + +\param rev_hes_sparsity +The set wiht index i_x in rev_hes_sparsity +is the Hessian sparsity pattern for the function G +where one of the partial derivatives is with respect to z. +\n +\n +The set with index arg[0] in rev_hes_sparsity +is the Hessian sparsity pattern where one of the +partial derivatives is with respect to x. +On input, it corresponds to the function G, +and on output it correspondst to H. +\n +\n +The set with index arg[1] in rev_hes_sparsity +is the Hessian sparsity pattern where one of the +partial derivatives is with respect to y. +On input, it corresponds to the function G, +and on output it correspondst to H. + +\par Checked Assertions: +\li arg[0] < i_z +\li arg[1] < i_z +*/ +template +void reverse_sparse_hessian_binary_op( + size_t i_z , + const addr_t* arg , + bool* jac_reverse , + Vector_set& for_jac_sparsity , + Vector_set& rev_hes_sparsity ) +{ + // This routine is only for documentaiton, it should not be used + CPPAD_ASSERT_UNKNOWN( false ); +} + + +} } // END_CPPAD_LOCAL_NAMESPACE +# endif diff --git a/build-config/cppad/include/cppad/local/record/comp_op.hpp b/build-config/cppad/include/cppad/local/record/comp_op.hpp new file mode 100644 index 00000000..04669f84 --- /dev/null +++ b/build-config/cppad/include/cppad/local/record/comp_op.hpp @@ -0,0 +1,287 @@ +# ifndef CPPAD_LOCAL_RECORD_COMP_OP_HPP +# define CPPAD_LOCAL_RECORD_COMP_OP_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ +# include + +namespace CppAD { namespace local { // BEGIN_CPPAD_LOCAL_NAMESPACE +/* +$begin recorder_put_comp_op$$ +$spell + rel + aleft + eq + le + lt + var + dyn + taddr +$$ + +$section Put Compare Operators in Recording$$ + +$head Syntax$$ +$icode%rec%.put_comp_%rel%( %aleft%, %aright%, %result%) +%$$ + +$subhead rel$$ +The text $icode rel$$ in the function name above +is $code eq$$ (for equals), +$code le$$ (for less than or equal), or +$code lt$$ (for less than). + +$head Prototype$$ +$srcthisfile% + 0%// BEGIN_COMP_EQ%// END_COMP_EQ%1 +%$$ +The other prototypes for the functions $code comp_le$$ and $code comp_lt$$ +are same except for the function name. + +$head var_left$$ +is true if the left operand is a variable. + +$head var_right$$ +is true if the right operand is a variable. + +$head dyn_left$$ +is true if the left operand is a dynamic parameter. + +$head dyn_right$$ +is true if the right operand is a dynamic parameter. + +$head aleft$$ +is the compare operator left operand. + +$head aright$$ +is the compare operator right operand. + +$head taddr_$$ +The values $icode%aleft.taddr_%$$ and $icode%aright%.taddr_%$$ +are the proper address for dynamic parameters and variables +and does not matter for constants. + +$head value_$$ +The values $icode%aleft.value_%$$ and $icode%aright%.value_%$$ +are the proper address for constants and does not matter +for variables and dynamic parameters. + +$head result$$ +This is the result for this comparison corresponding to this +recording (sequence of operations). + +$end +*/ +// BEGIN_COMP_EQ +template +void recorder::comp_eq( + bool var_left , + bool var_right , + bool dyn_left , + bool dyn_right , + const AD& aleft , + const AD& aright , + bool result ) +// END_COMP_EQ +{ if( var_left ) + { if( var_right ) + { // variable == variable + PutArg(aleft.taddr_, aright.taddr_); + if( result ) + PutOp(EqvvOp); + else + PutOp(NevvOp); + } + else + { // variable == parameter + addr_t p = aright.taddr_; + if( ! dyn_right ) + p = put_con_par(aright.value_); + PutArg(p, aleft.taddr_); + if( result ) + PutOp(EqpvOp); + else + PutOp(NepvOp); + } + } + else if ( var_right ) + { // parameter == variable + addr_t p = aleft.taddr_; + if( ! dyn_left ) + p = put_con_par(aleft.value_); + PutArg(p, aright.taddr_); + if( result ) + PutOp(EqpvOp); + else + PutOp(NepvOp); + } + else if( dyn_left | dyn_right ) + { // parameter == parameter + addr_t arg0 = aleft.taddr_; + addr_t arg1 = aright.taddr_; + if( ! dyn_left ) + arg0 = put_con_par(aleft.value_); + if( ! dyn_right ) + arg1 = put_con_par(aright.value_); + // + PutArg(arg0, arg1); + if( result ) + PutOp(EqppOp); + else + PutOp(NeppOp); + } +} +// --------------------------------------------------------------------------- +// comp_le +template +void recorder::comp_le( + bool var_left , + bool var_right , + bool dyn_left , + bool dyn_right , + const AD& aleft , + const AD& aright , + bool result ) +{ + if( var_left ) + { if( var_right ) + { // variable <= variable + if( result ) + { PutOp(LevvOp); + PutArg(aleft.taddr_, aright.taddr_); + } + else + { PutOp(LtvvOp); + PutArg(aright.taddr_, aleft.taddr_); + } + } + else + { // variable <= parameter + addr_t p = aright.taddr_; + if( ! dyn_right ) + p = put_con_par(aright.value_); + if( result ) + { PutOp(LevpOp); + PutArg(aleft.taddr_, p); + } + else + { PutOp(LtpvOp); + PutArg(p, aleft.taddr_); + } + } + } + else if ( var_right ) + { // parameter <= variable + addr_t p = aleft.taddr_; + if( ! dyn_left ) + p = put_con_par(aleft.value_); + if( result ) + { PutOp(LepvOp); + PutArg(p, aright.taddr_); + } + else + { PutOp(LtvpOp); + PutArg(aright.taddr_, p); + } + } + else if( dyn_left | dyn_right ) + { // parameter <= parameter + addr_t arg0 = aleft.taddr_; + addr_t arg1 = aright.taddr_; + if( ! dyn_left ) + arg0 = put_con_par(aleft.value_); + if( ! dyn_right ) + arg1 = put_con_par(aright.value_); + // + if( result ) + { PutOp(LeppOp); + PutArg(arg0, arg1); + } + else + { PutOp(LtppOp); + PutArg(arg1, arg0); + } + } +} +// -------------------------------------------------------------------------- +// comp_lt +template +void recorder::comp_lt( + bool var_left , + bool var_right , + bool dyn_left , + bool dyn_right , + const AD& aleft , + const AD& aright , + bool result ) +{ + if( var_left ) + { if( var_right ) + { // variable < variable + if( result ) + { PutOp(LtvvOp); + PutArg(aleft.taddr_, aright.taddr_); + } + else + { PutOp(LevvOp); + PutArg(aright.taddr_, aleft.taddr_); + } + } + else + { // variable < parameter + addr_t p = aright.taddr_; + if( ! dyn_right ) + p = put_con_par(aright.value_); + if( result ) + { PutOp(LtvpOp); + PutArg(aleft.taddr_, p); + } + else + { PutOp(LepvOp); + PutArg(p, aleft.taddr_); + } + } + } + else if ( var_right ) + { // parameter < variable + addr_t p = aleft.taddr_; + if( ! dyn_left ) + p = put_con_par(aleft.value_); + if( result ) + { PutOp(LtpvOp); + PutArg(p, aright.taddr_); + } + else + { PutOp(LevpOp); + PutArg(aright.taddr_, p); + } + } + else if( dyn_left | dyn_right ) + { // parameter < parameter + addr_t arg0 = aleft.taddr_; + addr_t arg1 = aright.taddr_; + if( ! dyn_left ) + arg0 = put_con_par(aleft.value_); + if( ! dyn_right ) + arg1 = put_con_par(aright.value_); + // + if( result ) + { PutOp(LtppOp); + PutArg(arg0, arg1); + } + else + { PutOp(LeppOp); + PutArg(arg1, arg0); + } + } +} +} } // END_CPPAD_LOCAL_NAMESPACE +# endif diff --git a/build-config/cppad/include/cppad/local/record/cond_exp.hpp b/build-config/cppad/include/cppad/local/record/cond_exp.hpp new file mode 100644 index 00000000..f72e3249 --- /dev/null +++ b/build-config/cppad/include/cppad/local/record/cond_exp.hpp @@ -0,0 +1,176 @@ +# ifndef CPPAD_LOCAL_RECORD_COND_EXP_HPP +# define CPPAD_LOCAL_RECORD_COND_EXP_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ +# include + +namespace CppAD { namespace local { // BEGIN_CPPAD_LOCAL_NAMESPACE +/* +$begin recorder_cond_exp$$ +$spell + cond_exp + ptr +$$ + +$section Record a Variable or Dynamic Parameter Conditional Expression$$ + +$head Syntax$$ +$icode%rec%.cond_exp( + %tape_id%, %cop%, %result%, %left%, %right%, %if_true%, %if_false% +)%$$ + +$head Prototype$$ +$srcthisfile% + 0%// BEGIN_COND_EXP%// END_COND_EXP%1 +%$$ + +$head tape_id$$ +identifier for the tape that this operation is being recorded on. +Passing tape_id avoids having to call tape_ptr() in case where +left, right, if_true, and if_false are all be constant at this AD level +(but left and right are not identically constant). + +$head cop$$ +Which $cref/comparison operator/base_cond_exp/CompareOp/$$; +i.e., <, <=, ==, >=, >, or !=. + +$head result$$ +is the result for this operation conditional expression. +On input, $icode%result%.value_%$$ is the proper value and +the other fields do not matter. +Upon return, the other fields have been set to their proper values. +It is an error to call this routine when all the arguments are constants; i.e., +when the result is a constant. + +$head left$$ +value of the left operand in the comparison. +If $icode%left%.tape_id_%$$ is not zero it must equal $icode tape_id$$. + +$head right$$ +value of the right operand in the comparison. +If $icode%right%.tape_id_%$$ is not zero it must equal $icode tape_id$$. + +$head if_true$$ +value of the result if the comparison value is true. +If $icode%if_true%.tape_id_%$$ is not zero it must equal $icode tape_id$$. + +$head if_false$$ +value of the result if the comparison value is false. +If $icode%if_false%.tape_id_%$$ is not zero it must equal $icode tape_id$$. + +$end +*/ +// BEGIN_COND_EXP +template +void recorder::cond_exp( + tape_id_t tape_id , + enum CompareOp cop , + AD &result , + const AD &left , + const AD &right , + const AD &if_true , + const AD &if_false ) +// END_COND_EXP +{ // check for invalid tape_id + CPPAD_ASSERT_UNKNOWN( tape_id != 0 ); + + // arg[0] = cop + addr_t arg0 = addr_t( cop ); + + // arg[1] = base 2 represenation of the value + // [Var(left), Var(right), Var(if_true), Var(if_false)] + addr_t arg1 = 0; + + // arg[2] = left address + // set first bit in arg1 + addr_t arg2 = left.taddr_; + if( Constant(left) ) + arg2 = put_con_par(left.value_); + else + { CPPAD_ASSERT_KNOWN( tape_id == left.tape_id_ , + "CondExpRel: arguments are variables or dynamics for different thread" + ); + if(left.ad_type_ != dynamic_enum) + arg1 += 1; + } + + // arg[3] = right address + // set second bit in arg1 + addr_t arg3 = right.taddr_; + if( Constant(right) ) + arg3 = put_con_par(right.value_); + else + { CPPAD_ASSERT_KNOWN( tape_id == right.tape_id_ , + "CondExpRel: arguments are variables or dynamics for different thread" + ); + if(right.ad_type_ != dynamic_enum) + arg1 += 2; + } + + // arg[4] = if_true address + // set third bit in arg1 + addr_t arg4 = if_true.taddr_; + if( Constant(if_true) ) + arg4 = put_con_par(if_true.value_); + else + { CPPAD_ASSERT_KNOWN( tape_id == if_true.tape_id_ , + "CondExpRel: arguments are variables or dynamics for different thread" + ); + if(if_true.ad_type_ != dynamic_enum) + arg1 += 4; + } + + // arg[5] = if_false address + // set fourth bit in arg1 + addr_t arg5 = if_false.taddr_; + if( Constant(if_false) ) + arg5 = put_con_par(if_false.value_); + else + { CPPAD_ASSERT_KNOWN( tape_id == if_false.tape_id_ , + "CondExpRel: arguments are variables or dynamics for different thread" + ); + if(if_false.ad_type_ != dynamic_enum) + arg1 += 8; + } + if( arg1 == 0 ) + { // none of the arguments are variables, record cond_exp_dyn + + // put the result at the end of the parameter vector as dynamic + // put_dyn_cond_exp(par, cop, left, right, if_true, if_false) + result.taddr_ = put_dyn_cond_exp( + result.value_, CompareOp(arg0), arg2, arg3, arg4, arg5 + ); + result.ad_type_ = dynamic_enum; + result.tape_id_ = tape_id; + + // check that result is a dynamic parameter + CPPAD_ASSERT_UNKNOWN( Dynamic(result) ); + } + else + { CPPAD_ASSERT_UNKNOWN( NumArg(CExpOp) == 6 ); + CPPAD_ASSERT_UNKNOWN( NumRes(CExpOp) == 1 ); + + // put operator in tape + result.taddr_ = PutOp(CExpOp); + PutArg(arg0, arg1, arg2, arg3, arg4, arg5); + + // make result a variable + CPPAD_ASSERT_UNKNOWN( result.ad_type_ == constant_enum ); + result.ad_type_ = variable_enum; + result.tape_id_ = tape_id; + + // check that result is a variable + CPPAD_ASSERT_UNKNOWN( Variable(result) ); + } +} +} } // END_CPPAD_LOCAL_NAMESPACE +# endif diff --git a/build-config/cppad/include/cppad/local/record/put_dyn_atomic.hpp b/build-config/cppad/include/cppad/local/record/put_dyn_atomic.hpp new file mode 100644 index 00000000..51b0f0a1 --- /dev/null +++ b/build-config/cppad/include/cppad/local/record/put_dyn_atomic.hpp @@ -0,0 +1,169 @@ +# ifndef CPPAD_LOCAL_RECORD_PUT_DYN_ATOMIC_HPP +# define CPPAD_LOCAL_RECORD_PUT_DYN_ATOMIC_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ +# include + +namespace CppAD { namespace local { // BEGIN_CPPAD_LOCAL_NAMESPACE +/* +$begin recorder_put_dyn_atomic$$ +$spell + ptr + dyn + enum + taddr +$$ + +$section Put a Dynamic Parameter Atomic Call Operator in Recording$$ + +$head Syntax$$ +$icode%rec%.put_dyn_atomic( + %tape_id%, %atomic_index%, %type_x%, %type_y%, %ax%, %ay% +)%$$ + +$head Prototype$$ +$srcthisfile% + 0%// BEGIN_PUT_DYN_ATOMIC%// END_PROTOTYPE%1 +%$$ + +$head tape_id$$ +identifies the tape that this recording corresponds to. +This is zero if and only if there is no tape for this recording; i.e. +$codei%AD<%Base%>.tape_ptr()%$$ is null. + +$head atomic_index$$ +is the $cref atomic_index$$ for this atomic function. + +$head type_x$$ +is the $cref ad_type_enum$$ for each of the atomic function arguments. + +$head type_y$$ +is the $code ad_type_enum$$ for each of the atomic function results. + +$head ax$$ +is the atomic function argument vector for this call. + +$subhead value_$$ +The value $icode%ax%[%j%].value_%$$ is the proper value for +parameters and does not matter for variables. + +$subhead taddr_$$ +The value $icode%ax%[%j%].taddr_%$$ is the proper address for +dynamic parameters and does not matter for constants or variables. + +$head ay$$ +is the atomic function result vector for this call. + +$subhead Input$$ +On input, $icode%ay%[%j%].value_%$$ has the proper value for parameters +(result for the atomic function). + +$subhead Output$$ +Upon return, if the $th i$$ result is a dynamic parameter, +$codei% + %ay%[%i%].ad_type_ = dynamic_enum + %ay%[%i%].tape_id_ = %tape_id% + %ay%[%i%].taddr_ = %p_index% +%$$ +where $icode p_index$$ is the index of this dynamic parameter +in the vector of all parameters. + +$end +*/ + +// BEGIN_PUT_DYN_ATOMIC +template template +void recorder::put_dyn_atomic( + tape_id_t tape_id , + size_t atomic_index , + const vector& type_x , + const vector& type_y , + const VectorAD& ax , + VectorAD& ay ) +// END_PROTOTYPE +{ CPPAD_ASSERT_UNKNOWN( + (tape_id == 0) == (AD::tape_ptr() == nullptr) + ); + CPPAD_ASSERT_UNKNOWN( ax.size() == type_x.size() ); + CPPAD_ASSERT_UNKNOWN( ay.size() == type_y.size() ); + size_t n = ax.size(); + size_t m = ay.size(); + size_t num_dyn = 0; + for(size_t i = 0; i < m; ++i) + if( type_y[i] == dynamic_enum ) + ++num_dyn; + CPPAD_ASSERT_UNKNOWN( num_dyn > 0 ); + // + dyn_par_arg_.push_back( addr_t(atomic_index )); // arg[0] = atomic_index + dyn_par_arg_.push_back( addr_t( n ) ); // arg[1] = n + dyn_par_arg_.push_back( addr_t( m ) ); // arg[2] = m + dyn_par_arg_.push_back( addr_t( num_dyn ) ); // arg[3] = num_dyn + // arg[4 + j] for j = 0, ... , n-1 + for(size_t j = 0; j < n; ++j) + { addr_t arg = 0; + switch( type_x[j] ) + { case constant_enum: + arg = put_con_par( ax[j].value_ ); + break; + + case dynamic_enum: + arg = ax[j].taddr_; + break; + + case variable_enum: + arg = 0; // phantom parameter index + CPPAD_ASSERT_UNKNOWN( isnan( all_par_vec_[arg] ) ) + break; + + default: + arg = 0; + CPPAD_ASSERT_UNKNOWN( false ); + } + dyn_par_arg_.push_back( arg ); // arg[4 + j] + } + // arg[4 + n + i] for i = 0, ... , m-1 + bool first_dynamic_result = true; + for(size_t i = 0; i < m; ++i) + { addr_t arg; + switch( type_y[i] ) + { case constant_enum: + arg = 0; // phantom parameter index + break; + + case dynamic_enum: + // one operator for each dynamic parameter result + // so number of operators is equal number of dynamic parameters + if( first_dynamic_result ) + arg = put_dyn_par(ay[i].value_, atom_dyn ); // atom_dyn + else + arg = put_dyn_par(ay[i].value_, result_dyn ); // result_dyn + ay[i].ad_type_ = dynamic_enum; + ay[i].taddr_ = arg; + ay[i].tape_id_ = tape_id; + first_dynamic_result = false; + break; + + case variable_enum: + arg = 0; // phantom parameter (has value nan) + break; + + default: + arg = 0; + CPPAD_ASSERT_UNKNOWN( false ); + } + dyn_par_arg_.push_back( arg ); // arg[4 + n + i] + } + dyn_par_arg_.push_back( addr_t(5 + n + m) ); // arg[4 + n + m] +} + +} } // END_CPPAD_LOCAL_NAMESPACE +# endif diff --git a/build-config/cppad/include/cppad/local/record/put_var_atomic.hpp b/build-config/cppad/include/cppad/local/record/put_var_atomic.hpp new file mode 100644 index 00000000..ea4f0a8f --- /dev/null +++ b/build-config/cppad/include/cppad/local/record/put_var_atomic.hpp @@ -0,0 +1,150 @@ +# ifndef CPPAD_LOCAL_RECORD_PUT_VAR_ATOMIC_HPP +# define CPPAD_LOCAL_RECORD_PUT_VAR_ATOMIC_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ +# include + +namespace CppAD { namespace local { // BEGIN_CPPAD_LOCAL_NAMESPACE +/* +$begin recorder_put_var_atomic$$ +$spell + ptr + var + enum + taddr +$$ + +$section Put a Variable Atomic Call Operator in Recording$$ + +$head Syntax$$ +$icode%rec%.put_var_atomic( + %tape_id%, %atomic_index%, %type_x%, %type_y%, %ax%, %ay% +)%$$ + +$head Prototype$$ +$srcthisfile% + 0%// BEGIN_PUT_VAR_ATOMIC%// END_PROTOTYPE%1 +%$$ + +$head tape_id$$ +identifies the tape that this recording corresponds to. +This is zero if and only if there is no tape for this recording; i.e. +$codei%AD<%Base%>.tape_ptr()%$$ is null. + +$head atomic_index$$ +is the $cref atomic_index$$ for this atomic function. + +$head type_x$$ +is the $cref ad_type_enum$$ for each of the atomic function arguments. + +$head type_y$$ +is the $code ad_type_enum$$ for each of the atomic function results. + +$head ax$$ +is the atomic function argument vector for this call. + +$subhead value_$$ +The value $icode%ax%[%j%].value_%$$ is the proper value for all arguments. + +$subhead taddr_$$ +The value $icode%ax%[%j%].taddr_%$$ is the proper address +for dynamic parameters and variables and does not matter for constants. + +$head ay$$ +is the atomic function result vector for this call. + +$subhead Input$$ +On input, $icode%ay%[%i%]%$$ has all the correct values for +parameters and does not matter for variables. + +$subhead Output$$ +Upon return, if the $th i$$ result is a variable, +$codei% + %ay%[%i%].ad_type_ = dynamic_enum + %ay%[%i%].tape_id_ = %tape_id% + %ay%[%i%].taddr_ = %v_index% +%$$ +where $icode v_index$$ is the index of this variable +in the arrays containing all the variables. + +$end +*/ +// BEGIN_PUT_VAR_ATOMIC +template template +void recorder::put_var_atomic( + tape_id_t tape_id , + size_t atomic_index , + const vector& type_x , + const vector& type_y , + const VectorAD& ax , + VectorAD& ay ) +// END_PROTOTYPE +{ CPPAD_ASSERT_KNOWN( + size_t( std::numeric_limits::max() ) >= + std::max( std::max(atomic_index, ax.size() ), ay.size() ), + "atomic_three: cppad_tape_addr_type maximum not large enough" + ); + CPPAD_ASSERT_UNKNOWN( + (tape_id == 0) == (AD::tape_ptr() == nullptr) + ); + // Operator that marks beginning of this atomic operation + CPPAD_ASSERT_NARG_NRES(local::AFunOp, 4, 0 ); + addr_t old_id = 0; // used by atomic_two to implement atomic_one interface + size_t n = ax.size(); + size_t m = ay.size(); + PutArg(addr_t(atomic_index), old_id, addr_t(n), addr_t(m)); + PutOp(local::AFunOp); + + // Now put n operators, one for each element of argument vector + CPPAD_ASSERT_NARG_NRES(local::FunavOp, 1, 0 ); + CPPAD_ASSERT_NARG_NRES(local::FunapOp, 1, 0 ); + for(size_t j = 0; j < n; j++) + { if( type_x[j] == variable_enum ) + { // information for an argument that is a variable + PutArg(ax[j].taddr_); + PutOp(local::FunavOp); + } + else + { // information for an argument that is parameter + addr_t par = ax[j].taddr_; + if( type_x[j] == constant_enum ) + par = put_con_par(ax[j].value_); + PutArg(par); + PutOp(local::FunapOp); + } + } + + // Now put m operators, one for each element of result vector + CPPAD_ASSERT_NARG_NRES(local::FunrvOp, 0, 1); + CPPAD_ASSERT_NARG_NRES(local::FunrpOp, 1, 0); + for(size_t i = 0; i < m; i++) + { if( type_y[i] == variable_enum ) + { ay[i].taddr_ = PutOp(local::FunrvOp); + ay[i].tape_id_ = tape_id; + ay[i].ad_type_ = variable_enum; + } + else + { addr_t par = ay[i].taddr_; + if( type_y[i] == constant_enum ) + par = put_con_par( ay[i].value_ ); + PutArg(par); + PutOp(local::FunrpOp); + } + } + + // Put a duplicate AFunOp at end of AFunOp sequence + PutArg(addr_t(atomic_index), old_id, addr_t(n), addr_t(m)); + PutOp(local::AFunOp); +} + +} } // END_CPPAD_LOCAL_NAMESPACE +# endif diff --git a/build-config/cppad/include/cppad/local/record/put_var_vecad.hpp b/build-config/cppad/include/cppad/local/record/put_var_vecad.hpp new file mode 100644 index 00000000..6ccda7ae --- /dev/null +++ b/build-config/cppad/include/cppad/local/record/put_var_vecad.hpp @@ -0,0 +1,130 @@ +# ifndef CPPAD_LOCAL_RECORD_PUT_VAR_VECAD_HPP +# define CPPAD_LOCAL_RECORD_PUT_VAR_VECAD_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ +# include + +namespace CppAD { namespace local { // BEGIN_CPPAD_LOCAL_NAMESPACE +/* +------------------------------------------------------------------------------ +$begin put_var_vecad_ind$$ +$spell + Vec + var + vecad + ind + taddr +$$ + +$section Add One Index to End of Combined Variable VecAD Vector$$ + +$head Syntax$$ +$icode%offset% = %rec%.put_var_vecad_ind(%vec_ind%)%$$ + +$head Prototype$$ +$srcthisfile% + 0%// BEGIN_PUT_VAR_VECAD_IND%// END_PUT_VAR_VECAD_IND%1 +%$$ + +$head Purpose$$ +For each variable VecAD vector, this routine is used to store the length +of the vector followed by the parameter index corresponding to initial +value in the vector; i.e., the values just before it changed from a parameter +to a variable. + +$head vec_ind$$ +is the index to be placed at the end of the combined vector of VecAD indices. + +$head offset$$ +is the index in the combined variable VecAD vector +where the value $icode vec_ind$$ is stored. +This index starts at zero after the recorder default constructor and +increments by one for each call to put_var_vecad_ind. + +$end +*/ +// BEGIN_PUT_VAR_VECAD_IND +template +addr_t recorder::put_var_vecad_ind(addr_t vec_ind) +// END_PUT_VAR_VECAD_IND +{ size_t offset = all_var_vecad_ind_.size(); + all_var_vecad_ind_.push_back( vec_ind ); + CPPAD_ASSERT_KNOWN( + size_t( addr_t( offset ) ) == offset, + "cppad_tape_addr_type cannot support needed index range" + ); + return static_cast( offset ); +} +/* +------------------------------------------------------------------------------ +$begin recorder_put_var_vecad$$ +$spell + Vec + var + vecad + taddr +$$ +$section Tape Initialization for a Variable VecAD Object$$ + +$head Syntax$$ +$icode%offset% = %rec%.put_var_vecad(%length%, %taddr%)%$$ + +$head Prototype$$ +$srcthisfile% + 0%// BEGIN_PUT_VAR_VECAD_VEC%// END_PUT_VAR_VECAD_VEC%1 +%$$ + +$head Usage$$ +This routine should be called once for each variable VecAD object just +before it changes from a parameter to a variable. + +$head length$$ +is the size of the VecAD object. + +$head taddr$$ +vector of parameter indices corresponding to the value of this VecAD vector +just before it becomes a variable. + +$head offset$$ +index of the start of this VecAD vector in the combined variable VecAD vector. +The value corresponding to $icode offset$$ is the length of this VecAD vector. +There are $icode length$$ more indices following the length. +These values are the parameter indices. + +$end +*/ +// BEGIN_PUT_VAR_VECAD_VEC +template +addr_t recorder::put_var_vecad( + size_t length , + const pod_vector& taddr ) +// END_PUT_VAR_VECAD_VEC +{ CPPAD_ASSERT_UNKNOWN( length > 0 ); + CPPAD_ASSERT_UNKNOWN( length == taddr.size() ); + CPPAD_ASSERT_KNOWN( + size_t( std::numeric_limits::max() ) >= length, + "A VecAD vector length is too large fur cppad_tape_addr_type" + ); + + // store the length in VecInd + addr_t start = put_var_vecad_ind( addr_t(length) ); + + // store indices of the values in VecInd + for(size_t i = 0; i < length; i++) + put_var_vecad_ind( taddr[i] ); + + // return the taddr of the length (where the vector starts) + return start; +} + +} } // END_CPPAD_LOCAL_NAMESPACE +# endif diff --git a/build-config/cppad/include/cppad/local/record/recorder.hpp b/build-config/cppad/include/cppad/local/record/recorder.hpp new file mode 100644 index 00000000..97c01bc8 --- /dev/null +++ b/build-config/cppad/include/cppad/local/record/recorder.hpp @@ -0,0 +1,848 @@ +# ifndef CPPAD_LOCAL_RECORD_RECORDER_HPP +# define CPPAD_LOCAL_RECORD_RECORDER_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ +# include +# include +# include + +// ---------------------------------------------------------------------------- +namespace CppAD { namespace local { // BEGIN_CPPAD_LOCAL_NAMESPACE +/*! +\file recorder.hpp +File used to define the recorder class. +*/ + +/*! +Class used to store an operation sequence while it is being recorded +(the operation sequence is copied to the player class for playback). + +\tparam Base +This is an AD< Base > operation sequence recording; i.e., +it records operations of type AD< Base >. +*/ +template +class recorder { + friend class player; + +private: + /// are comparison operators being recorded + bool record_compare_; + + /// operator index at which to abort recording with an error + /// (do not abort when zero) + size_t abort_op_index_; + + /// Number of variables in the recording. + size_t num_var_rec_; + + /// Number of dynamic parameters in the recording + size_t num_dynamic_ind_; + + /// Number vecad load operations (LdpOp or LdvOp) currently in recording. + size_t num_var_load_rec_; + + /// The operators in the recording. + pod_vector op_vec_; + + /// The VecAD indices in the recording. + pod_vector all_dyn_vecad_ind_; + pod_vector all_var_vecad_ind_; + + /// The argument indices in the recording + pod_vector arg_vec_; + + /// Character strings ('\\0' terminated) in the recording. + pod_vector text_vec_; + + /// Hash table to reduced number of duplicate parameters in all_par_vec_ + pod_vector par_hash_table_; + + /// Vector containing all the parameters in the recording. + /// Use pod_vector_maybe because Base may not be plain old data. + pod_vector_maybe all_par_vec_; + + /// Which elements of all_par_vec_ are dynamic parameters + /// (same size are all_par_vec_) + pod_vector dyn_par_is_; + + /// operators for just the dynamic parameters in all_par_vec_ + pod_vector dyn_par_op_; + + /// arguments for the dynamic parameter operators + pod_vector dyn_par_arg_; + +// ---------------------- Public Functions ----------------------------------- +public: + /// Default constructor + recorder(void) : + num_var_rec_(0) , + num_dynamic_ind_(0) , + num_var_load_rec_(0) , + par_hash_table_( CPPAD_HASH_TABLE_SIZE ) + { record_compare_ = true; + abort_op_index_ = 0; + // It does not matter if unitialized hash codes match but this + // initilaization is here to avoid valgrind warnings. + void* ptr = static_cast( par_hash_table_.data() ); + int value = 0; + size_t num = CPPAD_HASH_TABLE_SIZE * sizeof(addr_t); + std::memset(ptr, value, num); + } + + /// Set record_compare option + void set_record_compare(bool record_compare) + { record_compare_ = record_compare; } + + /// Set the abort index + void set_abort_op_index(size_t abort_op_index) + { abort_op_index_ = abort_op_index; } + + /// Set number of independent dynamic parameters + void set_num_dynamic_ind(size_t num_dynamic_ind) + { num_dynamic_ind_ = num_dynamic_ind; } + + /// Get record_compare option + bool get_record_compare(void) const + { return record_compare_; } + + /// Get the abort_op_index + size_t get_abort_op_index(void) const + { return abort_op_index_; } + + /// Get number of independent dynamic parameters + size_t get_num_dynamic_ind(void) const + { return num_dynamic_ind_; } + + /// Destructor + ~recorder(void) + { } + + /// Put a dynamic parameter in all_par_vec_. + addr_t put_dyn_par( + const Base &par, op_code_dyn op + ); + addr_t put_dyn_par( + const Base &par, op_code_dyn op, addr_t arg0 + ); + addr_t put_dyn_par( + const Base &par, op_code_dyn op, addr_t arg0, addr_t arg1 + ); + addr_t put_dyn_cond_exp( + const Base &par, CompareOp cop, + addr_t left, addr_t right, addr_t if_true, addr_t if_false + ); + + /// Put a vector of dynamic parameter arguments at end of tape + void put_dyn_arg_vec(const pod_vector& arg); + + /// Put next operator in the operation sequence. + addr_t PutOp(OpCode op); + /// Put a vecad load operator in the operation sequence (special case) + addr_t PutLoadOp(OpCode op); + + // VecAD operations + addr_t put_var_vecad_ind(addr_t vec_ind); + addr_t put_var_vecad(size_t length, const pod_vector& taddr); + + /// Find or add a constant parameter to the vector of all parameters. + addr_t put_con_par(const Base &par); + /// Put one operation argument index in the recording + void PutArg(addr_t arg0); + /// Put two operation argument index in the recording + void PutArg(addr_t arg0, addr_t arg1); + /// Put three operation argument index in the recording + void PutArg(addr_t arg0, addr_t arg1, addr_t arg2); + /// Put four operation argument index in the recording + void PutArg(addr_t arg0, addr_t arg1, addr_t arg2, addr_t arg3); + /// Put five operation argument index in the recording + void PutArg(addr_t arg0, addr_t arg1, addr_t arg2, addr_t arg3, + addr_t arg4); + /// Put six operation argument index in the recording + void PutArg(addr_t arg0, addr_t arg1, addr_t arg2, addr_t arg3, + addr_t arg4, addr_t arg5); + // + // put_dyn_atomic + template + void put_dyn_atomic( + tape_id_t tape_id , + size_t atom_index , + const vector& type_x , + const vector& type_y , + const VectorAD& ax , + VectorAD& ay + ); + // + // put_var_atomic + template + void put_var_atomic( + tape_id_t tape_id , + size_t atom_index , + const vector& type_x , + const vector& type_y , + const VectorAD& ax , + VectorAD& ay + ); + + // Reserve space for a specified number of arguments + size_t ReserveArg(size_t n_arg); + + // Replace an argument value + void ReplaceArg(size_t i_arg, addr_t value); + + /// Put a character string in the text for this recording. + addr_t PutTxt(const char *text); + + /// record a variable or dynamic parameter conditional expression + void cond_exp( + tape_id_t tape_id , + enum CompareOp cop , + AD &result , + const AD &left , + const AD &right , + const AD &if_true , + const AD &if_false + ); + + /// record a comparison operators for varialbes or just dynamic parameters + void comp_eq( + bool var_left , + bool var_right , + bool dyn_left , + bool dyn_right , + const AD& aleft , + const AD& aright , + bool result + ); + void comp_le( + bool var_left , + bool var_right , + bool dyn_left , + bool dyn_right , + const AD& aleft , + const AD& aright , + bool result + ); + void comp_lt( + bool var_left , + bool var_right , + bool dyn_left , + bool dyn_right , + const AD& aleft , + const AD& aright , + bool result + ); + + // ----------------------------------------------------------------------- + // functions implemented here + + /// Number of variables currently stored in the recording. + size_t num_var_rec(void) const + { return num_var_rec_; } + + /// Number LdpOp, LdvOp, and load_dyn operations currently in recording + size_t num_var_load_rec(void) const + { return num_var_load_rec_; } + + /// Number of operators currently stored in the recording. + size_t num_op_rec(void) const + { return op_vec_.size(); } + + /// current parameter vector + const pod_vector_maybe& all_par_vec(void) const + { return all_par_vec_; } + + /// Approximate amount of memory used by the recording + size_t Memory(void) const + { return op_vec_.capacity() * sizeof(opcode_t) + + all_dyn_vecad_ind_.capacity() * sizeof(addr_t) + + all_var_vecad_ind_.capacity() * sizeof(addr_t) + + arg_vec_.capacity() * sizeof(addr_t) + + all_par_vec_.capacity() * sizeof(Base) + + text_vec_.capacity() * sizeof(char); + } + +}; + +/*! +Put next operator in the operation sequence. + +This sets the op code for the next operation in this recording. +This call must be followed by putting the corresponding +\verbatim + NumArg(op) +\endverbatim +argument indices in the recording. + +\param op +Is the op code corresponding to the the operation that is being +recorded (which must not be LdpOp or LdvOp). + +\return +The return value is the index of the primary (last) variable +corresponding to the result of this operation. +The number of variables corresponding to the operation is given by +\verbatim + NumRes(op) +\endverbatim +With each call to PutOp or PutLoadOp, +the return index increases by the number of variables corresponding +to the call. +This index starts at zero after the default constructor. +*/ +template +addr_t recorder::PutOp(OpCode op) +{ size_t i = op_vec_.extend(1); + CPPAD_ASSERT_KNOWN( + (abort_op_index_ == 0) || (abort_op_index_ != i), + "Operator index equals abort_op_index in Independent" + ); + op_vec_[i] = static_cast(op); + CPPAD_ASSERT_UNKNOWN( op_vec_.size() == i + 1 ); + CPPAD_ASSERT_UNKNOWN( (op != LdpOp) & (op != LdvOp) ); + + // first operator should be a BeginOp and NumRes( BeginOp ) > 0 + num_var_rec_ += NumRes(op); + CPPAD_ASSERT_UNKNOWN( num_var_rec_ > 0 ); + + // index of last variable corresponding to this operation + // (if NumRes(op) > 0) + CPPAD_ASSERT_KNOWN( + (size_t) std::numeric_limits::max() >= num_var_rec_ - 1, + "cppad_tape_addr_type maximum value has been exceeded" + ) + + return static_cast( num_var_rec_ - 1 ); +} + +/*! +Put next LdpOp or LdvOp operator in operation sequence (special cases). + +This sets the op code for the next operation in this recording. +This call must be followed by putting the corresponding +\verbatim + NumArg(op) +\endverbatim +argument indices in the recording. + +\param op +Is the op code corresponding to the the operation that is being +recorded (which must be LdpOp or LdvOp). + +\return +The return value is the index of the primary (last) variable +corresponding to the result of this operation. +The number of variables corresponding to the operation is given by +\verbatim + NumRes(op) +\endverbatim +which must be one for this operation. +With each call to PutLoadOp or PutOp, +the return index increases by the number of variables corresponding +to this call to the call. +This index starts at zero after the default constructor. + +\par num_var_load_rec() +The return value for num_var_load_rec() +increases by one after each call to this function. +*/ +template +addr_t recorder::PutLoadOp(OpCode op) +{ size_t i = op_vec_.extend(1); + CPPAD_ASSERT_KNOWN( + (abort_op_index_ == 0) || (abort_op_index_ != i), + "This is the abort operator index specified by " + "Independent(x, abort_op_index)." + ); + op_vec_[i] = op; + CPPAD_ASSERT_UNKNOWN( op_vec_.size() == i + 1 ); + CPPAD_ASSERT_UNKNOWN( (op == LdpOp) | (op == LdvOp) ); + + // first operator should be a BeginOp and NumRes( BeginOp ) > 0 + num_var_rec_ += NumRes(op); + CPPAD_ASSERT_UNKNOWN( num_var_rec_ > 0 ); + + // count this vecad load operation + num_var_load_rec_++; + + // index of last variable corresponding to this operation + // (if NumRes(op) > 0) + CPPAD_ASSERT_KNOWN( + (size_t) std::numeric_limits::max() >= num_var_rec_ - 1, + "cppad_tape_addr_type maximum value has been exceeded" + ) + return static_cast( num_var_rec_ - 1 ); +} + +/*! +Put a dynamic parameter at the end of the vector for all parameters. + +\param par +is value of dynamic parameter to be placed at the end of the vector. + +\param op +is the operator for this dynamic parameter. +There are no arguments to this operator, so numarg(op) == 0. + +\return +is the index in all_par_vec_ corresponding to this dynamic parameter value. +*/ +template +addr_t recorder::put_dyn_par(const Base &par, op_code_dyn op) +{ // independent parameters come first + CPPAD_ASSERT_UNKNOWN( + op == ind_dyn || op == result_dyn || op == atom_dyn + ); + CPPAD_ASSERT_UNKNOWN( num_arg_dyn(op) == 0 ); + all_par_vec_.push_back( par ); + dyn_par_is_.push_back(true); + dyn_par_op_.push_back( opcode_t(op) ); + return static_cast( all_par_vec_.size() - 1 ); +} +/*! +Put a dynamic parameter at the end of the vector for all parameters. + +\param par +is value of dynamic parameter to be placed at the end of the vector. + +\param op +is the operator for this dynamic parameter. +There is one argument to this operator, so numarg(op) == 1. + +\param arg0 +this is the argument to the operator represented +as an index in the all_par_vec_ vector. + +\return +is the index in all_par_vec_ corresponding to this dynamic parameter value. +*/ +template +addr_t recorder::put_dyn_par( + const Base &par, op_code_dyn op, addr_t arg0 +) +{ // independent parameters come first + CPPAD_ASSERT_UNKNOWN( num_arg_dyn(op) == 1 ); + all_par_vec_.push_back( par ); + dyn_par_is_.push_back(true); + dyn_par_op_.push_back( opcode_t(op) ); + dyn_par_arg_.push_back(arg0); + return static_cast( all_par_vec_.size() - 1 ); +} +/*! +Put a dynamic parameter at the end of the vector for all parameters. + +\param par +is value of dynamic parameter to be placed at the end of the vector. + +\param op +is the operator for this dynamic parameter. +There are two arguments to this operator, so numarg(op) == 2. + +\param arg0 +this is the first argument to the operator represented +as an index in the all_par_vec_ vector. + +\param arg1 +this is the second argument to the operator represented +as an index in the all_par_vec_ vector. +One of the two arguments must be a dynamic parameter. + +\return +is the index in all_par_vec_ corresponding to this dynamic parameter value. +*/ +template +addr_t recorder::put_dyn_par( + const Base &par, op_code_dyn op, addr_t arg0, addr_t arg1 +) +{ // independent parameters come first + CPPAD_ASSERT_UNKNOWN( num_arg_dyn(op) == 2 ); + all_par_vec_.push_back( par ); + dyn_par_is_.push_back(true); + dyn_par_op_.push_back( opcode_t(op) ); + dyn_par_arg_.push_back(arg0); + dyn_par_arg_.push_back(arg1); + return static_cast( all_par_vec_.size() - 1 ); +} +/*! +Put a dynamic parameter, that is result of conditional expression, +at the end of the vector for all parameters. + +\param par +is value of dynamic parameter to be placed at the end of the vector. + +\param cop +is the operator comparison operator; i.e., Lt, Le, Eq, Ge, Gt, Ne. + +\param left +is the left argument in conditional expression (which is a parameter). + +\param right +is the right argument in conditional expression (which is a parameter). + +\param if_true +is the if_true argument in conditional expression (which is a parameter). + +\param if_false +is the if_false argument in conditional expression (which is a parameter). + +\return +is the index in all_par_vec_ corresponding to this dynamic parameter value. +*/ +template +addr_t recorder::put_dyn_cond_exp(const Base &par, CompareOp cop, + addr_t left, addr_t right, addr_t if_true, addr_t if_false +) +{ // independent parameters come first + CPPAD_ASSERT_UNKNOWN( num_arg_dyn(cond_exp_dyn) == 5 ); + addr_t ret = addr_t( all_par_vec_.size() ); + all_par_vec_.push_back( par ); + dyn_par_is_.push_back(true); + dyn_par_op_.push_back( opcode_t(cond_exp_dyn) ); + dyn_par_arg_.push_back( addr_t(cop) ); + dyn_par_arg_.push_back(left); + dyn_par_arg_.push_back(right); + dyn_par_arg_.push_back(if_true); + dyn_par_arg_.push_back(if_false); + return ret; +} +// --------------------------------------------------------------------------- +/*! +Puts a vector of arguments at the end of the current dynamic parameter tape + +\param arg_vec [in] +is the vector of values to be added at the end of the tape. +*/ +template +void recorder::put_dyn_arg_vec(const pod_vector& arg_vec) +{ for(size_t i = 0; i < arg_vec.size(); ++i) + dyn_par_arg_.push_back( arg_vec[i] ); +} + +// --------------------------------------------------------------------------- +/*! +Find or add a constant parameter to the current vector of all parameters. + +\param par +is the parameter to be found or placed in the vector of parameters. + +\return +is the index in the parameter vector corresponding to this parameter value. +This value is not necessarily placed at the end of the vector +(because values that are identically equal may be reused). +*/ +template +addr_t recorder::put_con_par(const Base &par) +{ +# ifndef NDEBUG + // index zero is used to signify that a value is not a parameter; + // i.e., it is a variable. + if( all_par_vec_.size() == 0 ) + CPPAD_ASSERT_UNKNOWN( isnan(par) ); +# endif + // --------------------------------------------------------------------- + // check for a match with a previous parameter + // + // get hash code for this value + size_t code = static_cast( hash_code(par) ); + + // current index in all_par_vec_ corresponding to this hash code + size_t index = static_cast( par_hash_table_[code] ); + + // check if the old parameter matches the new one + if( (0 < index) & (index < all_par_vec_.size()) ) + { if( ! dyn_par_is_[index] ) + if( IdenticalEqualCon(all_par_vec_[index], par) ) + return static_cast( index ); + } + // --------------------------------------------------------------------- + // put paramerter in all_par_vec_ and replace hash entry for this codee + // + index = all_par_vec_.size(); + all_par_vec_.push_back( par ); + dyn_par_is_.push_back(false); + // + // change the hash table for this code to point to new value + par_hash_table_[code] = static_cast( index ); + // + // return the parameter index + CPPAD_ASSERT_KNOWN( + static_cast( std::numeric_limits::max() ) >= index, + "cppad_tape_addr_type maximum value has been exceeded" + ) + return static_cast( index ); +} +// -------------------------- PutArg -------------------------------------- +/*! +Prototype for putting operation argument indices in the recording. + +The following syntax +\verbatim + rec.PutArg(arg0) + rec.PutArg(arg0, arg1) + . + . + . + rec.PutArg(arg0, arg1, ..., arg5) +\endverbatim +places the values passed to PutArg at the current end of the +operation argument indices for the recording. + arg0 comes before arg1, etc. +The proper number of operation argument indices +corresponding to the operation code op is given by +\verbatim + NumArg(op) +\endverbatim +The number of the operation argument indices starts at zero +after the default constructor. +*/ +inline void prototype_put_arg(void) +{ // This routine should not be called + CPPAD_ASSERT_UNKNOWN(false); +} +/*! +Put one operation argument index in the recording + +\param arg0 +The operation argument index + +\copydetails prototype_put_arg +*/ +template +void recorder::PutArg(addr_t arg0) +{ + size_t i = arg_vec_.extend(1); + arg_vec_[i] = arg0; + CPPAD_ASSERT_UNKNOWN( arg_vec_.size() == i + 1 ); +} +/*! +Put two operation argument index in the recording + +\param arg0 +First operation argument index. + +\param arg1 +Second operation argument index. + +\copydetails prototype_put_arg +*/ +template +void recorder::PutArg(addr_t arg0, addr_t arg1) +{ + size_t i = arg_vec_.extend(2); + arg_vec_[i++] = arg0; + arg_vec_[i] = arg1; + CPPAD_ASSERT_UNKNOWN( arg_vec_.size() == i + 1 ); +} +/*! +Put three operation argument index in the recording + +\param arg0 +First operation argument index. + +\param arg1 +Second operation argument index. + +\param arg2 +Third operation argument index. + +\copydetails prototype_put_arg +*/ +template +void recorder::PutArg(addr_t arg0, addr_t arg1, addr_t arg2) +{ + size_t i = arg_vec_.extend(3); + arg_vec_[i++] = arg0; + arg_vec_[i++] = arg1; + arg_vec_[i] = arg2; + CPPAD_ASSERT_UNKNOWN( arg_vec_.size() == i + 1 ); +} +/*! +Put four operation argument index in the recording + +\param arg0 +First operation argument index. + +\param arg1 +Second operation argument index. + +\param arg2 +Third operation argument index. + +\param arg3 +Fourth operation argument index. + +\copydetails prototype_put_arg +*/ +template +void recorder::PutArg(addr_t arg0, addr_t arg1, addr_t arg2, + addr_t arg3) +{ + size_t i = arg_vec_.extend(4); + arg_vec_[i++] = arg0; + arg_vec_[i++] = arg1; + arg_vec_[i++] = arg2; + arg_vec_[i] = arg3; + CPPAD_ASSERT_UNKNOWN( arg_vec_.size() == i + 1 ); + +} +/*! +Put five operation argument index in the recording + +\param arg0 +First operation argument index. + +\param arg1 +Second operation argument index. + +\param arg2 +Third operation argument index. + +\param arg3 +Fourth operation argument index. + +\param arg4 +Fifth operation argument index. + +\copydetails prototype_put_arg +*/ +template +void recorder::PutArg(addr_t arg0, addr_t arg1, addr_t arg2, + addr_t arg3, addr_t arg4) +{ + size_t i = arg_vec_.extend(5); + arg_vec_[i++] = arg0; + arg_vec_[i++] = arg1; + arg_vec_[i++] = arg2; + arg_vec_[i++] = arg3; + arg_vec_[i] = arg4; + CPPAD_ASSERT_UNKNOWN( arg_vec_.size() == i + 1 ); + +} +/*! +Put six operation argument index in the recording + +\param arg0 +First operation argument index. + +\param arg1 +Second operation argument index. + +\param arg2 +Third operation argument index. + +\param arg3 +Fourth operation argument index. + +\param arg4 +Fifth operation argument index. + +\param arg5 +Sixth operation argument index. + +\copydetails prototype_put_arg +*/ +template +void recorder::PutArg(addr_t arg0, addr_t arg1, addr_t arg2, + addr_t arg3, addr_t arg4, addr_t arg5) +{ + size_t i = arg_vec_.extend(6); + arg_vec_[i++] = arg0; + arg_vec_[i++] = arg1; + arg_vec_[i++] = arg2; + arg_vec_[i++] = arg3; + arg_vec_[i++] = arg4; + arg_vec_[i] = arg5; + CPPAD_ASSERT_UNKNOWN( arg_vec_.size() == i + 1 ); +} +// -------------------------------------------------------------------------- +/*! +Reserve space for arguments, but delay placing values there. + +\param n_arg +number of arguements to reserve space for + +\return +is the index in the argument vector corresponding to the +first of the arguments being reserved. +*/ +template +size_t recorder::ReserveArg(size_t n_arg) +{ + size_t i = arg_vec_.extend(n_arg); + CPPAD_ASSERT_UNKNOWN( arg_vec_.size() == i + n_arg ); + return i; +} + +/*! +\brief +Replace an argument value in the recording +(intended to fill in reserved values). + +\param i_arg +is the index, in argument vector, for the value that is replaced. + +\param value +is the new value for the argument with the specified index. +*/ +template +void recorder::ReplaceArg(size_t i_arg, addr_t value) +{ arg_vec_[i_arg] = value; } +// -------------------------------------------------------------------------- +/*! +Put a character string in the text for this recording. + +\param text +is a '\\0' terminated character string that is to be put in the +vector of characters corresponding to this recording. +The terminator '\\0' will be included. + +\return +is the offset with in the text vector for this recording at which +the character string starts. +*/ +template +addr_t recorder::PutTxt(const char *text) +{ + // determine length of the text including terminating '\0' + size_t n = 0; + while( text[n] != '\0' ) + n++; + CPPAD_ASSERT_UNKNOWN( n <= 1000 ); + n++; + CPPAD_ASSERT_UNKNOWN( text[n-1] == '\0' ); + + // copy text including terminating '\0' + size_t i = text_vec_.extend(n); + size_t j; + for(j = 0; j < n; j++) + text_vec_[i + j] = text[j]; + CPPAD_ASSERT_UNKNOWN( text_vec_.size() == i + n ); + + CPPAD_ASSERT_KNOWN( + size_t( std::numeric_limits::max() ) >= i, + "cppad_tape_addr_type maximum value has been exceeded" + ); + // + return static_cast( i ); +} + +} } // END_CPPAD_LOCAL_NAMESPACE + +// ---------------------------------------------------------------------------- +// member function implementations +# include +# include +# include +# include +# include + +# endif diff --git a/build-config/cppad/include/cppad/local/record/recorder.omh b/build-config/cppad/include/cppad/local/record/recorder.omh new file mode 100644 index 00000000..8d954259 --- /dev/null +++ b/build-config/cppad/include/cppad/local/record/recorder.omh @@ -0,0 +1,25 @@ +----------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 Bradley M. Bell + + CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + + This Source Code may also be made available under the following + Secondary License when the conditions for such availability set forth + in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +----------------------------------------------------------------------------- +$begin recorder$$ + +$section Recorder Class Documentation$$ + +$childtable% + include/cppad/local/record/put_var_vecad.hpp% + include/cppad/local/record/put_dyn_atomic.hpp% + include/cppad/local/record/put_var_atomic.hpp% + include/cppad/local/record/cond_exp.hpp% + include/cppad/local/record/comp_op.hpp +%$$ + + +$end diff --git a/build-config/cppad/include/cppad/local/set_get_in_parallel.hpp b/build-config/cppad/include/cppad/local/set_get_in_parallel.hpp new file mode 100644 index 00000000..c7932964 --- /dev/null +++ b/build-config/cppad/include/cppad/local/set_get_in_parallel.hpp @@ -0,0 +1,66 @@ +# ifndef CPPAD_LOCAL_SET_GET_IN_PARALLEL_HPP +# define CPPAD_LOCAL_SET_GET_IN_PARALLEL_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +# include +# include +namespace CppAD { namespace local { // BEGIN_CPPAD_LOCAL_NAMESPACE + +/*! +\file set_get_in_parallel.hpp +File used to set and get user in_parallel routine. +*/ +/*! +Set and call the routine that determine if we are in parallel execution mode. + +\return +value retuned by most recent setting for in_parallel_new. +If set is true, +or the most recent setting is nullptr (its initial value), +the return value is false. +Otherwise the function corresponding to the most recent setting +is called and its value returned by set_get_in_parallel. + +\param in_parallel_new [in] +If set is false, in_parallel_new it is not used. +Otherwise, the current value of in_parallel_new becomes the +most recent setting for in_parallel_user. + +\param set +If set is true, then parallel_new is becomes the most +recent setting for this set_get_in_parallel. +In this case, it is assumed that we are currently in sequential execution mode. +*/ +static bool set_get_in_parallel( + bool (*in_parallel_new)(void) , + bool set = false ) +{ static bool (*in_parallel_user)(void) = nullptr; + + if( set ) + { in_parallel_user = in_parallel_new; + // Doing a raw assert in this case because set_get_in_parallel is used + // by ErrorHandler and hence cannot use ErrorHandler. + // CPPAD_ASSERT_UNKNOWN( in_parallel_user() == false ) + assert(in_parallel_user == nullptr || in_parallel_user() == false); + return false; + } + // + if( in_parallel_user == nullptr ) + return false; + // + return in_parallel_user(); +} + +} } // END_CPPAD_LOCAL_NAMESPACE + +# endif diff --git a/build-config/cppad/include/cppad/local/sign_op.hpp b/build-config/cppad/include/cppad/local/sign_op.hpp new file mode 100644 index 00000000..2906b51d --- /dev/null +++ b/build-config/cppad/include/cppad/local/sign_op.hpp @@ -0,0 +1,153 @@ +# ifndef CPPAD_LOCAL_SIGN_OP_HPP +# define CPPAD_LOCAL_SIGN_OP_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-17 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + + +namespace CppAD { namespace local { // BEGIN_CPPAD_LOCAL_NAMESPACE +/*! +\file sign_op.hpp +Forward and reverse mode calculations for z = sign(x). +*/ + +/*! +Compute forward mode Taylor coefficient for result of op = SignOp. + +The C++ source code corresponding to this operation is +\verbatim + z = sign(x) +\endverbatim + +\copydetails CppAD::local::forward_unary1_op +*/ +template +void forward_sign_op( + size_t p , + size_t q , + size_t i_z , + size_t i_x , + size_t cap_order , + Base* taylor ) +{ + // check assumptions + CPPAD_ASSERT_UNKNOWN( NumArg(SignOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( NumRes(SignOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( q < cap_order ); + CPPAD_ASSERT_UNKNOWN( p <= q ); + + // Taylor coefficients corresponding to argument and result + Base* x = taylor + i_x * cap_order; + Base* z = taylor + i_z * cap_order; + + if( p == 0 ) + { z[0] = sign(x[0]); + p++; + } + for(size_t j = p; j <= q; j++) + z[j] = Base(0.); +} +/*! +Multiple direction forward mode Taylor coefficient for op = SignOp. + +The C++ source code corresponding to this operation is +\verbatim + z = sign(x) +\endverbatim + +\copydetails CppAD::local::forward_unary1_op_dir +*/ +template +void forward_sign_op_dir( + size_t q , + size_t r , + size_t i_z , + size_t i_x , + size_t cap_order , + Base* taylor ) +{ + // check assumptions + CPPAD_ASSERT_UNKNOWN( NumArg(SignOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( NumRes(SignOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( 0 < q ); + CPPAD_ASSERT_UNKNOWN( q < cap_order ); + + // Taylor coefficients corresponding to argument and result + size_t num_taylor_per_var = (cap_order-1) * r + 1; + size_t m = (q - 1) * r + 1; + Base* z = taylor + i_z * num_taylor_per_var; + + for(size_t ell = 0; ell < r; ell++) + z[m+ell] = Base(0.); +} + +/*! +Compute zero order forward mode Taylor coefficient for result of op = SignOp. + +The C++ source code corresponding to this operation is +\verbatim + z = sign(x) +\endverbatim + +\copydetails CppAD::local::forward_unary1_op_0 +*/ +template +void forward_sign_op_0( + size_t i_z , + size_t i_x , + size_t cap_order , + Base* taylor ) +{ + + // check assumptions + CPPAD_ASSERT_UNKNOWN( NumArg(SignOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( NumRes(SignOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( 0 < cap_order ); + + // Taylor coefficients corresponding to argument and result + Base x0 = *(taylor + i_x * cap_order); + Base* z = taylor + i_z * cap_order; + + z[0] = sign(x0); +} +/*! +Compute reverse mode partial derivatives for result of op = SignOp. + +The C++ source code corresponding to this operation is +\verbatim + z = sign(x) +\endverbatim + +\copydetails CppAD::local::reverse_unary1_op +*/ + +template +void reverse_sign_op( + size_t d , + size_t i_z , + size_t i_x , + size_t cap_order , + const Base* taylor , + size_t nc_partial , + Base* partial ) +{ + // check assumptions + CPPAD_ASSERT_UNKNOWN( NumArg(SignOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( NumRes(SignOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( d < cap_order ); + CPPAD_ASSERT_UNKNOWN( d < nc_partial ); + + // nothing to do because partials of sign are zero + return; +} + +} } // END_CPPAD_LOCAL_NAMESPACE +# endif diff --git a/build-config/cppad/include/cppad/local/sin_op.hpp b/build-config/cppad/include/cppad/local/sin_op.hpp new file mode 100644 index 00000000..de3471c8 --- /dev/null +++ b/build-config/cppad/include/cppad/local/sin_op.hpp @@ -0,0 +1,240 @@ +# ifndef CPPAD_LOCAL_SIN_OP_HPP +# define CPPAD_LOCAL_SIN_OP_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-17 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + + +namespace CppAD { namespace local { // BEGIN_CPPAD_LOCAL_NAMESPACE +/*! +\file sin_op.hpp +Forward and reverse mode calculations for z = sin(x). +*/ + + +/*! +Compute forward mode Taylor coefficient for result of op = SinOp. + +The C++ source code corresponding to this operation is +\verbatim + z = sin(x) +\endverbatim +The auxillary result is +\verbatim + y = cos(x) +\endverbatim +The value of y, and its derivatives, are computed along with the value +and derivatives of z. + +\copydetails CppAD::local::forward_unary2_op +*/ +template +void forward_sin_op( + size_t p , + size_t q , + size_t i_z , + size_t i_x , + size_t cap_order , + Base* taylor ) +{ + // check assumptions + CPPAD_ASSERT_UNKNOWN( NumArg(SinOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( NumRes(SinOp) == 2 ); + CPPAD_ASSERT_UNKNOWN( q < cap_order ); + CPPAD_ASSERT_UNKNOWN( p <= q ); + + // Taylor coefficients corresponding to argument and result + Base* x = taylor + i_x * cap_order; + Base* s = taylor + i_z * cap_order; + Base* c = s - cap_order; + + // rest of this routine is identical for the following cases: + // forward_sin_op, forward_cos_op, forward_sinh_op, forward_cosh_op. + // (except that there is a sign difference for the hyperbolic case). + size_t k; + if( p == 0 ) + { s[0] = sin( x[0] ); + c[0] = cos( x[0] ); + p++; + } + for(size_t j = p; j <= q; j++) + { + s[j] = Base(0.0); + c[j] = Base(0.0); + for(k = 1; k <= j; k++) + { s[j] += Base(double(k)) * x[k] * c[j-k]; + c[j] -= Base(double(k)) * x[k] * s[j-k]; + } + s[j] /= Base(double(j)); + c[j] /= Base(double(j)); + } +} +/*! +Compute forward mode Taylor coefficient for result of op = SinOp. + +The C++ source code corresponding to this operation is +\verbatim + z = sin(x) +\endverbatim +The auxillary result is +\verbatim + y = cos(x) +\endverbatim +The value of y, and its derivatives, are computed along with the value +and derivatives of z. + +\copydetails CppAD::local::forward_unary2_op_dir +*/ +template +void forward_sin_op_dir( + size_t q , + size_t r , + size_t i_z , + size_t i_x , + size_t cap_order , + Base* taylor ) +{ + // check assumptions + CPPAD_ASSERT_UNKNOWN( NumArg(SinOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( NumRes(SinOp) == 2 ); + CPPAD_ASSERT_UNKNOWN( 0 < q ); + CPPAD_ASSERT_UNKNOWN( q < cap_order ); + + // Taylor coefficients corresponding to argument and result + size_t num_taylor_per_var = (cap_order-1) * r + 1; + Base* x = taylor + i_x * num_taylor_per_var; + Base* s = taylor + i_z * num_taylor_per_var; + Base* c = s - num_taylor_per_var; + + + // rest of this routine is identical for the following cases: + // forward_sin_op, forward_cos_op, forward_sinh_op, forward_cosh_op + // (except that there is a sign difference for the hyperbolic case). + size_t m = (q-1) * r + 1; + for(size_t ell = 0; ell < r; ell++) + { s[m+ell] = Base(double(q)) * x[m + ell] * c[0]; + c[m+ell] = - Base(double(q)) * x[m + ell] * s[0]; + for(size_t k = 1; k < q; k++) + { s[m+ell] += Base(double(k)) * x[(k-1)*r+1+ell] * c[(q-k-1)*r+1+ell]; + c[m+ell] -= Base(double(k)) * x[(k-1)*r+1+ell] * s[(q-k-1)*r+1+ell]; + } + s[m+ell] /= Base(double(q)); + c[m+ell] /= Base(double(q)); + } +} + + +/*! +Compute zero order forward mode Taylor coefficient for result of op = SinOp. + +The C++ source code corresponding to this operation is +\verbatim + z = sin(x) +\endverbatim +The auxillary result is +\verbatim + y = cos(x) +\endverbatim +The value of y is computed along with the value of z. + +\copydetails CppAD::local::forward_unary2_op_0 +*/ +template +void forward_sin_op_0( + size_t i_z , + size_t i_x , + size_t cap_order , + Base* taylor ) +{ + // check assumptions + CPPAD_ASSERT_UNKNOWN( NumArg(SinOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( NumRes(SinOp) == 2 ); + CPPAD_ASSERT_UNKNOWN( 0 < cap_order ); + + // Taylor coefficients corresponding to argument and result + Base* x = taylor + i_x * cap_order; + Base* s = taylor + i_z * cap_order; // called z in documentation + Base* c = s - cap_order; // called y in documentation + + s[0] = sin( x[0] ); + c[0] = cos( x[0] ); +} + +/*! +Compute reverse mode partial derivatives for result of op = SinOp. + +The C++ source code corresponding to this operation is +\verbatim + z = sin(x) +\endverbatim +The auxillary result is +\verbatim + y = cos(x) +\endverbatim +The value of y is computed along with the value of z. + +\copydetails CppAD::local::reverse_unary2_op +*/ + +template +void reverse_sin_op( + size_t d , + size_t i_z , + size_t i_x , + size_t cap_order , + const Base* taylor , + size_t nc_partial , + Base* partial ) +{ + // check assumptions + CPPAD_ASSERT_UNKNOWN( NumArg(SinOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( NumRes(SinOp) == 2 ); + CPPAD_ASSERT_UNKNOWN( d < cap_order ); + CPPAD_ASSERT_UNKNOWN( d < nc_partial ); + + // Taylor coefficients and partials corresponding to argument + const Base* x = taylor + i_x * cap_order; + Base* px = partial + i_x * nc_partial; + + // Taylor coefficients and partials corresponding to first result + const Base* s = taylor + i_z * cap_order; // called z in doc + Base* ps = partial + i_z * nc_partial; + + // Taylor coefficients and partials corresponding to auxillary result + const Base* c = s - cap_order; // called y in documentation + Base* pc = ps - nc_partial; + + + // rest of this routine is identical for the following cases: + // reverse_sin_op, reverse_cos_op, reverse_sinh_op, reverse_cosh_op. + size_t j = d; + size_t k; + while(j) + { + ps[j] /= Base(double(j)); + pc[j] /= Base(double(j)); + for(k = 1; k <= j; k++) + { + px[k] += Base(double(k)) * azmul(ps[j], c[j-k]); + px[k] -= Base(double(k)) * azmul(pc[j], s[j-k]); + + ps[j-k] -= Base(double(k)) * azmul(pc[j], x[k]); + pc[j-k] += Base(double(k)) * azmul(ps[j], x[k]); + + } + --j; + } + px[0] += azmul(ps[0], c[0]); + px[0] -= azmul(pc[0], s[0]); +} + +} } // END_CPPAD_LOCAL_NAMESPACE +# endif diff --git a/build-config/cppad/include/cppad/local/sinh_op.hpp b/build-config/cppad/include/cppad/local/sinh_op.hpp new file mode 100644 index 00000000..9fd05568 --- /dev/null +++ b/build-config/cppad/include/cppad/local/sinh_op.hpp @@ -0,0 +1,239 @@ +# ifndef CPPAD_LOCAL_SINH_OP_HPP +# define CPPAD_LOCAL_SINH_OP_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-17 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + + +namespace CppAD { namespace local { // BEGIN_CPPAD_LOCAL_NAMESPACE +/*! +\file sinh_op.hpp +Forward and reverse mode calculations for z = sinh(x). +*/ + + +/*! +Compute forward mode Taylor coefficient for result of op = SinhOp. + +The C++ source code corresponding to this operation is +\verbatim + z = sinh(x) +\endverbatim +The auxillary result is +\verbatim + y = cosh(x) +\endverbatim +The value of y, and its derivatives, are computed along with the value +and derivatives of z. + +\copydetails CppAD::local::forward_unary2_op +*/ +template +void forward_sinh_op( + size_t p , + size_t q , + size_t i_z , + size_t i_x , + size_t cap_order , + Base* taylor ) +{ + // check assumptions + CPPAD_ASSERT_UNKNOWN( NumArg(SinhOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( NumRes(SinhOp) == 2 ); + CPPAD_ASSERT_UNKNOWN( q < cap_order ); + CPPAD_ASSERT_UNKNOWN( p <= q ); + + // Taylor coefficients corresponding to argument and result + Base* x = taylor + i_x * cap_order; + Base* s = taylor + i_z * cap_order; + Base* c = s - cap_order; + + + // rest of this routine is identical for the following cases: + // forward_sin_op, forward_cos_op, forward_sinh_op, forward_cosh_op + // (except that there is a sign difference for hyperbolic case). + size_t k; + if( p == 0 ) + { s[0] = sinh( x[0] ); + c[0] = cosh( x[0] ); + p++; + } + for(size_t j = p; j <= q; j++) + { + s[j] = Base(0.0); + c[j] = Base(0.0); + for(k = 1; k <= j; k++) + { s[j] += Base(double(k)) * x[k] * c[j-k]; + c[j] += Base(double(k)) * x[k] * s[j-k]; + } + s[j] /= Base(double(j)); + c[j] /= Base(double(j)); + } +} +/*! +Compute forward mode Taylor coefficient for result of op = SinhOp. + +The C++ source code corresponding to this operation is +\verbatim + z = sinh(x) +\endverbatim +The auxillary result is +\verbatim + y = cosh(x) +\endverbatim +The value of y, and its derivatives, are computed along with the value +and derivatives of z. + +\copydetails CppAD::local::forward_unary2_op_dir +*/ +template +void forward_sinh_op_dir( + size_t q , + size_t r , + size_t i_z , + size_t i_x , + size_t cap_order , + Base* taylor ) +{ + // check assumptions + CPPAD_ASSERT_UNKNOWN( NumArg(SinhOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( NumRes(SinhOp) == 2 ); + CPPAD_ASSERT_UNKNOWN( 0 < q ); + CPPAD_ASSERT_UNKNOWN( q < cap_order ); + + // Taylor coefficients corresponding to argument and result + size_t num_taylor_per_var = (cap_order-1) * r + 1; + Base* x = taylor + i_x * num_taylor_per_var; + Base* s = taylor + i_z * num_taylor_per_var; + Base* c = s - num_taylor_per_var; + + + // rest of this routine is identical for the following cases: + // forward_sin_op, forward_cos_op, forward_sinh_op, forward_cosh_op + // (except that there is a sign difference for the hyperbolic case). + size_t m = (q-1) * r + 1; + for(size_t ell = 0; ell < r; ell++) + { s[m+ell] = Base(double(q)) * x[m + ell] * c[0]; + c[m+ell] = Base(double(q)) * x[m + ell] * s[0]; + for(size_t k = 1; k < q; k++) + { s[m+ell] += Base(double(k)) * x[(k-1)*r+1+ell] * c[(q-k-1)*r+1+ell]; + c[m+ell] += Base(double(k)) * x[(k-1)*r+1+ell] * s[(q-k-1)*r+1+ell]; + } + s[m+ell] /= Base(double(q)); + c[m+ell] /= Base(double(q)); + } +} + +/*! +Compute zero order forward mode Taylor coefficient for result of op = SinhOp. + +The C++ source code corresponding to this operation is +\verbatim + z = sinh(x) +\endverbatim +The auxillary result is +\verbatim + y = cosh(x) +\endverbatim +The value of y is computed along with the value of z. + +\copydetails CppAD::local::forward_unary2_op_0 +*/ +template +void forward_sinh_op_0( + size_t i_z , + size_t i_x , + size_t cap_order , + Base* taylor ) +{ + // check assumptions + CPPAD_ASSERT_UNKNOWN( NumArg(SinhOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( NumRes(SinhOp) == 2 ); + CPPAD_ASSERT_UNKNOWN( 0 < cap_order ); + + // Taylor coefficients corresponding to argument and result + Base* x = taylor + i_x * cap_order; + Base* s = taylor + i_z * cap_order; // called z in documentation + Base* c = s - cap_order; // called y in documentation + + s[0] = sinh( x[0] ); + c[0] = cosh( x[0] ); +} +/*! +Compute reverse mode partial derivatives for result of op = SinhOp. + +The C++ source code corresponding to this operation is +\verbatim + z = sinh(x) +\endverbatim +The auxillary result is +\verbatim + y = cosh(x) +\endverbatim +The value of y is computed along with the value of z. + +\copydetails CppAD::local::reverse_unary2_op +*/ + +template +void reverse_sinh_op( + size_t d , + size_t i_z , + size_t i_x , + size_t cap_order , + const Base* taylor , + size_t nc_partial , + Base* partial ) +{ + // check assumptions + CPPAD_ASSERT_UNKNOWN( NumArg(SinhOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( NumRes(SinhOp) == 2 ); + CPPAD_ASSERT_UNKNOWN( d < cap_order ); + CPPAD_ASSERT_UNKNOWN( d < nc_partial ); + + // Taylor coefficients and partials corresponding to argument + const Base* x = taylor + i_x * cap_order; + Base* px = partial + i_x * nc_partial; + + // Taylor coefficients and partials corresponding to first result + const Base* s = taylor + i_z * cap_order; // called z in doc + Base* ps = partial + i_z * nc_partial; + + // Taylor coefficients and partials corresponding to auxillary result + const Base* c = s - cap_order; // called y in documentation + Base* pc = ps - nc_partial; + + + // rest of this routine is identical for the following cases: + // reverse_sin_op, reverse_cos_op, reverse_sinh_op, reverse_cosh_op. + size_t j = d; + size_t k; + while(j) + { + ps[j] /= Base(double(j)); + pc[j] /= Base(double(j)); + for(k = 1; k <= j; k++) + { + px[k] += Base(double(k)) * azmul(ps[j], c[j-k]); + px[k] += Base(double(k)) * azmul(pc[j], s[j-k]); + + ps[j-k] += Base(double(k)) * azmul(pc[j], x[k]); + pc[j-k] += Base(double(k)) * azmul(ps[j], x[k]); + + } + --j; + } + px[0] += azmul(ps[0], c[0]); + px[0] += azmul(pc[0], s[0]); +} + +} } // END_CPPAD_LOCAL_NAMESPACE +# endif diff --git a/build-config/cppad/include/cppad/local/sparse/binary_op.hpp b/build-config/cppad/include/cppad/local/sparse/binary_op.hpp new file mode 100644 index 00000000..77cceef1 --- /dev/null +++ b/build-config/cppad/include/cppad/local/sparse/binary_op.hpp @@ -0,0 +1,617 @@ +# ifndef CPPAD_LOCAL_SPARSE_BINARY_OP_HPP +# define CPPAD_LOCAL_SPARSE_BINARY_OP_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +// BEGIN_CPPAD_LOCAL_SPARSE_NAMESPACE +namespace CppAD { namespace local { namespace sparse { +// END_DECLARE_NAMESPACE + +/*! +\file sparse_binary_op.hpp +Forward and reverse mode sparsity patterns for binary operators. +*/ + + +/*! +Forward mode Jacobian sparsity pattern for all binary operators. + +The C++ source code corresponding to a binary operation has the form +\verbatim + z = fun(x, y) +\endverbatim +where fun is a C++ binary function and both x and y are variables, +or it has the form +\verbatim + z = x op y +\endverbatim +where op is a C++ binary unary operator and both x and y are variables. + +\tparam Vector_set +is the type used for vectors of sets. It can be either +sparse::pack_setvec or sparse::list_setvec. + +\param i_z +variable index corresponding to the result for this operation; +i.e., z. + +\param arg + arg[0] +variable index corresponding to the left operand for this operator; +i.e., x. +\n +\n arg[1] +variable index corresponding to the right operand for this operator; +i.e., y. + +\param sparsity +\b Input: +The set with index arg[0] in sparsity +is the sparsity bit pattern for x. +This identifies which of the independent variables the variable x +depends on. +\n +\n +\b Input: +The set with index arg[1] in sparsity +is the sparsity bit pattern for y. +This identifies which of the independent variables the variable y +depends on. +\n +\n +\b Output: +The set with index i_z in sparsity +is the sparsity bit pattern for z. +This identifies which of the independent variables the variable z +depends on. + +\par Checked Assertions: +\li arg[0] < i_z +\li arg[1] < i_z +*/ + +template +void for_jac_binary_op( + size_t i_z , + const addr_t* arg , + Vector_set& sparsity ) +{ + // check assumptions + CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) < i_z ); + CPPAD_ASSERT_UNKNOWN( size_t(arg[1]) < i_z ); + + sparsity.binary_union(i_z, size_t(arg[0]), size_t(arg[1]), sparsity); + + return; +} + +/*! +Reverse mode Jacobian sparsity pattern for all binary operators. + +The C++ source code corresponding to a unary operation has the form +\verbatim + z = fun(x, y) +\endverbatim +where fun is a C++ unary function and x and y are variables, +or it has the form +\verbatim + z = x op y +\endverbatim +where op is a C++ bianry operator and x and y are variables. + +This routine is given the sparsity patterns +for a function G(z, y, x, ... ) +and it uses them to compute the sparsity patterns for +\verbatim + H( y, x, w , u , ... ) = G[ z(x,y) , y , x , w , u , ... ] +\endverbatim + +\tparam Vector_set +is the type used for vectors of sets. It can be either +sparse::pack_setvec or sparse::list_setvec. + +\param i_z +variable index corresponding to the result for this operation; +i.e., z. + +\param arg + arg[0] +variable index corresponding to the left operand for this operator; +i.e., x. + +\n +\n arg[1] +variable index corresponding to the right operand for this operator; +i.e., y. + +\param sparsity +The set with index i_z in sparsity +is the sparsity pattern for z corresponding ot the function G. +\n +\n +The set with index arg[0] in sparsity +is the sparsity pattern for x. +On input, it corresponds to the function G, +and on output it corresponds to H. +\n +\n +The set with index arg[1] in sparsity +is the sparsity pattern for y. +On input, it corresponds to the function G, +and on output it corresponds to H. +\n +\n + +\par Checked Assertions: +\li arg[0] < i_z +\li arg[1] < i_z +*/ +template +void rev_jac_binary_op( + size_t i_z , + const addr_t* arg , + Vector_set& sparsity ) +{ + // check assumptions + CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) < i_z ); + CPPAD_ASSERT_UNKNOWN( size_t(arg[1]) < i_z ); + + sparsity.binary_union( size_t(arg[0]), size_t(arg[0]), i_z, sparsity); + sparsity.binary_union( size_t(arg[1]), size_t(arg[1]), i_z, sparsity); + + return; +} +// --------------------------------------------------------------------------- +/*! +Reverse mode Hessian sparsity pattern for add and subtract operators. + +The C++ source code corresponding to a unary operation has the form +\verbatim + z = x op y +\endverbatim +where op is + or - and x, y are variables. + +\copydetails CppAD::local::reverse_sparse_hessian_binary_op +*/ +template +void rev_hes_addsub_op( + size_t i_z , + const addr_t* arg , + bool* jac_reverse , + const Vector_set& for_jac_sparsity , + Vector_set& rev_hes_sparsity ) +{ + // check assumptions + CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) < i_z ); + CPPAD_ASSERT_UNKNOWN( size_t(arg[1]) < i_z ); + + // check for no effect + if( ! jac_reverse[i_z] ) + return; + + // propagate hessian sparsity from i_z to arg[0] and arg[1] + rev_hes_sparsity.binary_union( + size_t(arg[0]), size_t(arg[0]), i_z, rev_hes_sparsity + ); + rev_hes_sparsity.binary_union( + size_t(arg[1]), size_t(arg[1]), i_z, rev_hes_sparsity + ); + + jac_reverse[arg[0]] = true; + jac_reverse[arg[1]] = true; + + return; +} + +/*! +Reverse mode Hessian sparsity pattern for multiplication operator. + +The C++ source code corresponding to a unary operation has the form +\verbatim + z = x * y +\endverbatim +where x and y are variables. + +\copydetails CppAD::local::reverse_sparse_hessian_binary_op +*/ +template +void rev_hes_mul_op( + size_t i_z , + const addr_t* arg , + bool* jac_reverse , + const Vector_set& for_jac_sparsity , + Vector_set& rev_hes_sparsity ) +{ + // check assumptions + CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) < i_z ); + CPPAD_ASSERT_UNKNOWN( size_t(arg[1]) < i_z ); + + // check for no effect + if( ! jac_reverse[i_z] ) + return; + + // progagate hessian sparsity from i_z to arg[0] and arg[1] + rev_hes_sparsity.binary_union( + size_t(arg[0]), size_t(arg[0]), i_z, rev_hes_sparsity + ); + rev_hes_sparsity.binary_union( + size_t(arg[1]), size_t(arg[1]), i_z, rev_hes_sparsity + ); + + // new hessian sparsity terms between i_z and arg[0], arg[1] + rev_hes_sparsity.binary_union( + size_t(arg[0]), size_t(arg[0]), size_t(arg[1]), for_jac_sparsity + ); + rev_hes_sparsity.binary_union( + size_t(arg[1]), size_t(arg[1]), size_t(arg[0]), for_jac_sparsity + ); + + jac_reverse[arg[0]] = true; + jac_reverse[arg[1]] = true; + return; +} + +/*! +Reverse mode Hessian sparsity pattern for division operator. + +The C++ source code corresponding to a unary operation has the form +\verbatim + z = x / y +\endverbatim +where x and y are variables. + +\copydetails CppAD::local::reverse_sparse_hessian_binary_op +*/ +template +void rev_hes_div_op( + size_t i_z , + const addr_t* arg , + bool* jac_reverse , + const Vector_set& for_jac_sparsity , + Vector_set& rev_hes_sparsity ) +{ + // check assumptions + CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) < i_z ); + CPPAD_ASSERT_UNKNOWN( size_t(arg[1]) < i_z ); + + // check for no effect + if( ! jac_reverse[i_z] ) + return; + + // propagate hessian sparsity from i_z to arg[0] and arg[1] + rev_hes_sparsity.binary_union( + size_t(arg[0]), size_t(arg[0]), i_z, rev_hes_sparsity + ); + rev_hes_sparsity.binary_union( + size_t(arg[1]), size_t(arg[1]), i_z, rev_hes_sparsity + ); + + // new hessian sparsity terms between i_z and arg[0], arg[1] + rev_hes_sparsity.binary_union( + size_t(arg[0]), size_t(arg[0]), size_t(arg[1]), for_jac_sparsity + ); + rev_hes_sparsity.binary_union( + size_t(arg[1]), size_t(arg[1]), size_t(arg[0]), for_jac_sparsity + ); + rev_hes_sparsity.binary_union( + size_t(arg[1]), size_t(arg[1]), size_t(arg[1]), for_jac_sparsity + ); + + jac_reverse[arg[0]] = true; + jac_reverse[arg[1]] = true; + return; +} + +/*! +Reverse mode Hessian sparsity pattern for power function. + +The C++ source code corresponding to a unary operation has the form +\verbatim + z = pow(x, y) +\endverbatim +where x and y are variables. + +\copydetails CppAD::local::reverse_sparse_hessian_binary_op +*/ +template +void rev_hes_pow_op( + size_t i_z , + const addr_t* arg , + bool* jac_reverse , + const Vector_set& for_jac_sparsity , + Vector_set& rev_hes_sparsity ) +{ + // check assumptions + CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) < i_z ); + CPPAD_ASSERT_UNKNOWN( size_t(arg[1]) < i_z ); + + // check for no effect + if( ! jac_reverse[i_z] ) + return; + + // propigate hessian sparsity from i_z to arg[0] and arg[1] + rev_hes_sparsity.binary_union( + size_t(arg[0]), size_t(arg[0]), i_z, rev_hes_sparsity + ); + rev_hes_sparsity.binary_union( + size_t(arg[1]), size_t(arg[1]), i_z, rev_hes_sparsity + ); + + // new hessian sparsity terms between i_z and arg[0], arg[1] + rev_hes_sparsity.binary_union( + size_t(arg[0]), size_t(arg[0]), size_t(arg[0]), for_jac_sparsity + ); + rev_hes_sparsity.binary_union( + size_t(arg[0]), size_t(arg[0]), size_t(arg[1]), for_jac_sparsity + ); + rev_hes_sparsity.binary_union( + size_t(arg[1]), size_t(arg[1]), size_t(arg[0]), for_jac_sparsity + ); + rev_hes_sparsity.binary_union( + size_t(arg[1]), size_t(arg[1]), size_t(arg[1]), for_jac_sparsity + ); + + // I cannot think of a case where this is necessary, but it including + // it makes it like the other cases. + jac_reverse[arg[0]] = true; + jac_reverse[arg[1]] = true; + return; +} +// --------------------------------------------------------------------------- +/* +$begin sparse_for_hes_nl_binary_op$$ +$spell + hes + div + op + np + numvar + Jacobian + arg + mul + Namespace +$$ + +$section Forward Hessian Sparsity for Nonlinear Binary Operators$$ + +$head Namespace$$ +$srcthisfile% + 0%// BEGIN_CPPAD_LOCAL_SPARSE_NAMESPACE%// END_DECLARE_NAMESPACE%0 +%$$ + +$head for_hes_mul_op$$ + +$subhead Syntax$$ +$codei%for_hes_mul_op(%i_v%, %np1%, %numvar%, %for_sparsity%)%$$ + +$subhead Prototype$$ +$srcthisfile% + 0%// BEGIN_for_hes_mul_op%// END_for_hes_mul_op%1 +%$$ + +$head for_hes_div_op$$ + +$subhead Syntax$$ +$codei%for_hes_div_op(%i_v%, %np1%, %numvar%, %for_sparsity%)%$$ + +$subhead Prototype$$ +$srcthisfile% + 0%// BEGIN_for_hes_div_op%// END_for_hes_div_op%1 +%$$ + +$head for_hes_pow_op$$ + +$subhead Syntax$$ +$codei%for_hes_pow_op(%i_v%, %np1%, %numvar%, %for_sparsity%)%$$ + +$subhead Prototype$$ +$srcthisfile% + 0%// BEGIN_for_hes_pow_op%// END_for_hes_pow_op%1 +%$$ + +$head C++ Source$$ +The C++ source code corresponding to this operation is +$codei% + %w% = %v0% * %v1% + %w% = %v0% / %v1% + %w% = pow(%v0% , %v1%) +%$$ + +$head np1$$ +This is the number of independent variables plus one; +i.e. size of $icode x$$ plus one. + +$head numvar$$ +This is the total number of variables in the tape. + +$head i_w$$ +is the index of the variable corresponding to the result $icode w$$. + +$head arg$$ +is the index of the argument vector for the nonlinear binary operation; i.e., +$icode%arg%[0]%$$, $icode%arg%[1]%$$ are the left and right operands; i.e., +corresponding to $icode v0$$, $icode v1$$. + +$head for_sparsity$$ +We have the conditions $icode%np1% = %for_sparsity%.end()%$$ +and $icode%for_sparsity%.n_set() = %np1% + %numvar%$$. + +$subhead Input Jacobian Sparsity$$ +For $icode%i%= 0, ..., %i_w%-1%$$, +the $icode%np1%+%i%$$ row of $icode for_sparsity$$ is the Jacobian sparsity +for the $th i$$ variable. These values do not change. +Note that $icode%i%=0%$$ corresponds to a parameter and +the corresponding Jacobian sparsity is empty. + +$subhead Input Hessian Sparsity$$ +For $icode%j%=1, ..., %n%$$, +the $th j$$ row of $icode for_sparsity$$ is the Hessian sparsity +before including the function $latex w(x)$$. + +$subhead Output Jacobian Sparsity$$ +the $icode i_w$$ row of $icode for_sparsity$$ is the Jacobian sparsity +for the variable $icode w$$. + +$subhead Output Hessian Sparsity$$ +For $icode%j%=1, ..., %n%$$, +the $th j$$ row of $icode for_sparsity$$ is the Hessian sparsity +after including the function $latex w(x)$$. + +$end +*/ +// BEGIN_for_hes_mul_op +template +void for_hes_mul_op( + size_t np1 , + size_t numvar , + size_t i_w , + const addr_t* arg , + Vector_set& for_sparsity ) +// END_for_hes_mul_op +{ // + CPPAD_ASSERT_UNKNOWN( for_sparsity.end() == np1 ); + CPPAD_ASSERT_UNKNOWN( for_sparsity.n_set() == np1 + numvar ); + // + size_t i_v0 = size_t(arg[0]); + size_t i_v1 = size_t(arg[1]); + CPPAD_ASSERT_UNKNOWN( i_v0 < i_w ); + CPPAD_ASSERT_UNKNOWN( i_v1 < i_w ); + CPPAD_ASSERT_UNKNOWN( i_w < numvar ); + + // set Jacobian sparsity J(i_w) + for_sparsity.binary_union(np1 + i_w, np1 + i_v0, np1 + i_v1, for_sparsity); + + // -------------------------------------------------- + // set of independent variables that v0 depends on + typename Vector_set::const_iterator itr_0(for_sparsity, i_v0 + np1); + + // loop over independent variables non-zero partial for v0 + size_t i_x = *itr_0; + while( i_x < np1 ) + { // N(i_x) = N(i_x) union J(v1) + for_sparsity.binary_union(i_x, i_x, i_v1 + np1, for_sparsity); + i_x = *(++itr_0); + } + // -------------------------------------------------- + // set of independent variables that v1 depends on + typename Vector_set::const_iterator itr_1(for_sparsity, i_v1 + np1); + + // loop over independent variables with non-zero partial for v1 + i_x = *itr_1; + while( i_x < np1 ) + { // N(i_x) = N(i_x) union J(v0) + for_sparsity.binary_union(i_x, i_x, i_v0 + np1, for_sparsity); + i_x = *(++itr_1); + } + return; +} +// BEGIN_for_hes_div_op +template +void for_hes_div_op( + size_t np1 , + size_t numvar , + size_t i_w , + const addr_t* arg , + Vector_set& for_sparsity ) +// END_for_hes_div_op +{ // + CPPAD_ASSERT_UNKNOWN( for_sparsity.end() == np1 ); + CPPAD_ASSERT_UNKNOWN( for_sparsity.n_set() == np1 + numvar ); + // + size_t i_v0 = size_t(arg[0]); + size_t i_v1 = size_t(arg[1]); + CPPAD_ASSERT_UNKNOWN( i_v0 < i_w ); + CPPAD_ASSERT_UNKNOWN( i_v1 < i_w ); + CPPAD_ASSERT_UNKNOWN( i_w < numvar ); + + // set Jacobian sparsity J(i_w) + for_sparsity.binary_union(np1 + i_w, np1 + i_v0, np1 + i_v1, for_sparsity); + + // -------------------------------------------------- + // set of independent variables that v0 depends on + typename Vector_set::const_iterator itr_0(for_sparsity, i_v0 + np1); + + // loop over independent variables non-zero partial for v0 + size_t i_x = *itr_0; + while( i_x < np1 ) + { // N(i_x) = N(i_x) union J(v1) + for_sparsity.binary_union(i_x, i_x, i_v1 + np1, for_sparsity); + i_x = *(++itr_0); + } + // -------------------------------------------------- + // set of independent variables that v1 depends on + typename Vector_set::const_iterator itr_1(for_sparsity, i_v1 + np1); + + // loop over independent variables with non-zero partial for v1 + i_x = *itr_1; + while( i_x < np1 ) + { // N(i_x) = N(i_x) union J(v0) + for_sparsity.binary_union(i_x, i_x, i_v0 + np1, for_sparsity); + // N(i_x) = N(i_x) union J(v1) + for_sparsity.binary_union(i_x, i_x, i_v1 + np1, for_sparsity); + i_x = *(++itr_1); + } + return; +} +// BEGIN_for_hes_pow_op +template +void for_hes_pow_op( + size_t np1 , + size_t numvar , + size_t i_w , + const addr_t* arg , + Vector_set& for_sparsity ) +// END_for_hes_pow_op +{ // + CPPAD_ASSERT_UNKNOWN( for_sparsity.end() == np1 ); + CPPAD_ASSERT_UNKNOWN( for_sparsity.n_set() == np1 + numvar ); + // + size_t i_v0 = size_t(arg[0]); + size_t i_v1 = size_t(arg[1]); + CPPAD_ASSERT_UNKNOWN( i_v0 < i_w ); + CPPAD_ASSERT_UNKNOWN( i_v1 < i_w ); + CPPAD_ASSERT_UNKNOWN( i_w < numvar ); + + // set Jacobian sparsity J(i_w) + for_sparsity.binary_union(np1 + i_w, np1 + i_v0, np1 + i_v1, for_sparsity); + + // -------------------------------------------------- + // set of independent variables that v0 depends on + typename Vector_set::const_iterator itr_0(for_sparsity, i_v0 + np1); + + // loop over independent variables non-zero partial for v0 + size_t i_x = *itr_0; + while( i_x < np1 ) + { // N(i_x) = N(i_x) union J(v0) + for_sparsity.binary_union(i_x, i_x, i_v0 + np1, for_sparsity); + // N(i_x) = N(i_x) union J(v1) + for_sparsity.binary_union(i_x, i_x, i_v1 + np1, for_sparsity); + i_x = *(++itr_0); + } + // -------------------------------------------------- + // set of independent variables that v1 depends on + typename Vector_set::const_iterator itr_1(for_sparsity, i_v1 + np1); + + // loop over independent variables with non-zero partial for v1 + i_x = *itr_1; + while( i_x < np1 ) + { // N(i_x) = N(i_x) union J(v0) + for_sparsity.binary_union(i_x, i_x, i_v0 + np1, for_sparsity); + // N(i_x) = N(i_x) union J(v1) + for_sparsity.binary_union(i_x, i_x, i_v1 + np1, for_sparsity); + i_x = *(++itr_1); + } + return; +} +// --------------------------------------------------------------------------- +} } } // END_CPPAD_LOCAL_SPARSE_NAMESPACE +# endif diff --git a/build-config/cppad/include/cppad/local/sparse/dev_sparse.omh b/build-config/cppad/include/cppad/local/sparse/dev_sparse.omh new file mode 100644 index 00000000..f2a26c1f --- /dev/null +++ b/build-config/cppad/include/cppad/local/sparse/dev_sparse.omh @@ -0,0 +1,23 @@ +----------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 Bradley M. Bell + + CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + + This Source Code may also be made available under the following + Secondary License when the conditions for such availability set forth + in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +----------------------------------------------------------------------------- +$begin dev_sparse$$ + +$section Developer Sparse Documentation$$ + +$childtable% + include/cppad/local/sparse/unary_op.hpp% + include/cppad/local/sparse/binary_op.hpp% + include/cppad/local/sparse/setvector.omh +%$$ + + +$end diff --git a/build-config/cppad/include/cppad/local/sparse/internal.hpp b/build-config/cppad/include/cppad/local/sparse/internal.hpp new file mode 100644 index 00000000..e76c919a --- /dev/null +++ b/build-config/cppad/include/cppad/local/sparse/internal.hpp @@ -0,0 +1,455 @@ +# ifndef CPPAD_LOCAL_SPARSE_INTERNAL_HPP +# define CPPAD_LOCAL_SPARSE_INTERNAL_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +// necessary definitions +# include +# include +# include +# include + +// BEGIN_CPPAD_LOCAL_SPARSE_NAMESPACE +namespace CppAD { namespace local { namespace sparse { + +/*! +\file sparse_internal.hpp +Routines that enable code to be independent of which internal spasity pattern +is used. +*/ +// --------------------------------------------------------------------------- +/*! +Template structure used obtain the internal sparsity pattern type +form the corresponding element type. +The general form is not valid, must use a specialization. + +\tparam Element_type +type of an element in the sparsity structrue. + +\par internal_pattern::pattern_type +is the type of the corresponding internal sparsity pattern. +*/ +template struct internal_pattern; +/// Specilization for bool elements. +template <> +struct internal_pattern +{ + typedef sparse::pack_setvec pattern_type; +}; +/// Specilization for std::set elements. +template <> +struct internal_pattern< std::set > +{ + typedef list_setvec pattern_type; +}; +// --------------------------------------------------------------------------- +/*! +Update the internal sparsity pattern for a sub-set of rows + +\tparam SizeVector +The type used for index sparsity patterns. This is a simple vector +with elements of type size_t. + +\tparam InternalSparsitiy +The type used for intenal sparsity patterns. This can be either +sparse::pack_setvec or list_setvec. + +\param zero_empty +If this is true, the internal sparstity pattern corresponds to row zero +must be empty on input and will be emtpy output; i.e., any corresponding +values in pattern_in will be ignored. + +\param input_empty +If this is true, the initial sparsity pattern for row +internal_index[i] is empty for all i. +In this case, one is setting the sparsity patterns; i.e., +the output pattern in row internal_index[i] is the corresponding +entries in pattern. + +\param transpose +If this is true, pattern_in is transposed. + +\param internal_index +This specifies the sub-set of rows in internal_pattern that we are updating. +If traspose is false (true), +this is the mapping from row (column) index in pattern_in to the corresponding +row index in the internal_pattern. + +\param internal_pattern +On input, the number of sets internal_pattern.n_set(), +and possible elements internal_pattern.end(), have been set. +If input_empty is true, and all of the sets +in internal_index are empty on input. +On output, the entries in pattern_in are added to internal_pattern. +To be specific, suppose transpose is false, and (i, j) is a possibly +non-zero entry in pattern_in, the entry (internal_index[i], j) is added +to internal_pattern. +On the other hand, if transpose is true, +the entry (internal_index[j], i) is added to internal_pattern. + +\param pattern_in +This is the sparsity pattern for variables, +or its transpose, depending on the value of transpose. +*/ +template +void set_internal_pattern( + bool zero_empty , + bool input_empty , + bool transpose , + const pod_vector& internal_index , + InternalSparsity& internal_pattern , + const sparse_rc& pattern_in ) +{ + size_t nr = internal_index.size(); +# ifndef NDEBUG + size_t nc = internal_pattern.end(); + if( transpose ) + { CPPAD_ASSERT_UNKNOWN( pattern_in.nr() == nc ); + CPPAD_ASSERT_UNKNOWN( pattern_in.nc() == nr ); + } + else + { CPPAD_ASSERT_UNKNOWN( pattern_in.nr() == nr ); + CPPAD_ASSERT_UNKNOWN( pattern_in.nc() == nc ); + } + if( input_empty ) for(size_t i = 0; i < nr; i++) + { size_t i_var = internal_index[i]; + CPPAD_ASSERT_UNKNOWN( internal_pattern.number_elements(i_var) == 0 ); + } +# endif + const SizeVector& row( pattern_in.row() ); + const SizeVector& col( pattern_in.col() ); + size_t nnz = row.size(); + for(size_t k = 0; k < nnz; k++) + { size_t r = row[k]; + size_t c = col[k]; + if( transpose ) + std::swap(r, c); + // + size_t i_var = internal_index[r]; + CPPAD_ASSERT_UNKNOWN( i_var < internal_pattern.n_set() ); + CPPAD_ASSERT_UNKNOWN( c < nc ); + bool ignore = zero_empty && i_var == 0; + if( ! ignore ) + internal_pattern.post_element( internal_index[r], c ); + } + // process posts + for(size_t i = 0; i < nr; ++i) + internal_pattern.process_post( internal_index[i] ); +} +template +void set_internal_pattern( + bool zero_empty , + bool input_empty , + bool transpose , + const pod_vector& internal_index , + InternalSparsity& internal_pattern , + const vectorBool& pattern_in ) +{ size_t nr = internal_index.size(); + size_t nc = internal_pattern.end(); +# ifndef NDEBUG + CPPAD_ASSERT_UNKNOWN( pattern_in.size() == nr * nc ); + if( input_empty ) for(size_t i = 0; i < nr; i++) + { size_t i_var = internal_index[i]; + CPPAD_ASSERT_UNKNOWN( internal_pattern.number_elements(i_var) == 0 ); + } +# endif + for(size_t i = 0; i < nr; i++) + { for(size_t j = 0; j < nc; j++) + { bool flag = pattern_in[i * nc + j]; + if( transpose ) + flag = pattern_in[j * nr + i]; + if( flag ) + { size_t i_var = internal_index[i]; + CPPAD_ASSERT_UNKNOWN( i_var < internal_pattern.n_set() ); + CPPAD_ASSERT_UNKNOWN( j < nc ); + bool ignore = zero_empty && i_var == 0; + if( ! ignore ) + internal_pattern.post_element( i_var, j); + } + } + } + // process posts + for(size_t i = 0; i < nr; ++i) + internal_pattern.process_post( internal_index[i] ); + return; +} +template +void set_internal_pattern( + bool zero_empty , + bool input_empty , + bool transpose , + const pod_vector& internal_index , + InternalSparsity& internal_pattern , + const vector& pattern_in ) +{ size_t nr = internal_index.size(); + size_t nc = internal_pattern.end(); +# ifndef NDEBUG + CPPAD_ASSERT_UNKNOWN( pattern_in.size() == nr * nc ); + if( input_empty ) for(size_t i = 0; i < nr; i++) + { size_t i_var = internal_index[i]; + CPPAD_ASSERT_UNKNOWN( internal_pattern.number_elements(i_var) == 0 ); + } +# endif + for(size_t i = 0; i < nr; i++) + { for(size_t j = 0; j < nc; j++) + { bool flag = pattern_in[i * nc + j]; + if( transpose ) + flag = pattern_in[j * nr + i]; + if( flag ) + { size_t i_var = internal_index[i]; + CPPAD_ASSERT_UNKNOWN( i_var < internal_pattern.n_set() ); + CPPAD_ASSERT_UNKNOWN( j < nc ); + bool ignore = zero_empty && i_var == 0; + if( ! ignore ) + internal_pattern.post_element( i_var, j); + } + } + } + // process posts + for(size_t i = 0; i < nr; ++i) + internal_pattern.process_post( internal_index[i] ); + return; +} +template +void set_internal_pattern( + bool zero_empty , + bool input_empty , + bool transpose , + const pod_vector& internal_index , + InternalSparsity& internal_pattern , + const vector< std::set >& pattern_in ) +{ size_t nr = internal_index.size(); + size_t nc = internal_pattern.end(); +# ifndef NDEBUG + if( input_empty ) for(size_t i = 0; i < nr; i++) + { size_t i_var = internal_index[i]; + CPPAD_ASSERT_UNKNOWN( internal_pattern.number_elements(i_var) == 0 ); + } +# endif + if( transpose ) + { CPPAD_ASSERT_UNKNOWN( pattern_in.size() == nc ); + for(size_t j = 0; j < nc; j++) + { std::set::const_iterator itr( pattern_in[j].begin() ); + while( itr != pattern_in[j].end() ) + { size_t i = *itr; + size_t i_var = internal_index[i]; + CPPAD_ASSERT_UNKNOWN( i_var < internal_pattern.n_set() ); + CPPAD_ASSERT_UNKNOWN( j < nc ); + bool ignore = zero_empty && i_var == 0; + if( ! ignore ) + internal_pattern.post_element( i_var, j); + ++itr; + } + } + } + else + { CPPAD_ASSERT_UNKNOWN( pattern_in.size() == nr ); + for(size_t i = 0; i < nr; i++) + { std::set::const_iterator itr( pattern_in[i].begin() ); + while( itr != pattern_in[i].end() ) + { size_t j = *itr; + size_t i_var = internal_index[i]; + CPPAD_ASSERT_UNKNOWN( i_var < internal_pattern.n_set() ); + CPPAD_ASSERT_UNKNOWN( j < nc ); + bool ignore = zero_empty && i_var == 0; + if( ! ignore ) + internal_pattern.post_element( i_var, j); + ++itr; + } + } + } + // process posts + for(size_t i = 0; i < nr; ++i) + internal_pattern.process_post( internal_index[i] ); + return; +} +// --------------------------------------------------------------------------- +/*! +Get sparsity pattern for a sub-set of variables + +\tparam SizeVector +The type used for index sparsity patterns. This is a simple vector +with elements of type size_t. + +\tparam InternalSparsitiy +The type used for intenal sparsity patterns. This can be either +sparse::pack_setvec or list_setvec. + +\param transpose +If this is true, pattern_out is transposed. + +\param internal_index +If transpose is false (true) +this is the mapping from row (column) an index in pattern_out +to the corresponding row index in internal_pattern. + +\param internal_pattern +This is the internal sparsity pattern. + +\param pattern_out +The input value of pattern_out does not matter. +Upon return it is an index sparsity pattern for each of the variables +in internal_index, or its transpose, depending on the value of transpose. +*/ +template +void get_internal_pattern( + bool transpose , + const pod_vector& internal_index , + const InternalSparsity& internal_pattern , + sparse_rc& pattern_out ) +{ typedef typename InternalSparsity::const_iterator iterator; + // number variables + size_t nr = internal_index.size(); + // column size of interanl sparstiy pattern + size_t nc = internal_pattern.end(); + // determine nnz, the number of possibly non-zero index pairs + size_t nnz = 0; + for(size_t i = 0; i < nr; i++) + { CPPAD_ASSERT_UNKNOWN( internal_index[i] < internal_pattern.n_set() ); + iterator itr(internal_pattern, internal_index[i]); + size_t j = *itr; + while( j < nc ) + { ++nnz; + j = *(++itr); + } + } + // transposed + if( transpose ) + { pattern_out.resize(nc, nr, nnz); + // + size_t k = 0; + for(size_t i = 0; i < nr; i++) + { iterator itr(internal_pattern, internal_index[i]); + size_t j = *itr; + while( j < nc ) + { pattern_out.set(k++, j, i); + j = *(++itr); + } + } + return; + } + // not transposed + pattern_out.resize(nr, nc, nnz); + // + size_t k = 0; + for(size_t i = 0; i < nr; i++) + { iterator itr(internal_pattern, internal_index[i]); + size_t j = *itr; + while( j < nc ) + { pattern_out.set(k++, i, j); + j = *(++itr); + } + } + return; +} +template +void get_internal_pattern( + bool transpose , + const pod_vector& internal_index , + const InternalSparsity& internal_pattern , + vectorBool& pattern_out ) +{ typedef typename InternalSparsity::const_iterator iterator; + // number variables + size_t nr = internal_index.size(); + // + // column size of interanl sparstiy pattern + size_t nc = internal_pattern.end(); + // + pattern_out.resize(nr * nc); + for(size_t ij = 0; ij < nr * nc; ij++) + pattern_out[ij] = false; + // + for(size_t i = 0; i < nr; i++) + { CPPAD_ASSERT_UNKNOWN( internal_index[i] < internal_pattern.n_set() ); + iterator itr(internal_pattern, internal_index[i]); + size_t j = *itr; + while( j < nc ) + { if( transpose ) + pattern_out[j * nr + i] = true; + else + pattern_out[i * nc + j] = true; + j = *(++itr); + } + } + return; +} +template +void get_internal_pattern( + bool transpose , + const pod_vector& internal_index , + const InternalSparsity& internal_pattern , + vector& pattern_out ) +{ typedef typename InternalSparsity::const_iterator iterator; + // number variables + size_t nr = internal_index.size(); + // + // column size of interanl sparstiy pattern + size_t nc = internal_pattern.end(); + // + pattern_out.resize(nr * nc); + for(size_t ij = 0; ij < nr * nc; ij++) + pattern_out[ij] = false; + // + for(size_t i = 0; i < nr; i++) + { CPPAD_ASSERT_UNKNOWN( internal_index[i] < internal_pattern.n_set() ); + iterator itr(internal_pattern, internal_index[i]); + size_t j = *itr; + while( j < nc ) + { if( transpose ) + pattern_out[j * nr + i] = true; + else + pattern_out[i * nc + j] = true; + j = *(++itr); + } + } + return; +} +template +void get_internal_pattern( + bool transpose , + const pod_vector& internal_index , + const InternalSparsity& internal_pattern , + vector< std::set >& pattern_out ) +{ typedef typename InternalSparsity::const_iterator iterator; + // number variables + size_t nr = internal_index.size(); + // + // column size of interanl sparstiy pattern + size_t nc = internal_pattern.end(); + // + if( transpose ) + pattern_out.resize(nc); + else + pattern_out.resize(nr); + for(size_t k = 0; k < pattern_out.size(); k++) + pattern_out[k].clear(); + // + for(size_t i = 0; i < nr; i++) + { CPPAD_ASSERT_UNKNOWN( internal_index[i] < internal_pattern.n_set() ); + iterator itr(internal_pattern, internal_index[i]); + size_t j = *itr; + while( j < nc ) + { if( transpose ) + pattern_out[j].insert(i); + else + pattern_out[i].insert(j); + j = *(++itr); + } + } + return; +} + + + +} } } // END_CPPAD_LOCAL_SPARSE_NAMESPACE + +# endif diff --git a/build-config/cppad/include/cppad/local/sparse/list_setvec.hpp b/build-config/cppad/include/cppad/local/sparse/list_setvec.hpp new file mode 100644 index 00000000..4ea5241b --- /dev/null +++ b/build-config/cppad/include/cppad/local/sparse/list_setvec.hpp @@ -0,0 +1,1721 @@ +# ifndef CPPAD_LOCAL_SPARSE_LIST_SETVEC_HPP +# define CPPAD_LOCAL_SPARSE_LIST_SETVEC_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ +# include +# include + +// BEGIN_CPPAD_LOCAL_SPARSE_NAMESPACE +namespace CppAD { namespace local { namespace sparse { + +// forward declaration of iterator class +class list_setvec_const_iterator; + +// ========================================================================= +class list_setvec { // BEGIN_CLASS_LIST_SETVEC +// ========================================================================= + +/* +------------------------------------------------------------------------------- +$begin list_setvec_member_data$$ +$spell + setvec + struct +$$ + +$section class list_setvec: Private Member Data$$ + +$head pair_size_t$$ +This $code struct$$ is local to the $code list_setvec$$ class. +It is the type used for each entry in a singly linked list +and has the following fields: + +$subhead value$$ +The is the value of an entry in the list +(for sets, the first entry in the list is a reference count). + +$subhead next$$ +This is the index in $code data_$$ for the next entry in the list. +If there are no more entries in the list, this value is zero; i.e., +$code data_[0]$$ is used to represent the end of a list. + +$head end_$$ +The possible elements in each set are $code 0$$, $code 1$$, ..., +$code end_-1$$ + +$head number_not_used_$$ +Number of elements of the $code data_$$ vector that are not being used. + +$head data_not_used_$$ +Index in $code data_$$ for the start of the linked list of elements +that are not being used. + +$head data_$$ +The data for all the singly linked lists. +If $icode%n_set% > 0%$$, +$codei%data[0].value == end_%$$ and +$codei%data[0].next == 0%$$. + +$head start_$$ +The size of this vector is the number of set; i.e., +$cref/n_set/SetVector/Vector Operations/n_set/$$. +The starting index for $th i$$ set is $codei%start_[%i%]%$$. +If $codei%start_[%i%] == 0%$$, the i-th set has no elements. +Otherwise it is the index of the reference count for the list. + +$subhead Reference Count$$ +If $codei%start_[%i%] != 0%$$, $codei%data_[start_[%i%]].value%$$ +is the reference count for the $th i$$ list +(not the value of an element in the list). +The reference count must be greater than zero. + +$subhead First Element$$ +If $codei%start_[%i%] != 0%$$, +$codei% + %first_index% = data_[start_[%i%]].next +%$$ +is the index of the first element in the list. +This must be non-zero because the list is empty. + +$subhead Next Element$$ +Starting with $icode%index% = %first_index%$$, +while $icode%index% != 0%$$, +The value of the corresponding element in the list is +$codei%data_[%index%].value%$$ (which must be less than $code end_$$). +The $icode index$$ for the next element of the list is +$codei%data_[%index%].next%$$. + +$subhead Last Element$$ +An index $icode last$$ corresponds to the last element of a list if +$codei%data_[%last%].next == 0%$$. +(Note that $code data_[0].value == end_$$). + +$head post_$$ +The size of this vector is the number of set; i.e., +$cref/n_set/SetVector/Vector Operations/n_set/$$. +Starting with $icode%index% = post_[%i%]%$$, +while $icode%index% != 0%$$, +The value of the next element posted to the $th i$$ list is +$codei%data_[%index%].value%$$ (which must be less than $code end_$$). +The $icode index$$ for the next element posted to the $th i$$ list is +$codei%data_[%index%].next%$$. + +$head temporary_$$ +A temporary vector, used by member functions, that keeps its capacity +to avoid re-allocating memory. +If a member function calls another, +no conditions about $code temporary_$$ should be assumed during that call. + +$head Source Code$$ +$srccode%hpp% */ +private: + struct pair_size_t {size_t value; size_t next; }; + friend bool CppAD::local::is_pod(void); + // + size_t end_; + size_t number_not_used_; + size_t data_not_used_; + // + pod_vector data_; + pod_vector start_; + pod_vector post_; + pod_vector temporary_; +/* %$$ +$end +------------------------------------------------------------------------------ +$begin list_setvec_reference_count$$ +$spell + vec + setvec + const +$$ + +$section class list_setvec private: Number of References to a Set$$ + +$head Syntax$$ +$icode%count% = %vec%.reference_count(%i%)%$$ + +$head vec$$ +Is a $code list_setvec$$ object and can be $code const$$. + +$head i$$ +is the index of the set that we are retrieving the references for. + +$head count$$ +is the reference count. + +$head Prototype$$ +$srccode%hpp% */ +private: + size_t reference_count(size_t i) const +/* %$$ +$end +*/ + { // start data index + size_t start = start_[i]; + if( start == 0 ) + return 0; + // + // reference count + return data_[start].value; + } +/* +------------------------------------------------------------------------------ +$begin list_setvec_drop$$ +$spell + setvec + vec + decremented +$$ +$section class list_setvec private: Drop a Set No Longer Being Used$$ + +$head Syntax$$ +$icode%not_used% = %vec%.drop(%i%)%$$ + +$head i$$ +is the index of the set that is dropped. + +$head reference_count$$ +if the set is non-empty, the +$cref/reference count/list_setvec_member_data/start_/Reference Count/$$ +is decremented. + +$head start_$$ +The value $codei%start_[%i%]%$$ is set to zero; i.e., +the $th i$$ set is empty after the call. + +$head post_$$ +The value $codei%post_[%i%]%$$ is set to zero; i.e., +any postings to the list are also dropped. + +$head data_not_used_$$ +The elements of $code data_$$ were information for the $th i$$ set, +and are no longer being used, are added to the linked list starting at +$code data_not_used$$. +This includes both set elements and postings. + +$head not_used$$ +is the number of elements of $code data_$$ that were begin used for the +$th i$$ set and are no longer being used; i.e., the number of elements +moved to $code data_not_used$$. + +$head Prototype$$ +$srccode%hpp% */ +private: + size_t drop(size_t i) +/* %$$ +$end +*/ + { // inialize count of addition elements not being used. + size_t number_drop = 0; + + // the elements in the post list will no longer be used + size_t post = post_[i]; + if( post != 0 ) + { // drop this posting + post_[i] = 0; + // + // count elements in this posting + ++number_drop; + size_t previous = post; + size_t next = data_[previous].next; + while( next != 0 ) + { previous = next; + next = data_[previous].next; + ++number_drop; + } + // + // add the posting elements to data_not_used_ + data_[previous].next = data_not_used_; + data_not_used_ = post; + } + + // check for empty set + size_t start = start_[i]; + if( start == 0 ) + return number_drop; + + // decrement reference counter + CPPAD_ASSERT_UNKNOWN( data_[start].value > 0 ); + data_[start].value--; + + // set this set to empty + start_[i] = 0; + + // If new reference count is positive, the list corresponding to + // start is still being used. + if( data_[start].value > 0 ) + return number_drop; + + // + // count elements representing this set + ++number_drop; + size_t previous = start; + size_t next = data_[previous].next; + while( next != 0 ) + { previous = next; + next = data_[previous].next; + ++number_drop; + } + // + // add representing this set to data_not_used_ + data_[previous].next = data_not_used_; + data_not_used_ = start; + // + return number_drop; + } +/* +------------------------------------------------------------------------------ +$begin list_setvec_get_data_index$$ +$spell + decremented + setvec + vec +$$ + +$section class list_setvec private: Get a New List Pair$$ + +$head Syntax$$ +$icode%index% = %vec%.get_data_index()%$$ + +$head vec$$ +Is a $code list_setvec$$ object. + +$head data_not_used_$$ +If the input value of $code data_not_used_$$ is zero, +it is not changed. +Otherwise, the index for the element at the front of that list is returned. +In this case, +$code data_not_used$$ is advanced to the next element in that list. + +$head number_not_used_$$ +If the input value of $code data_not_used_$$ is zero, +$code number_not_used_$$ is not changed. +Otherwise it is decremented by one. + +$head index$$ +If the input value of $code data_not_used_$$ is zero, +the size of $code data_$$ is increased by one and index corresponding +to the end of $code data_$$ is returned. +Otherwise, the input value for $code data_not_used_$$ is returned. + +$head Prototype$$ +$srccode%hpp% */ +private: + size_t get_data_index(void) +/* %$$ +$end +*/ + { size_t index; + if( data_not_used_ > 0 ) + { CPPAD_ASSERT_UNKNOWN( number_not_used_ > 0 ); + --number_not_used_; + index = data_not_used_; + data_not_used_ = data_[index].next; + } + else + { index = data_.extend(1); + } + return index; + } +/* +------------------------------------------------------------------------------- +$begin list_setvec_check_data_structure$$ +$spell + setvec + vec + const +$$ + +$section class list_setvec private: Check Data Structure$$ + +$head Syntax$$ +$icode%vec%.check_data_structure()%$$ + +$head vec$$ +Is a $code list_setvec$$ object that is effectively const. +It is not declared const because the data structure is modified and +then restored. + +$head NDEBUG$$ +If $code NDEBUG$$ is defined, the routine does nothing. +Otherwise, if an error is found in the data structure, +a $code CPPAD_ASSERT_UNKNOWN$$ is generated. + +$head Prototype$$ +$srccode%hpp% */ +private: + void check_data_structure(void) +/* %$$ +$end +*/ +# ifdef NDEBUG + { return; } +# else + { // number of sets + CPPAD_ASSERT_UNKNOWN( post_.size() == start_.size() ); + size_t n_set = start_.size(); + if( n_set == 0 ) + { CPPAD_ASSERT_UNKNOWN( end_ == 0 ); + CPPAD_ASSERT_UNKNOWN( number_not_used_ == 0 ); + CPPAD_ASSERT_UNKNOWN( data_not_used_ == 0 ); + CPPAD_ASSERT_UNKNOWN( data_.size() == 0 ); + CPPAD_ASSERT_UNKNOWN( start_.size() == 0 ); + return; + } + // check data index zero + CPPAD_ASSERT_UNKNOWN( data_[0].value == end_ ); + CPPAD_ASSERT_UNKNOWN( data_[0].next == 0 ); + // ----------------------------------------------------------- + // save a copy of the reference counters in temporary_ + temporary_.resize(n_set); + for(size_t i = 0; i < n_set; i++) + temporary_[i] = reference_count(i); + // ----------------------------------------------------------- + // Initialize number of entries in data used by sets and posts. + // Start with 1 for data_[0]. + size_t number_used_by_sets = 1; + // ----------------------------------------------------------- + // count the number of entries in data_ that are used by sets + for(size_t i = 0; i < n_set; i++) + { size_t start = start_[i]; + if( start > 0 ) + { // check structure for this non-empty set + size_t reference_count = data_[start].value; + size_t next = data_[start].next; + CPPAD_ASSERT_UNKNOWN( reference_count > 0 ); + CPPAD_ASSERT_UNKNOWN( next != 0 ); + CPPAD_ASSERT_UNKNOWN( data_[next].value < end_ ); + // + // decrement the reference counter + data_[start].value--; + // + // count the entries when find last reference + if( data_[start].value == 0 ) + { + // restore reference count + data_[start].value = temporary_[i]; + + // number of data entries used for this set + number_used_by_sets += number_elements(i) + 1; + /* + number of elements checks that value < end_ + .resizeeach pair in the list except for the start pair + and the pair with index zero. + */ + } + } + } + // ------------------------------------------------------------------ + // count the number of entries in data_ that are used by posts + size_t number_used_by_posts = 0; + for(size_t i = 0; i < n_set; i++) + { size_t post = post_[i]; + if( post > 0 ) + { size_t value = data_[post].value; + size_t next = data_[post].next; + CPPAD_ASSERT_UNKNOWN( value < end_ ); + // + while( value < end_ ) + { ++number_used_by_posts; + value = data_[next].value; + next = data_[next].next; + } + } + } + // ------------------------------------------------------------------ + // count number of entries in data_not_used_ + size_t count = 0; + size_t next = data_not_used_; + while( next != 0 ) + { ++count; + next = data_[next].next; + } + CPPAD_ASSERT_UNKNOWN( number_not_used_ == count ); + // ------------------------------------------------------------------ + size_t number_used = number_used_by_sets + number_used_by_posts; + CPPAD_ASSERT_UNKNOWN( + number_used + number_not_used_ == data_.size() + ); + return; + } +# endif +/* +------------------------------------------------------------------------------- +$begin list_setvec_vec_memory$$ +$spell + setvec +$$ + +$section class list_setvec: Approximate Memory Used by Vector$$ + +$head Public$$ +This function is declared public, but is not part of +$cref SetVector$$ concept. + +$head Implementation$$ +$srccode%hpp% */ +public: + size_t memory(void) const + { return data_.capacity() * sizeof(pair_size_t); } +/* %$$ +$end +------------------------------------------------------------------------------- +$begin list_setvec_vec_print$$ +$spell + setvec +$$ + +$section class list_setvec: Print a Vector of Sets$$ + + +$head Public$$ +This function is declared public, but is not part of +$cref SetVector$$ concept. + +$head Prototype$$ +$srccode%hpp% */ +public: + void print(void) const; +/* %$$ +$end +------------------------------------------------------------------------------- +$begin list_setvec_iterators$$ +$spell + setvec + Iterators + typedef + const_iterator +$$ + +$section class list_setvec: Iterators$$ + +$head SetVector Concept$$ +$cref/const_iterator/SetVector/const_iterator/$$ + +$head typedef$$ +$srccode%hpp% */ +public: + friend class list_setvec_const_iterator; + typedef list_setvec_const_iterator const_iterator; +/* %$$ +$end +------------------------------------------------------------------------------- +$begin list_setvec_default_ctor$$ +$spell + setvec +$$ + +$section class list_setvec: Default Constructor$$ + +$head SetVector Concept$$ +$cref/constructor/SetVector/Vector Operations/Constructor/$$ + +$head size_t Members$$ +All of the $code size_t$$ member variables are initialized as zero. + +$head pod_vector Members$$ +All of the $code pod_vector$$ member variables are initialized +using their default constructors. + +$head Implementation$$ +$srccode%hpp% */ +public: + list_setvec(void) + : end_(0), number_not_used_(0), data_not_used_(0) + { } +/* %$$ +$end +------------------------------------------------------------------------------- +$begin list_setvec_destructor$$ +$spell + setvec +$$ + +$section class list_setvec: Destructor$$ + +$head Implementation$$ +If $code NDEBUG$$ is not defined, +$cref/check data structure/list_setvec_check_data_structure/$$. +$srccode%hpp% */ +public: + ~list_setvec(void) + { check_data_structure(); } +/* %$$ +$end +------------------------------------------------------------------------------- +$begin list_setvec_copy_ctor$$ +$spell + setvec + CppAD +$$ + +$section class list_setvec: Copy Constructor$$ + +$head v$$ +The vector of sets that we are attempting to make a copy of. + +$head Implementation$$ +Using the copy constructor is probably due to a $code list_setvec$$ +being passed by value instead of by reference. +This is a CppAD programing error (not CppAD user error). +$srccode%hpp% */ +public: + list_setvec(const list_setvec& v) + { CPPAD_ASSERT_UNKNOWN(false); } +/* %$$ +$end +------------------------------------------------------------------------------- +$begin list_setvec_vec_resize$$ +$spell + setvec + resize +$$ + +$section class list_setvec: Vector resize$$ + +$head SetVector Concept$$ +$cref/vector resize/SetVector/Vector Operations/resize/$$ + +$head Prototype$$ +$srccode%hpp% */ +public: + void resize(size_t n_set, size_t end) +/* %$$ +$end +*/ + { check_data_structure(); + + if( n_set == 0 ) + { CPPAD_ASSERT_UNKNOWN( end == 0 ); + // + // restore object to start after constructor + // (no memory allocated for this object) + data_.clear(); + start_.clear(); + post_.clear(); + number_not_used_ = 0; + data_not_used_ = 0; + end_ = 0; + // + return; + } + end_ = end; + // + start_.resize(n_set); + post_.resize(n_set); + // + for(size_t i = 0; i < n_set; i++) + { start_[i] = 0; + post_[i] = 0; + } + // + // last element, marks the end for all lists + data_.resize(1); + data_[0].value = end_; + data_[0].next = 0; + // + number_not_used_ = 0; + data_not_used_ = 0; + } +/* %$$ +------------------------------------------------------------------------------- +$begin list_setvec_vec_n_set$$ +$spell + setvec +$$ + +$section class list_setvec: Number of Sets$$ + +$head SetVector Concept$$ +$cref/n_set/SetVector/Vector Operations/n_set/$$ + +$head Implementation$$ +$srccode%hpp% */ +public: + size_t n_set(void) const + { return start_.size(); } +/* %$$ +$end +------------------------------------------------------------------------------- +$begin list_setvec_vec_end$$ +$spell + setvec +$$ + +$section class list_setvec: End Value$$ + +$head SetVector Concept$$ +$cref/end/SetVector/Vector Operations/end/$$ + +$head Implementation$$ +$srccode%hpp% */ +public: + size_t end(void) const + { return end_; } +/* %$$ +$end +------------------------------------------------------------------------------- +$begin list_setvec_vec_assignment$$ +$spell + setvec +$$ + +$section class list_setvec: Vector Assignment$$ + +$head SetVector Concept$$ +$cref/vector assignment/SetVector/Vector Operations/Assignment/$$ + +$head Prototype$$ +$srccode%hpp% */ +public: + void operator=(const list_setvec& other) +/* %$$ +$end +*/ + { end_ = other.end_; + number_not_used_ = other.number_not_used_; + data_not_used_ = other.data_not_used_; + data_ = other.data_; + start_ = other.start_; + post_ = other.post_; + } +/* +------------------------------------------------------------------------------- +$begin list_setvec_vec_swap$$ +$spell + setvec +$$ + +$section class list_setvec: Vector Swap$$ + +$head SetVector Concept$$ +$cref/vector swap/SetVector/Vector Operations/swap/$$ + +$head Prototype$$ +$srccode%hpp% */ +public: + void swap(list_setvec& other) +/* %$$ +$end +*/ + { // size_t objects + std::swap(end_ , other.end_); + std::swap(number_not_used_ , other.number_not_used_); + std::swap(data_not_used_ , other.data_not_used_); + + // pod_vectors + data_.swap( other.data_); + start_.swap( other.start_); + post_.swap( other.post_); + temporary_.swap( other.temporary_); + } +/* +------------------------------------------------------------------------------- +$begin list_setvec_number_elements$$ +$spell + setvec +$$ + +$section class list_setvec: Number of Elements in a Set$$ + +$head SetVector Concept$$ +$cref/number_elements/SetVector/number_elements/$$ + +$head Prototype$$ +$srccode%hpp% */ +public: + size_t number_elements(size_t i) const +/* %$$ +$end +*/ + { CPPAD_ASSERT_UNKNOWN( post_[i] == 0 ); + + // check if the set is empty + size_t start = start_[i]; + if( start == 0 ) + return 0; + + // initialize counter + size_t count = 0; + + // advance to the first element in the set + size_t next = data_[start].next; + while( next != 0 ) + { CPPAD_ASSERT_UNKNOWN( data_[next].value < end_ ); + count++; + next = data_[next].next; + } + CPPAD_ASSERT_UNKNOWN( count > 0 ); + return count; + } +/* +------------------------------------------------------------------------------- +$begin list_setvec_add_element$$ +$spell + setvec +$$ + +$section class list_setvec: Add an Elements to a Set$$ + +$head SetVector Concept$$ +$cref/add_element/SetVector/add_element/$$ + +$head Prototype$$ +$srccode%hpp% */ +public: + void add_element(size_t i, size_t element) +/* %$$ +$end +*/ + { CPPAD_ASSERT_UNKNOWN( i < start_.size() ); + CPPAD_ASSERT_UNKNOWN( element < end_ ); + + // check for case where starting set is empty + size_t start = start_[i]; + if( start == 0 ) + { start = get_data_index(); + start_[i] = start; + data_[start].value = 1; // reference count + // + size_t next = get_data_index(); + data_[start].next = next; + // + data_[next].value = element; + data_[next].next = 0; + return; + } + // + // start of set with this index + size_t previous = start_[i]; + // + // first entry in this set + size_t next = data_[previous].next; + size_t value = data_[next].value; + // + // locate place to insert this element + while( value < element ) + { previous = next; + next = data_[next].next; + value = data_[next].value; + } + // + // check for case where element is in the set + if( value == element ) + return; + // + // + // check for case where this is the only reference to this set + CPPAD_ASSERT_UNKNOWN( element < value ); + if( data_[start].value == 1 ) + { size_t insert = get_data_index(); + data_[insert].next = next; + data_[insert].value = element; + data_[previous].next = insert; + // + return; + } + // + // must make a separate copy with new element inserted + CPPAD_ASSERT_UNKNOWN( data_[start].value > 1 ); + data_[start].value--; // reverence counter for old list + // + size_t start_new = get_data_index(); + data_[start_new].value = 1; // reference counter for new list + size_t previous_new = start_new; + // + // start of old set with this index + previous = start_[i]; + // + // first entry in old set + next = data_[previous].next; + value = data_[next].value; + // + // locate place to insert this element + while( value < element ) + { // copy to new list + size_t next_new = get_data_index(); + data_[previous_new].next = next_new; + data_[next_new].value = value; + previous_new = next_new; + // + // get next value + previous = next; + next = data_[next].next; + value = data_[next].value; + } + CPPAD_ASSERT_UNKNOWN( element < value ); + // + // insert the element + size_t next_new = get_data_index(); + data_[previous_new].next = next_new; + data_[next_new].value = element; + previous_new = next_new; + // + // copy rest of the old set + while( value < end_ ) + { // copy to new list + next_new = get_data_index(); + data_[previous_new].next = next_new; + data_[next_new].value = value; + previous_new = next_new; + // + // get next value + previous = next; + next = data_[next].next; + value = data_[next].value; + } + CPPAD_ASSERT_UNKNOWN( next == 0 ); + data_[previous_new].next = 0; + // + // hook up new list + start_[i] = start_new; + return; + } +/* +------------------------------------------------------------------------------- +$begin list_setvec_post_element$$ +$spell + setvec +$$ + +$section class list_setvec: Post an Elements for Addition to a Set$$ + +$head SetVector Concept$$ +$cref/post_element/SetVector/post_element/$$ + +$head post_$$ +The element is added at the front of the linked list +that starts at $code post_$$. + +$head Prototype$$ +$srccode%hpp% */ +public: + void post_element(size_t i, size_t element) +/* %$$ +$end +*/ + { CPPAD_ASSERT_UNKNOWN( i < start_.size() ); + CPPAD_ASSERT_UNKNOWN( element < end_ ); + + // put element at the front of this list + size_t next = post_[i]; + size_t post = get_data_index(); + post_[i] = post; + data_[post].value = element; + data_[post].next = next; + + return; + } +/* +------------------------------------------------------------------------------- +$begin list_setvec_process_post$$ +$spell + setvec +$$ + +$section class list_setvec: Add Posted Elements to a Set$$ + +$head SetVector Concept$$ +$cref/process_post/SetVector/process_post/$$ + +$head post_$$ +Upon call, $codei%post_[%i%]%$$ is the linked list of elements to +be added to the $th i$$ set. +Upon return, $codei%post_[%i%]%$$ is zero; i.e., the list is empty. + +$head Prototype$$ +$srccode%hpp% */ +public: + void process_post(size_t i) +/* %$$ +$end +*/ + { // post + size_t post = post_[i]; + // + // check if there are no elements to process + if( post == 0 ) + return; + // + // check if there is only one element to process + size_t next = data_[post].next; + if( next == 0 ) + { // done with this posting + size_t value = data_[post].value; + post_[i] = 0; + data_[post].next = data_not_used_; + data_not_used_ = post; + ++number_not_used_; + // + add_element(i, value); + // + return; + } + // + // copy posting to temporary_ + temporary_.resize(0); + size_t previous = post; + size_t value = data_[previous].value; + CPPAD_ASSERT_UNKNOWN( value < end_ ); + temporary_.push_back(value); + while( next != 0 ) + { previous = next; + value = data_[previous].value; + CPPAD_ASSERT_UNKNOWN( value < end_ ); + temporary_.push_back(value); + next = data_[previous].next; + } + size_t number_post = temporary_.size(); + // + // done with this posting + post_[i] = 0; + data_[previous].next = data_not_used_; + data_not_used_ = post; + number_not_used_ += number_post;; + // + // sort temporary_ + CPPAD_ASSERT_UNKNOWN( number_post > 1 ); + std::sort( temporary_.data(), temporary_.data() + number_post); + // posting is the set { temporary_[0], ... , [number_post-1] } + // ------------------------------------------------------------------- + // put union of posting and set i in + // temporary_[number_post], ... , temporary_[ temporary_.size()-1 ] + // + size_t i_next = start_[i]; + size_t i_value = end_; + if( i_next > 0 ) + { // skip reference count + i_next = data_[i_next].next; + i_value = data_[i_next].value; + } + bool post_is_subset = true; + size_t previous_post = end_; + for(size_t j =0; j < number_post; ++j) + { size_t post_value = temporary_[j]; + CPPAD_ASSERT_UNKNOWN( post_value < end_ ); + while( i_value < post_value ) + { // i_value is in union + temporary_.push_back(i_value); + i_next = data_[i_next].next; + i_value = data_[i_next].value; + } + if( i_value == post_value ) + { i_next = data_[i_next].next; + i_value = data_[i_next].value; + } + else + post_is_subset = false; + // + if( previous_post != post_value ) + { // post_value is in union + temporary_.push_back(post_value); + } + previous_post = post_value; + } + // check if posting is a subset of set i + if( post_is_subset ) + return; + // + // rest of elements in set i + while( i_value < end_ ) + { temporary_.push_back(i_value); + i_next = data_[i_next].next; + i_value = data_[i_next].value; + } + + // adjust number_not_used_ + size_t number_drop = drop(i); + number_not_used_ += number_drop; + + // put new set in linked list for set i + CPPAD_ASSERT_UNKNOWN( temporary_.size() >= number_post + 1 ); + size_t index = get_data_index(); + start_[i] = index; // start for the union + data_[index].value = 1; // reference count for the union + for(size_t j = number_post; j < temporary_.size(); ++j) + { next = get_data_index(); + data_[index].next = next; + data_[next].value = temporary_[j]; // next element in union + index = next; + } + data_[index].next = 0; // end of union + // + return; + } +/* +------------------------------------------------------------------------------- +$begin list_setvec_is_element$$ +$spell + setvec +$$ + +$section class list_setvec: Is an Element in a Set$$ + +$head SetVector Concept$$ +$cref/is_element/SetVector/is_element/$$ + +$head Prototype$$ +$srccode%hpp% */ +public: + bool is_element(size_t i, size_t element) const +/* %$$ +$end +*/ + { CPPAD_ASSERT_UNKNOWN( post_[i] == 0 ); + CPPAD_ASSERT_UNKNOWN( element < end_ ); + // + size_t start = start_[i]; + if( start == 0 ) + return false; + // + size_t next = data_[start].next; + size_t value = data_[next].value; + while( value < element ) + { next = data_[next].next; + value = data_[next].value; + } + return element == value; + } +/* +------------------------------------------------------------------------------- +$begin list_setvec_clear$$ +$spell + setvec +$$ + +$section class list_setvec: Assign a Set to be Empty$$ + +$head SetVector Concept$$ +$cref/clear/SetVector/clear/$$ + +$head Prototype$$ +$srccode%hpp% */ +public: + void clear(size_t target) +/* %$$ +$end +*/ + { CPPAD_ASSERT_UNKNOWN( target < start_.size() ); + + // adjust number_not_used_ + size_t number_drop = drop(target); + number_not_used_ += number_drop; + + return; + } +/* +------------------------------------------------------------------------------- +$begin list_setvec_assignment$$ +$spell + setvec +$$ + +$section class list_setvec: Assign a Set To Equal Another Set$$ + +$head SetVector Concept$$ +$cref/assignment/SetVector/assignment/$$ + +$head Prototype$$ +$srccode%hpp% */ +public: + void assignment( + size_t this_target , + size_t other_source , + const list_setvec& other ) +/* %$$ +$end +*/ + { CPPAD_ASSERT_UNKNOWN( other.post_[ other_source ] == 0 ); + // + CPPAD_ASSERT_UNKNOWN( this_target < start_.size() ); + CPPAD_ASSERT_UNKNOWN( other_source < other.start_.size() ); + CPPAD_ASSERT_UNKNOWN( end_ == other.end_ ); + + // check if we are assigning a set to itself + if( (this == &other) & (this_target == other_source) ) + return; + + // set depending on cases below + size_t this_start; + + // If this and other are the same, use another reference to same list + size_t other_start = other.start_[other_source]; + if( this == &other ) + { this_start = other_start; + if( other_start != 0 ) + { data_[other_start].value++; // increment reference count + CPPAD_ASSERT_UNKNOWN( data_[other_start].value > 1 ); + } + } + else if( other_start == 0 ) + { this_start = 0; + } + else + { // make a copy of the other list in this list_setvec + this_start = get_data_index(); + size_t this_next = get_data_index(); + data_[this_start].value = 1; // reference count + data_[this_start].next = this_next; + // + size_t next = other.data_[other_start].next; + CPPAD_ASSERT_UNKNOWN( next != 0 ); + while( next != 0 ) + { data_[this_next].value = other.data_[next].value; + next = other.data_[next].next; + if( next == 0 ) + data_[this_next].next = 0; + else + { size_t tmp = get_data_index(); + data_[this_next].next = tmp; + this_next = tmp; + } + } + } + + // adjust number_not_used_ + size_t number_drop = drop(this_target); + number_not_used_ += number_drop; + + // set the new start value for this_target + start_[this_target] = this_start; + + return; + } +/* +------------------------------------------------------------------------------- +$begin list_setvec_binary_union$$ +$spell + setvec +$$ + +$section class list_setvec: Assign a Set To Union of Two Sets$$ + +$head SetVector Concept$$ +$cref/binary_union/SetVector/binary_union/$$ + +$head Prototype$$ +$srccode%hpp% */ +public: + void binary_union( + size_t this_target , + size_t this_left , + size_t other_right , + const list_setvec& other ) +/* %$$ +$end +*/ + { CPPAD_ASSERT_UNKNOWN( post_[this_left] == 0 ); + CPPAD_ASSERT_UNKNOWN( other.post_[ other_right ] == 0 ); + // + CPPAD_ASSERT_UNKNOWN( this_target < start_.size() ); + CPPAD_ASSERT_UNKNOWN( this_left < start_.size() ); + CPPAD_ASSERT_UNKNOWN( other_right < other.start_.size() ); + CPPAD_ASSERT_UNKNOWN( end_ == other.end_ ); + + // start indices for left and right sets + size_t start_left = start_[this_left]; + size_t start_right = other.start_[other_right]; + + // if right is empty, the result is the left set + if( start_right == 0 ) + { assignment(this_target, this_left, *this); + return; + } + // if left is empty, the result is the right set + if( start_left == 0 ) + { assignment(this_target, other_right, other); + return; + } + // if niether case holds, then both left and right are non-empty + CPPAD_ASSERT_UNKNOWN( reference_count(this_left) > 0 ); + CPPAD_ASSERT_UNKNOWN( other.reference_count(other_right) > 0 ); + + // we will use temparary_ for temporary storage of the union + temporary_.resize(0); + + // for left next and value + size_t next_left = data_[start_left].next; + size_t value_left = data_[next_left].value; + + // right next and value + size_t next_right = other.data_[start_right].next; + size_t value_right = other.data_[next_right].value; + + // both left and right set are non-empty + CPPAD_ASSERT_UNKNOWN( value_left < end_ && value_right < end_ ); + + // flag that detects if left is or right is a subset of the other + bool left_is_subset = true; + bool right_is_subset = true; + + while( (value_left < end_) & (value_right < end_) ) + { if( value_left == value_right ) + { // value is in both sets + temporary_.push_back(value_left); + // + // advance left + next_left = data_[next_left].next; + value_left = data_[next_left].value; + // + // advance right + next_right = other.data_[next_right].next; + value_right = other.data_[next_right].value; + } + else if( value_left < value_right ) + { // need a value from left that is not in right + left_is_subset = false; + temporary_.push_back(value_left); + // + // advance left to its next element + next_left = data_[next_left].next; + value_left = data_[next_left].value; + } + else + { CPPAD_ASSERT_UNKNOWN( value_right < value_left ) + // need a value from right that is not in left + right_is_subset = false; + temporary_.push_back(value_right); + // + // advance right to its next element + next_right = other.data_[next_right].next; + value_right = other.data_[next_right].value; + } + } + right_is_subset &= value_right == end_; + left_is_subset &= value_left == end_; + // + // check right first in case they are equal will do this assignment + if( right_is_subset ) + { assignment(this_target, this_left, *this); + return; + } + if( left_is_subset ) + { assignment(this_target, other_right, other); + return; + } + while( value_left < end_ ) + { CPPAD_ASSERT_UNKNOWN( value_right == end_); + temporary_.push_back(value_left); + next_left = data_[next_left].next; + value_left = data_[next_left].value; + } + while( value_right < end_ ) + { CPPAD_ASSERT_UNKNOWN( value_left == end_); + temporary_.push_back(value_right); + next_right = other.data_[next_right].next; + value_right = other.data_[next_right].value; + } + + // adjust number_not_used_ + size_t number_drop = drop(this_target); + number_not_used_ += number_drop; + + // put new set in linked for this_target + CPPAD_ASSERT_UNKNOWN( temporary_.size() >= 2 ); + size_t index = get_data_index(); + start_[this_target] = index; // start for the union + data_[index].value = 1; // reference count for the union + for(size_t i = 0; i < temporary_.size(); ++i) + { size_t next = get_data_index(); + data_[index].next = next; + data_[next].value = temporary_[i]; // next element in union + index = next; + } + data_[index].next = 0; // end of union + + return; + } +/* +------------------------------------------------------------------------------- +$begin list_setvec_binary_intersection$$ +$spell + setvec +$$ + +$section class list_setvec: Assign a Set To Equal Another Set$$ + +$head SetVector Concept$$ +$cref/binary_intersection/SetVector/binary_intersection/$$ + +$head Prototype$$ +$srccode%hpp% */ +public: + void binary_intersection( + size_t this_target , + size_t this_left , + size_t other_right , + const list_setvec& other ) +/* %$$ +$end +*/ + { CPPAD_ASSERT_UNKNOWN( post_[this_left] == 0 ); + CPPAD_ASSERT_UNKNOWN( other.post_[ other_right ] == 0 ); + // + CPPAD_ASSERT_UNKNOWN( this_target < start_.size() ); + CPPAD_ASSERT_UNKNOWN( this_left < start_.size() ); + CPPAD_ASSERT_UNKNOWN( other_right < other.start_.size() ); + CPPAD_ASSERT_UNKNOWN( end_ == other.end_ ); + + // start indices for left and right sets + size_t start_left = start_[this_left]; + size_t start_right = other.start_[other_right]; + + // if left or right is empty, the result is empty + if( (start_left == 0) | (start_right == 0) ) + { clear(this_target); + return; + } + // if niether case holds, then both left and right are non-empty + CPPAD_ASSERT_UNKNOWN( reference_count(this_left) > 0 ); + CPPAD_ASSERT_UNKNOWN( other.reference_count(other_right) > 0 ); + + // we will use temparary_ for temporary storage of the intersection + temporary_.resize(0); + + // left next and value + size_t next_left = data_[start_left].next; + size_t value_left = data_[next_left].value; + + // right next and value + size_t next_right = other.data_[start_right].next; + size_t value_right = other.data_[next_right].value; + + // both left and right set are non-empty + CPPAD_ASSERT_UNKNOWN( value_left < end_ && value_right < end_ ); + + // flag that detects if left is or right is a subset of the other + bool left_is_subset = true; + bool right_is_subset = true; + + while( (value_left < end_) & (value_right < end_) ) + { if( value_left == value_right ) + { // value is in both sets + temporary_.push_back(value_left); + // + // advance left + next_left = data_[next_left].next; + value_left = data_[next_left].value; + // + // advance right + next_right = other.data_[next_right].next; + value_right = other.data_[next_right].value; + } + else if( value_left < value_right ) + { // there is a value in left that is not in right + left_is_subset = false; + // + // advance left to its next element + next_left = data_[next_left].next; + value_left = data_[next_left].value; + } + else + { CPPAD_ASSERT_UNKNOWN( value_right < value_left ) + // there is a value in right that is not in left + right_is_subset = false; + // + // advance right to its next element + next_right = other.data_[next_right].next; + value_right = other.data_[next_right].value; + } + } + right_is_subset &= value_right == end_; + left_is_subset &= value_left == end_; + // + // check left first in case they are equal will do this assignment + if( left_is_subset ) + { assignment(this_target, this_left, *this); + return; + } + if( right_is_subset ) + { assignment(this_target, other_right, other); + return; + } + + // adjust number_not_used_ + size_t number_drop = drop(this_target); + number_not_used_ += number_drop; + + // check for empty result + if( temporary_.size() == 0 ) + return; + + // put new set in linked for this_target + size_t index = get_data_index(); + start_[this_target] = index; // start for the union + data_[index].value = 1; // reference count for the union + for(size_t i = 0; i < temporary_.size(); ++i) + { size_t next = get_data_index(); + data_[index].next = next; + data_[next].value = temporary_[i]; // next element in union + index = next; + } + data_[index].next = 0; // end of union + + return; + } +// ========================================================================= +}; // END_CLASS_LIST_SETVEC +// ========================================================================= + +// ========================================================================= +class list_setvec_const_iterator { // BEGIN_CLASS_LIST_SETVEC_CONST_ITERATOR +// ========================================================================= + +/* +$begin list_setvec_const_iterator_member_data$$ +$spell + setvec + const_iterator +$$ + +$section class list_setvec_const_iterator private: Member Data$$ + +$head pair_size_t$$ +This type is the same as +$cref/list_setvec pair_size_t/list_setvec_member_data/pair_size_t/$$. + +$head end_$$ +This is +$cref/end_/list_setvec_member_data/end_/$$ +for the $code list_setvec$$ object this iterator refers to. + +$head data_$$ +This is +$cref/data_/list_setvec_member_data/data_/$$ +for the $code list_setvec$$ object this iterator refers to. + +$head next_pair_$$ +Next element in the set that this iterator refers to. +If $code next_pair_.value == end_$$ there are no more elements in the set. + +$head Source Code$$ +$srccode%hpp% */ +private: + typedef list_setvec::pair_size_t pair_size_t; + const size_t end_; + const pod_vector& data_; + pair_size_t next_pair_; +/* %$$ +$end +------------------------------------------------------------------------------- +$begin list_setvec_const_iterator_ctor$$ +$spell + setvec + const_iterator +$$ + +$section class list_setvec_const_iterator: Constructor$$ + +$head SetVector Concept$$ +$cref/iterator constructor/SetVector/const_iterator/Constructor/$$ + +$head Prototype$$ +$srccode%hpp% */ +public: + list_setvec_const_iterator (const list_setvec& list, size_t i) +/* %$$ +$end +*/ + : end_ ( list.end_ ), data_( list.data_ ) + { CPPAD_ASSERT_UNKNOWN( list.post_[i] == 0 ); + // + size_t start = list.start_[i]; + if( start == 0 ) + { next_pair_.next = 0; + next_pair_.value = end_; + } + else + { // value for this entry is reference count for list + CPPAD_ASSERT_UNKNOWN( data_[start].value > 0 ); + + // data index where list truely starts + size_t next = data_[start].next; + CPPAD_ASSERT_UNKNOWN( next != 0 ); + + // true first entry in the list + next_pair_ = data_[next]; + CPPAD_ASSERT_UNKNOWN( next_pair_.value < end_ ); + } + } +/* +------------------------------------------------------------------------------- +$begin list_setvec_const_iterator_dereference$$ +$spell + setvec + const_iterator + Dereference +$$ + +$section class list_setvec_const_iterator: Dereference$$ + +$head SetVector Concept$$ +$cref/iterator deference/SetVector/const_iterator/Dereference/$$ + +$head Implementation$$ +$srccode%hpp% */ +public: + size_t operator*(void) + { return next_pair_.value; } +/* %$$ +$end +------------------------------------------------------------------------------- +$begin list_setvec_const_iterator_increment$$ +$spell + setvec + const_iterator +$$ + +$section class list_setvec_const_iterator: Increment$$ + +$head SetVector Concept$$ +$cref/iterator increment/SetVector/const_iterator/Increment/$$ + +$head Implementation$$ +$srccode%hpp% */ +public: + list_setvec_const_iterator& operator++(void) + { next_pair_ = data_[next_pair_.next]; + return *this; + } +/* %$$ +$end +*/ +// =========================================================================== +}; // END_CLASS_LIST_SETVEC_CONST_ITERATOR +// =========================================================================== + +// Implemented after list_setvec_const_iterator so can use it +inline void list_setvec::print(void) const +{ std::cout << "list_setvec:\n"; + for(size_t i = 0; i < n_set(); i++) + { std::cout << "set[" << i << "] = {"; + const_iterator itr(*this, i); + while( *itr != end() ) + { std::cout << *itr; + if( *(++itr) != end() ) std::cout << ","; + } + std::cout << "}\n"; + } + return; +} +// ---------------------------------------------------------------------------- +/* +$begin sparsity_user2internal_list_setvec$$ +$spell + setvec + std +$$ + +$section Copy A Vector of Standard Sets To A list_setvec Object$$ + +$head SetVector$$ +is a $cref/simple vector/SimpleVector/$$ type with elements of type +$code std::set$$. + +$head internal$$ +The input value of this object does not matter. +Upon return it contains the same sparsity pattern as $icode user$$ +(or its transpose). + +$head user$$ +is the sparsity pattern we are copying to $icode internal$$. + +$head n_set$$ +is the number of sets in the output sparsity pattern $icode internal$$. +If $icode transpose$$ is false, $icode n_set$$ is equal to +$icode%user%.size()%$$. + +$head end$$ +is the end value for the output sparsity pattern $icode internal$$. +$code list_setvec$$ sparsity pattern $icode internal$$. +If $icode transpose$$ is true, $icode end$$ is equal to +$icode%user%.size()%$$. + +$head transpose$$ +If $icode transpose$$ is false, +element $icode j$$ is in the $th i$$ $icode internal$$ set if +$icode j$$ is in the $icode%user%[%i%]%$$. +Otherwise, +element $icode j$$ is in the $th i$$ $icode internal$$ set if +$icode i$$ is in the $icode%user%[%j%]%$$. + +$head error_msg$$ +is the error message to display if some values in the $icode user$$ +sparsity pattern are not valid. + +$head Prototype$$ +$srccode%hpp% */ +template +void sparsity_user2internal( + list_setvec& internal , + const SetVector& user , + size_t n_set , + size_t end , + bool transpose , + const char* error_msg ) +/* %$$ +$end +**/ +{ +# ifndef NDEBUG + if( transpose ) + CPPAD_ASSERT_KNOWN( end == size_t( user.size() ), error_msg); + if( ! transpose ) + CPPAD_ASSERT_KNOWN( n_set == size_t( user.size() ), error_msg); +# endif + + // iterator for user set + std::set::const_iterator itr; + + // size of internal sparsity pattern + internal.resize(n_set, end); + + if( transpose ) + { // transposed pattern case + for(size_t j = 0; j < end; j++) + { itr = user[j].begin(); + while(itr != user[j].end()) + { size_t i = *itr++; + CPPAD_ASSERT_KNOWN(i < n_set, error_msg); + internal.post_element(i, j); + } + } + for(size_t i = 0; i < n_set; ++i) + internal.process_post(i); + } + else + { for(size_t i = 0; i < n_set; i++) + { itr = user[i].begin(); + while(itr != user[i].end()) + { size_t j = *itr++; + CPPAD_ASSERT_KNOWN( j < end, error_msg); + internal.post_element(i, j); + } + internal.process_post(i); + } + } + return; +} + +} } } // END_CPPAD_LOCAL_SPARSE_NAMESPACE + +// ========================================================================= +// Tell pod_vector class that each pair_size_t is plain old data and hence +// the corresponding constructor need not be called. +namespace CppAD { namespace local { + template <> inline bool + is_pod(void) + { return true; } +} } + +# endif diff --git a/build-config/cppad/include/cppad/local/sparse/list_setvec.omh b/build-config/cppad/include/cppad/local/sparse/list_setvec.omh new file mode 100644 index 00000000..5a41db6b --- /dev/null +++ b/build-config/cppad/include/cppad/local/sparse/list_setvec.omh @@ -0,0 +1,32 @@ +----------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +------------------------------------------------------------------------------ +$begin list_setvec$$ +$spell + Namespace + CppAD + setvec +$$ + +$section Implement SetVector Using Singly Linked Lists$$ + +$head Namespace$$ +This class is in the $code CppAD::local::sparse$$ namespace. + +$head Public$$ +The public member function for the $code list_setvec$$ class implement the +$cref SetVector$$ concept. + +$childtable% + include/cppad/local/sparse/list_setvec.hpp +%$$ + +$end diff --git a/build-config/cppad/include/cppad/local/sparse/pack_setvec.hpp b/build-config/cppad/include/cppad/local/sparse/pack_setvec.hpp new file mode 100644 index 00000000..55d80928 --- /dev/null +++ b/build-config/cppad/include/cppad/local/sparse/pack_setvec.hpp @@ -0,0 +1,910 @@ +# ifndef CPPAD_LOCAL_SPARSE_PACK_SETVEC_HPP +# define CPPAD_LOCAL_SPARSE_PACK_SETVEC_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ +# include +# include + +// BEGIN_CPPAD_LOCAL_SPARSE_NAMESPACE +namespace CppAD { namespace local { namespace sparse { + +// forward declaration of iterator class +class pack_setvec_const_iterator; + +// ============================================================================ +class pack_setvec { +// ============================================================================ +/* +$begin pack_setvec_member_data$$ +$spell + setvec + resize +$$ + +$section class pack_setvec: Private Member Data$$ + +$head Pack$$ +Type used to pack multiple elements of a set (multiple bits) onto one +$icode Pack$$ value. + +$head n_bit_$$ +Number of bits (elements) per $icode Pack$$ value. + +$head zero_$$ +The $icode Pack$$ value with all bits zero. + +$head one_$$ +The $icode Pack$$ value with all bits zero, except for the lowest order bit. + +$head n_set_$$ +Number of sets that we are representing. + +$head end_$$ +The possible elements in each set are $code 0$$, $code 1$$, ..., +$code end_-1$$. + +$head n_pack_$$ +Number of Pack values used to represent one set in the vector; i.e., +to represent $code end_$$ bits. + +$head data_$$ +Data for all of the sets. + +$head Source Code$$ +$srccode%hpp% */ +private: + typedef size_t Pack; + const size_t n_bit_; + const Pack zero_; + const Pack one_; + size_t n_set_; + size_t end_; + size_t n_pack_; + pod_vector data_; +/* %$$ +$end +----------------------------------------------------------------------------- +$begin pack_setvec_vec_memory$$ +$spell + setvec +$$ + +$section class pack_setvec: Approximate Memory Used by Vector$$ + +$head Public$$ +This function is declared public, but is not part of +$cref SetVector$$ concept. + +$head Implementation$$ +$srccode%hpp% */ +public: + size_t memory(void) const + { return data_.capacity() * sizeof(Pack); } +/* %$$ +$end +------------------------------------------------------------------------------- +$begin pack_setvec_vec_print$$ +$spell + setvec +$$ + +$section class pack_setvec: Print a Vector of Sets$$ + + +$head Public$$ +This function is declared public, but is not part of +$cref SetVector$$ concept. + +$head Prototype$$ +$srccode%hpp% */ +public: + void print(void) const; +/* %$$ +$end +------------------------------------------------------------------------------- +$begin pack_setvec_iterators$$ +$spell + setvec + Iterators + typedef + const_iterator +$$ + +$section class pack_setvec: Iterators$$ + +$head SetVector Concept$$ +$cref/const_iterator/SetVector/const_iterator/$$ + +$head typedef$$ +$srccode%hpp% */ +public: + /// declare a const iterator + friend class pack_setvec_const_iterator; + typedef pack_setvec_const_iterator const_iterator; +/* %$$ +$end +------------------------------------------------------------------------------- +$begin pack_setvec_default_ctor$$ +$spell + setvec +$$ + +$section class pack_setvec: Default Constructor$$ + +$head SetVector Concept$$ +$cref/constructor/SetVector/Vector Operations/Constructor/$$ + +$head n_bit_$$ +This member variable is set to the number of bits in a $icode Pack$$ value. + +$head one_$$ +This member variable has only its lowest order bit non-zero; + +$head data_$$ +This member is initialized as the empty vector; i.e., size zero.. + +$head Other$$ +All the other member data are $code size_t$$ values +that are initialized as zero. + +$head Implementation$$ +$srccode%hpp% */ +public: + pack_setvec(void) : + n_bit_( std::numeric_limits::digits ), + zero_(0), one_(1), n_set_(0), end_(0), n_pack_(0), data_(0) + { } +/* %$$ +$end +------------------------------------------------------------------------------- +$begin pack_setvec_destructor$$ +$spell + setvec +$$ + +$section class pack_setvec: Destructor$$ + +$head Implementation$$ +$srccode%hpp% */ +public: + ~pack_setvec(void) + { } +/* %$$ +$end +------------------------------------------------------------------------------- +$begin pack_setvec_copy_ctor$$ +$spell + setvec + CppAD +$$ + +$section class pack_setvec: Copy Constructor$$ + +$head v$$ +The vector of sets that we are attempting to make a copy of. + +$head Implementation$$ +Using the copy constructor is probably due to a $code pack_setvec$$ +being passed by value instead of by reference. +This is a CppAD programing error (not CppAD user error). +$srccode%hpp% */ +public: + pack_setvec(const pack_setvec& v) : + n_bit_( std::numeric_limits::digits ), zero_(0), one_(1) + { CPPAD_ASSERT_UNKNOWN(0); } +/* %$$ +$end +------------------------------------------------------------------------------- +$begin pack_setvec_vec_resize$$ +$spell + setvec + resize +$$ + +$section class pack_setvec: Vector resize$$ + +$head SetVector Concept$$ +$cref/vector resize/SetVector/Vector Operations/resize/$$ + +$head Prototype$$ +$srccode%hpp% */ +public: + void resize(size_t n_set, size_t end) +/* %$$ +$end +*/ + { n_set_ = n_set; + end_ = end; + if( n_set_ == 0 ) + { CPPAD_ASSERT_UNKNOWN( end == 0 ); + data_.clear(); + return; + } + // now start a new vector with empty sets + Pack zero(0); + // + n_pack_ = ( 1 + (end_ - 1) / n_bit_ ); + size_t i = n_set_ * n_pack_; + // + data_.resize(i); + while(i--) + data_[i] = zero; + } +/* %$$ +------------------------------------------------------------------------------- +$begin pack_setvec_vec_n_set$$ +$spell + setvec +$$ + +$section class pack_setvec: Number of Sets$$ + +$head SetVector Concept$$ +$cref/n_set/SetVector/Vector Operations/n_set/$$ + +$head Implementation$$ +$srccode%hpp% */ +public: + size_t n_set(void) const + { return n_set_; } +/* %$$ +$end +------------------------------------------------------------------------------- +$begin pack_setvec_vec_end$$ +$spell + setvec +$$ + +$section class pack_setvec: End Value$$ + +$head SetVector Concept$$ +$cref/end/SetVector/Vector Operations/end/$$ + +$head Implementation$$ +$srccode%hpp% */ +public: + size_t end(void) const + { return end_; } +/* %$$ +$end +------------------------------------------------------------------------------- +$begin pack_setvec_vec_assignment$$ +$spell + setvec +$$ + +$section class pack_setvec: Vector Assignment$$ + +$head SetVector Concept$$ +$cref/vector assignment/SetVector/Vector Operations/Assignment/$$ + +$head Prototype$$ +$srccode%hpp% */ +public: + void operator=(const pack_setvec& other) +/* %$$ +$end +*/ + { CPPAD_ASSERT_UNKNOWN( n_bit_ == other.n_bit_); + CPPAD_ASSERT_UNKNOWN( zero_ == other.zero_); + CPPAD_ASSERT_UNKNOWN( one_ == other.one_); + n_set_ = other.n_set_; + end_ = other.end_; + n_pack_ = other.n_pack_; + data_ = other.data_; + } +/* +------------------------------------------------------------------------------- +$begin pack_setvec_vec_swap$$ +$spell + setvec +$$ + +$section class pack_setvec: Vector Swap$$ + +$head SetVector Concept$$ +$cref/vector swap/SetVector/Vector Operations/swap/$$ + +$head Prototype$$ +$srccode%hpp% */ +public: + void swap(pack_setvec& other) +/* %$$ +$end +*/ + { // size_t objects + CPPAD_ASSERT_UNKNOWN( n_bit_ == other.n_bit_); + CPPAD_ASSERT_UNKNOWN( zero_ == other.zero_); + CPPAD_ASSERT_UNKNOWN( one_ == other.one_); + std::swap(n_set_ , other.n_set_); + std::swap(end_ , other.end_); + std::swap(n_pack_ , other.n_pack_); + // + // pod_vectors + data_.swap(other.data_); + } +/* +------------------------------------------------------------------------------- +$begin pack_setvec_number_elements$$ +$spell + setvec +$$ + +$section class pack_setvec: Number of Elements in a Set$$ + +$head SetVector Concept$$ +$cref/number_elements/SetVector/number_elements/$$ + +$head Prototype$$ +$srccode%hpp% */ +public: + size_t number_elements(size_t i) const +/* %$$ +$end +*/ + { CPPAD_ASSERT_UNKNOWN( i < n_set_ ); + // + // special case where data_[i] is 0 or 1 + if( end_ == 1 ) + { CPPAD_ASSERT_UNKNOWN( n_pack_ == 1 ); + return size_t( data_[i] ); + } + // + // initialize count of non-zero bits in this set + size_t count = 0; + // + // mask corresonding to first bit in Pack + Pack mask = one_; + // + // number of bits in last Packing unit + size_t n_last = (end_ - 1) % n_bit_ + 1; + // + // count bits in last unit + Pack unit = data_[(i + 1) * n_pack_ - 1]; + for(size_t bit = 0; bit < n_last; ++bit) + { CPPAD_ASSERT_UNKNOWN( mask >= one_ ); + if( mask & unit ) + ++count; + mask = mask << 1; + } + if( n_pack_ == 1 ) + return count; + // + // count bits in other units + for(size_t bit = 0; bit < n_bit_; ++bit) + { CPPAD_ASSERT_UNKNOWN( mask >= one_ ); + size_t k = n_pack_; + while(--k) + { if( data_[i * n_pack_ + k] & mask ) + ++count; + } + mask = mask << 1; + } + return count; + } +/* +------------------------------------------------------------------------------- +$begin pack_setvec_add_element$$ +$spell + setvec +$$ + +$section class pack_setvec: Add an Elements to a Set$$ + +$head SetVector Concept$$ +$cref/add_element/SetVector/add_element/$$ + +$head Prototype$$ +$srccode%hpp% */ +public: + void add_element(size_t i, size_t element) +/* %$$ +$end +*/ + { CPPAD_ASSERT_UNKNOWN( i < n_set_ ); + CPPAD_ASSERT_UNKNOWN( element < end_ ); + if( end_ == 1 ) + data_[i] |= one_; + else + { size_t j = element / n_bit_; + size_t k = element - j * n_bit_; + Pack mask = one_ << k; + data_[ i * n_pack_ + j] |= mask; + } + } +/* +------------------------------------------------------------------------------- +$begin pack_setvec_post_element$$ +$spell + setvec +$$ + +$section class pack_setvec: Add an Elements to a Set$$ + +$head SetVector Concept$$ +$cref/post_element/SetVector/post_element/$$ + +$head Implementation$$ +$srccode%hpp% */ +public: + void post_element(size_t i, size_t element) + { add_element(i, element); } +/* %$$ +$end +*/ +/* +------------------------------------------------------------------------------- +$begin pack_setvec_process_post$$ +$spell + setvec +$$ + +$section class pack_setvec: Add Posted Elements to a Set$$ + +$head SetVector Concept$$ +$cref/process_post/SetVector/process_post/$$ + +$head Implementation$$ +$srccode%hpp% */ +public: + void process_post(size_t i) + { return; } +/* %$$ +$end +------------------------------------------------------------------------------- +$begin pack_setvec_is_element$$ +$spell + setvec +$$ + +$section class pack_setvec: Is an Element in a Set$$ + +$head SetVector Concept$$ +$cref/is_element/SetVector/is_element/$$ + +$head Prototype$$ +$srccode%hpp% */ +public: + bool is_element(size_t i, size_t element) const +/* %$$ +$end +*/ + { CPPAD_ASSERT_UNKNOWN( i < n_set_ ); + CPPAD_ASSERT_UNKNOWN( element < end_ ); + if( end_ == 1 ) + return data_[i] != zero_; + // + size_t j = element / n_bit_; + size_t k = element - j * n_bit_; + Pack mask = one_ << k; + return (data_[i * n_pack_ + j] & mask) != zero_; + } +/* +------------------------------------------------------------------------------- +$begin pack_setvec_clear$$ +$spell + setvec +$$ + +$section class pack_setvec: Assign a Set to be Empty$$ + +$head SetVector Concept$$ +$cref/clear/SetVector/clear/$$ + +$head Prototype$$ +$srccode%hpp% */ +public: + void clear(size_t target) +/* %$$ +$end +*/ + { CPPAD_ASSERT_UNKNOWN( target < n_set_ ); + size_t t = target * n_pack_; + + size_t j = n_pack_; + while(j--) + data_[t++] = zero_; + } +/* +------------------------------------------------------------------------------- +$begin pack_setvec_assignment$$ +$spell + setvec +$$ + +$section class pack_setvec: Assign a Set To Equal Another Set$$ + +$head SetVector Concept$$ +$cref/assignment/SetVector/assignment/$$ + +$head Prototype$$ +$srccode%hpp% */ +public: + void assignment( + size_t this_target , + size_t other_value , + const pack_setvec& other ) +/* %$$ +$end +*/ + { CPPAD_ASSERT_UNKNOWN( this_target < n_set_ ); + CPPAD_ASSERT_UNKNOWN( other_value < other.n_set_ ); + CPPAD_ASSERT_UNKNOWN( n_pack_ == other.n_pack_ ); + size_t t = this_target * n_pack_; + size_t v = other_value * n_pack_; + + size_t j = n_pack_; + while(j--) + data_[t++] = other.data_[v++]; + } +/* +------------------------------------------------------------------------------- +$begin pack_setvec_binary_union$$ +$spell + setvec +$$ + +$section class pack_setvec: Assign a Set To Equal Union of Two Sets$$ + +$head SetVector Concept$$ +$cref/binary_union/SetVector/binary_union/$$ + +$head Prototype$$ +$srccode%hpp% */ +public: + void binary_union( + size_t this_target , + size_t this_left , + size_t other_right , + const pack_setvec& other ) +/* %$$ +$end +*/ + { CPPAD_ASSERT_UNKNOWN( this_target < n_set_ ); + CPPAD_ASSERT_UNKNOWN( this_left < n_set_ ); + CPPAD_ASSERT_UNKNOWN( other_right < other.n_set_ ); + CPPAD_ASSERT_UNKNOWN( n_pack_ == other.n_pack_ ); + + size_t t = this_target * n_pack_; + size_t l = this_left * n_pack_; + size_t r = other_right * n_pack_; + + size_t j = n_pack_; + while(j--) + data_[t++] = ( data_[l++] | other.data_[r++] ); + } +/* +------------------------------------------------------------------------------- +$begin pack_setvec_binary_intersection$$ +$spell + setvec +$$ + +$section class pack_setvec: Assign a Set To Intersection of Two Sets$$ + +$head SetVector Concept$$ +$cref/binary_intersection/SetVector/binary_intersection/$$ + +$head Prototype$$ +$srccode%hpp% */ +public: + void binary_intersection( + size_t this_target , + size_t this_left , + size_t other_right , + const pack_setvec& other ) +/* %$$ +$end +*/ + { CPPAD_ASSERT_UNKNOWN( this_target < n_set_ ); + CPPAD_ASSERT_UNKNOWN( this_left < n_set_ ); + CPPAD_ASSERT_UNKNOWN( other_right < other.n_set_ ); + CPPAD_ASSERT_UNKNOWN( n_pack_ == other.n_pack_ ); + + size_t t = this_target * n_pack_; + size_t l = this_left * n_pack_; + size_t r = other_right * n_pack_; + + size_t j = n_pack_; + while(j--) + data_[t++] = ( data_[l++] & other.data_[r++] ); + } +// ========================================================================== +}; // END_CLASS_PACK_SETVEC +// ========================================================================== + + +// ========================================================================= +class pack_setvec_const_iterator { // BEGIN_CLASS_PACK_SETVEC_CONST_ITERATOR +// ========================================================================= + +/* +$begin pack_setvec_const_iterator_member_data$$ +$spell + setvec + const_iterator +$$ + +$section class pack_setvec_const_iterator private: Member Data$$ + +$head Pack$$ +This is the same type as +$cref/pack_setvec Pack/pack_setvec_member_data/Pack/$$. + +$head n_bit_$$ +This is a reference to +$cref/pack_setvec n_bit_/pack_setvec_member_data/n_bit_/$$. + +$head one_$$ +This is a reference to +$cref/pack_setvec one_/pack_setvec_member_data/one_/$$. + +$head n_pack_$$ +This is a reference to +$cref/pack_setvec n_pack_/pack_setvec_member_data/n_pack_/$$. + +$head end_$$ +This is a reference to +$cref/pack_setvec end_/pack_setvec_member_data/end_/$$. + +$head data_$$ +This is a reference to +$cref/pack_setvec data_/pack_setvec_member_data/data_/$$. + +$head data_index_$$ +Index in $code data_$$ where the next element is located. + +$head next_element$$ +Value of the next element in this set +If $code next_element_$$ equals $code end_$$, +no next element exists; i.e., past end of the set. + +$head Source Code$$ +$srccode%hpp% */ +private: + typedef pack_setvec::Pack Pack; + const size_t& n_bit_; + const Pack& one_; + const size_t& n_pack_; + const size_t& end_; + const pod_vector& data_; + size_t data_index_; + size_t next_element_; +public: +/* %$$ +$end +------------------------------------------------------------------------------- +$begin pack_setvec_const_iterator_ctor$$ +$spell + setvec + const_iterator +$$ + +$section class pack_setvec_const_iterator: Constructor$$ + +$head SetVector Concept$$ +$cref/iterator constructor/SetVector/const_iterator/Constructor/$$ + +$head Prototype$$ +$srccode%hpp% */ +public: + pack_setvec_const_iterator (const pack_setvec& pack, size_t set_index) +/* %$$ +$end +*/ + : + n_bit_ ( pack.n_bit_ ) , + one_ ( pack.one_ ) , + n_pack_ ( pack.n_pack_ ) , + end_ ( pack.end_ ) , + data_ ( pack.data_ ) , + data_index_ ( set_index * n_pack_ ) + { CPPAD_ASSERT_UNKNOWN( set_index < pack.n_set_ ); + CPPAD_ASSERT_UNKNOWN( 0 < end_ ); + // + next_element_ = 0; + if( data_[data_index_] & one_ ) + return; + // + // element with index zero is not in this set of integers, + // advance to first element or end + ++(*this); + } +/* +------------------------------------------------------------------------------- +$begin pack_setvec_const_iterator_dereference$$ +$spell + setvec + const_iterator + Dereference +$$ + +$section class pack_setvec_const_iterator: Dereference$$ + +$head SetVector Concept$$ +$cref/iterator deference/SetVector/const_iterator/Dereference/$$ + +$head Implementation$$ +$srccode%hpp% */ + size_t operator*(void) const + { return next_element_; } +/* %$$ +$end +------------------------------------------------------------------------------- +$begin pack_setvec_const_iterator_increment$$ +$spell + setvec + const_iterator +$$ + +$section class pack_setvec_const_iterator: Increment$$ + +$head SetVector Concept$$ +$cref/iterator increment/SetVector/const_iterator/Increment/$$ + +$head Prototype$$ +$srccode%hpp% */ +public: + pack_setvec_const_iterator& operator++(void) +/* %$$ +$end +*/ + { CPPAD_ASSERT_UNKNOWN( next_element_ <= end_ ); + if( next_element_ == end_ ) + return *this; + // + ++next_element_; + if( next_element_ == end_ ) + return *this; + // + // bit index corresponding to next element + size_t bit = next_element_ % n_bit_; + // + // check if we have advanced to the next data index + if( bit == 0 ) + ++data_index_; + // + // initialize mask + size_t mask = one_ << bit; + // + while( next_element_ < end_ ) + { // check if this element is in the set + if( data_[data_index_] & mask ) + return *this; + // + // try next larger element + ++next_element_; + ++bit; + mask <<= 1; + // + // check if we must go to next packed data index + CPPAD_ASSERT_UNKNOWN( bit <= n_bit_ ); + if( bit == n_bit_ ) + { // get next packed value + bit = 0; + mask = one_; + ++data_index_; + } + } + CPPAD_ASSERT_UNKNOWN( next_element_ == end_ ); + return *this; + } +// ========================================================================= +}; // END_CLASS_PACK_SETVEC_CONST_ITERATOR +// ========================================================================= + +// Implemented after pack_setvec_const_iterator so can use it +inline void pack_setvec::print(void) const +{ std::cout << "pack_setvec:\n"; + for(size_t i = 0; i < n_set(); i++) + { std::cout << "set[" << i << "] = {"; + const_iterator itr(*this, i); + while( *itr != end() ) + { std::cout << *itr; + if( *(++itr) != end() ) + std::cout << ","; + } + std::cout << "}\n"; + } + return; +} + +// ---------------------------------------------------------------------------- +/* +$begin sparsity_user2internal_pack_setvec$$ +$spell + setvec + bool +$$ + +$section Copy A Boolean Sparsity Pattern To A pack_setvec Object$$ + +$head SetVector$$ +is a $cref/simple vector/SimpleVector/$$ type with elements of type +$code bool$$ containing the input sparsity pattern. + +$head internal$$ +The input value of this object does not matter. +Upon return it contains the same sparsity pattern as $icode user$$ +(or its transpose). + +$head user$$ +is the sparsity pattern we are copying to $icode internal$$. + +$head n_set$$ +is the number of sets in the output sparsity pattern $icode internal$$. + +$head end$$ +is the end value for the output sparsity pattern $icode internal$$. + +$head transpose$$ +If $icode transpose$$ is false, +element $icode j$$ is in the $th i$$ $icode internal$$ set if +$codei% + %user%[ %i% * %end% + %j% ] +%$$ +Otherwise, +element $icode j$$ is in the $th i$$ $icode internal$$ set if +$codei% + %user%[ %i% * %n_set% + %j% ] +%$$ + +$head error_msg$$ +is the error message to display if +$codei% + %n_set% * %end% != %user%.size() +%$$ + +$head Prototype$$ +$srccode%hpp% */ +template +void sparsity_user2internal( + pack_setvec& internal , + const SetVector& user , + size_t n_set , + size_t end , + bool transpose , + const char* error_msg ) +/* %$$ +$end +*/ +{ CPPAD_ASSERT_KNOWN(size_t( user.size() ) == n_set * end, error_msg ); + + // size of internal sparsity pattern + internal.resize(n_set, end); + + if( transpose ) + { // transposed pattern case + for(size_t j = 0; j < end; j++) + { for(size_t i = 0; i < n_set; i++) + { // no advantage to using post_element for pack_setvec + if( user[ j * n_set + i ] ) + internal.add_element(i, j); + } + } + return; + } + else + { for(size_t i = 0; i < n_set; i++) + { for(size_t j = 0; j < end; j++) + { // no advantage to using post_element for pack_setvec + if( user[ i * end + j ] ) + internal.add_element(i, j); + } + } + } + return; +} + +} } } // END_CPPAD_LOCAL_SPARSE_NAMESPACE + +# endif diff --git a/build-config/cppad/include/cppad/local/sparse/pack_setvec.omh b/build-config/cppad/include/cppad/local/sparse/pack_setvec.omh new file mode 100644 index 00000000..e68d041d --- /dev/null +++ b/build-config/cppad/include/cppad/local/sparse/pack_setvec.omh @@ -0,0 +1,32 @@ +----------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +------------------------------------------------------------------------------ +$begin pack_setvec$$ +$spell + Namespace + CppAD + setvec +$$ + +$section Implement SetVector Using Packed Boolean Values$$ + +$head Namespace$$ +This class is in the $code CppAD::local::sparse$$ namespace. + +$head Public$$ +The public member function for the $code list_setvec$$ class implement the +$cref SetVector$$ concept. + +$childtable% + include/cppad/local/sparse/pack_setvec.hpp +%$$ + +$end diff --git a/build-config/cppad/include/cppad/local/sparse/setvector.omh b/build-config/cppad/include/cppad/local/sparse/setvector.omh new file mode 100644 index 00000000..fb5885c7 --- /dev/null +++ b/build-config/cppad/include/cppad/local/sparse/setvector.omh @@ -0,0 +1,254 @@ +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +$begin SetVector$$ +$spell + dereference + itr + iterator + const + resize + vec + CppAD + bool +$$ + +$section C++ Concept: Vector of Sets With size_t Elements$$ + +$head Purpose$$ +The main CppAD use of this C++ Concept is to compute sparsity patterns +as fast as possible. +It is also used for conditional expression optimization. +We refer to a type that supports this concept as $icode SetVector$$ below. + +$head Vector Operations$$ + +$subhead Constructor$$ +In the specifications below, $icode vec$$ and $icode other$$ +are $icode SetVector$$ objects created using the default constructor; e.g., +$codei% + %SetVector% %vec%, %other%; +%$$ +After this constructor the vectors are empty; i.e., +there are no sets in either vector. +The $code resize$$ for $icode vec$$ and $icode other$$ can +have different $cref/n_set/SetVector/Vector Operations/n_set/$$ values, +but must have the same $cref/end/SetVector/Vector Operations/end/$$ value. + +$subhead resize$$ +This operation has the following syntax: +$codei% + %vec%.resize(%n_set%, %end%) +%$$ +The argument $icode n_set$$ has type $code size_t$$ and is the +number of sets in $icode vec$$. +The argument $icode end$$ has type $code size_t$$ and is greater than +any element allowed in any set in $icode vec$$. +Any information in $icode vec$$ before this operation is lost. +After this operation, all the sets in $icode vec$$ are empty. +If $icode n_set$$ is zero, +any allocated memory to keep track of this vector of sets is freed. + +$subhead n_set$$ +The syntax +$codei% + %n_set% = %vec%.n_set() +%$$ +sets the $code size_t$$ value $icode n_set$$ equal to the +number of sets in $icode vec$$. +The $icode vec$$ object is $code const$$ for this operation. + +$subhead end$$ +The syntax +$codei% + %end% = %vec%.end() +%$$ +sets the $code size_t$$ value $icode end$$ equal to the +end value for the sets in $icode vec$$. +(This is one greater than the maximum value for any element +in any set in $icode vec$$.) +The $icode vec$$ object is $code const$$ for this operation. + +$subhead Assignment$$ +The following +makes $icode vec$$ into a separate copy of $icode other$$: +$codei% + %vec% = %other% +%$$ +The $icode other$$ object is $code const$$ for this operation. + +$subhead swap$$ +The following +exchanges to vector of sets in $icode vec$$ and $icode other$$: +$codei% + %vec%.swap(%other%) +%$$ + +$head number_elements$$ +If $icode i$$ is a $code size_t$$ value less than $icode n_set$$, +$codei% + %count% = %vec%.number_elements(%i%) +%$$ +returns the $code size_t$$ value $icode count$$ +equal to the number of elements in the $th i$$ set. +The $icode vec$$ object is $code const$$ for this operation. +It is an error to have postings to $th i$$ that have not been processed. + +$head add_element$$ +If $icode i$$ is a $code size_t$$ value less than $icode n_set$$ +and $icode element$$ is a $code size_t$$ value less than $icode end$$, +$codei% + %vec%.add_element(%i%, %element%) +%$$ +adds the specified element to the $th i$$ set. + +$head post_element$$ +If $icode i$$ is a $code size_t$$ value less than $icode n_set$$ +and $icode element$$ is a $code size_t$$ value less than $icode end$$, +$codei% + %vec%.post_element(%i%, %element%) +%$$ +post the specified element for addition to the $th i$$ set. +Posting multiple elements to one set and then processing them may be faster +than adding one element at a time. +It is an error to use $icode vec$$, +in a way that depends on the values in the $th i$$ set, +between a $code post_element$$ and the corresponding $code process_post$$. + +$head process_post$$ +If $icode i$$ is a $code size_t$$ value less than $icode n_set$$, +$codei% + %vec%.process_post(%i%) +%$$ +Processes all of the posts that have been made for the $th i$$ set; i.e., +adds the posted elements to the set. + +$head is_element$$ +If $icode i$$ is a $code size_t$$ value less than $icode n_set$$ +and $icode element$$ is a $code size_t$$ value less than $icode end$$, +$codei% + %find% = %vec%.is_element(%i%, %element%) +%$$ +returns the $code bool$$ value $icode find$$ +which is true (false) if the specified element is in +(is not in) the $th i$$ set. +The $icode vec$$ object is $code const$$ for this operation. + +$head clear$$ +If $icode i$$ is a $code size_t$$ value less than $icode n_set$$, +$codei% + %vec%.clear(%i%) +%$$ +assigns the empty set to the $th i$$ set. +It is OK to have postings to $th i$$ that have not been processed +(they are removed). + +$head assignment$$ +If $icode this_target$$ and $icode other_source$$ +are $code size_t$$ with value less than the end value, +$codei% + %vec%.assignment(%this_target%, %other_source%, %other%) +%$$ +sets the $icode this_target$$ set in $icode vec$$ +equal to the $icode other_source$$ set in $icode other$$. +If $icode vec$$ and $icode other$$ are the same object, +this operation may save memory and time using smart pointers. +The $icode other$$ object is $code const$$ for this operation. +It is OK (is an error) to have postings to $icode this_target$$ +($icode other_source$$) that have not been processed. + +$head binary_union$$ +If $icode this_target$$, $icode this_left$$, and $icode other_right$$ +are $code size_t$$ with value less than the end value, +$codei% + %vec%.binary_union( + %this_target%, %this_left%, %other_right%, %other% + ) +%$$ +sets the $icode this_target$$ set in $icode vec$$ equal to the union of +the $icode this_left$$ set in $icode vec$$ and +the $icode other_right$$ set in $icode other$$. +If the resulting set is equal to the left set (right set), +this operation may use save memory and time using smart pointers +(provided $icode vec$$ and $icode other$$ are the same object), +The $icode other$$ object is $code const$$ for this operation. +It is OK (is an error) to have postings to $icode this_target$$ +($icode this_left$$ and $code other_right$$) that have not been processed. + +$head binary_intersection$$ +If $icode this_target$$, $icode this_left$$, and $icode other_right$$ +are $code size_t$$ with value less than the end value, +$codei% + %vec%.binary_intersection( + %this_target%, %this_left%, %other_right%, %other% + ) +%$$ +sets the $icode this_target$$ set in $icode vec$$ equal to the intersection of +the $icode this_left$$ set in $icode vec$$ and +the $icode other_right$$ set in $icode other$$. +If the resulting set is equal to the left set (right set), +this operation may use save memory and time using smart pointers +(provided $icode vec$$ and $icode other$$ are the same object), +The $icode other$$ object is $code const$$ for this operation. +It is OK (is an error) to have postings to $icode this_target$$ +($icode this_left$$ and $code other_right$$) that have not been processed. + + +$head const_iterator$$ + +$subhead Constructor$$ +Given a $icode SetVector$$ object $icode vec$$, +and a $code size_t$$ index $icode i$$, +a constant iterator $icode itr$$ is constructed as follows: +$codei% + %SetVector%::const_iterator %itr%(%vec%, %i%) +%$$ +After this constructor, $icode itr$$ points to the first +(smallest) element in the $th i$$ set. +The $icode vec$$ object is $code const$$ for this operation. +It is an error to have postings to $th i$$ that have not been processed. + +$subhead Dereference$$ +The operation +$codei% + %element% = *%itr +%$$ +sets the $code size_t$$ value $icode element$$ to the current element value. +If $icode element$$ is equal to value $icode%vec%.end()%$$, +we have iterated through all the elements of the set +($icode element$$ is not in the set). +It is an error to have postings to $th i$$ that have not been processed. + +$subhead Increment$$ +The operation $codei%++%itr%$$ points $icode itr$$ to the next larger +element in the set. +The increment operation is not defined when the value of +$codei%*%itr%$$ is equal to $icode%vec%.end()%$$. +The operation +$codei% + %element% = *(++%itr%) +%$$ +increments the iterator $icode itr$$ and sets $icode element$$ +to the deference after the increment (see dereference above). +It is an error to have postings to $th i$$ that have not been processed. + +$head Implementation$$ +$children% + include/cppad/local/sparse/list_setvec.omh% + include/cppad/local/sparse/pack_setvec.omh +%$$ +$table +$rref list_setvec$$ +$rref pack_setvec$$ +$tend + +$end diff --git a/build-config/cppad/include/cppad/local/sparse/svec_setvec.hpp b/build-config/cppad/include/cppad/local/sparse/svec_setvec.hpp new file mode 100644 index 00000000..60f58268 --- /dev/null +++ b/build-config/cppad/include/cppad/local/sparse/svec_setvec.hpp @@ -0,0 +1,1506 @@ +# ifndef CPPAD_LOCAL_SPARSE_SVEC_SETVEC_HPP +# define CPPAD_LOCAL_SPARSE_SVEC_SETVEC_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ +# include +# include +# include + +// BEGIN_CPPAD_LOCAL_SPARSE_NAMESPACE +namespace CppAD { namespace local { namespace sparse { + +/*! +\file svec_setvec.hpp +Vector of sets of positive integers stored as size_t vector +with the element values strictly increasing. + +Testing indicates this does not work as well as using sparse::list_setvec +(not currently being used except by test_more/general/local/vector_set.cpp). +*/ +class svec_setvec_const_iterator; + +// ========================================================================= +/*! +Vector of sets of positive integers, each set stored as a size_t vector. + +All the public members for this class are also in the +sparse::pack_setvec and sparse::list_setvec classes. +This defines the CppAD vector_of_sets concept. +*/ +class svec_setvec { + friend class svec_setvec_const_iterator; +private: + /// Possible elements in each set are 0, 1, ..., end_ - 1; + size_t end_; + + /// number of elements in data_ that have been allocated + /// and are no longer being used. + size_t data_not_used_; + + /// The data for all the singly linked lists. + pod_vector data_; + + /*! + Starting point for i-th set is start_[i]. + + \li + If the i-th set has no elements, start_[i] is zero. + Othersize the conditions below hold. + + \li + data_[ start_[i] ] is the reference count for this set + + \li + data_[ start_[i] + 1 ] is the first element in this set. + + \li + data_[ start_[i] + 2 ] is the first element in this set. + + \li + data_[ start_[i] + 2 + n ] = end_ where n is the number of + elements in this set + */ + pod_vector start_; + + /*! + Vectors of elements that have not yet been added to corresponding sets. + + \li + If all the post_element calls for the i-th set have been added, + post_[i] is zero. Otherwise the conditions below hold. + + \li + data_[ post_[i] ] the number of elements that have been posted, + but not yet added, to set i. + + \li + data_[ post_[i] + 1 ] is the capacity for holding elements + which is greater than or equal the number of elements. + + \li + data_[ post_[i] + 2 ] is the first element that has been posted, + but not yet added, to set i. + + \li + data_[ post_[i] + 1 + n] is the last element that has been posted, + but not yet added, to set i. + Here n is the number of elements that are posted and not yet added + to set i. + */ + pod_vector post_; + // ----------------------------------------------------------------- + /*! + Counts references to a set. + + \param i + is the index of the set that we are counting the references to. + + \return + if the set is empty, the return value is zero. + Otherwise it is the number of sets that share the same vector. + */ + size_t reference_count(size_t i) const + { // start data index + size_t start = start_[i]; + if( start == 0 ) + return 0; + // + // reference count + return data_[start]; + } + // ----------------------------------------------------------------- + /*! + drop a set. + + \param i + is the index of the set that will be dropped. + + \par reference_count + if the set is non-empty, + the reference count corresponding to index will be decremented. + + \return + is the number of elements of data_ that will be lost when the set is + dropped. This is non-zero when the initial reference count is one. + */ + size_t drop(size_t i) + { + // reference count + size_t ref_count = reference_count(i); + + // empty set case + if( ref_count == 0 ) + return 0; + + // start + size_t start = start_[i]; + CPPAD_ASSERT_UNKNOWN( data_[start] == ref_count ); + + // decrement reference counter + data_[start]--; + + // nothing lost unless new reference count is zero + if( ref_count != 1 ) + return 0; + + // number of elements in the set + size_t length = data_[start + 1]; + + // reference count, length, end marker, plus elements in set + size_t number_lost = 3 + length; + + // number_lost + return number_lost; + } + // ----------------------------------------------------------------- + /*! + Checks data structure + (effectively const, but modifies and restores values) + */ +# ifdef NDEBUG + void check_data_structure(void) + { return; } +# else + void check_data_structure(void) + { // number of sets + CPPAD_ASSERT_UNKNOWN( post_.size() == start_.size() ); + size_t n_set = start_.size(); + if( n_set == 0 ) + { CPPAD_ASSERT_UNKNOWN( end_ == 0 ); + CPPAD_ASSERT_UNKNOWN( data_not_used_ == 0 ); + CPPAD_ASSERT_UNKNOWN( data_.size() == 0 ); + CPPAD_ASSERT_UNKNOWN( start_.size() == 0 ); + CPPAD_ASSERT_UNKNOWN( post_.size() == 0 ); + return; + } + // ------------------------------------------------------------------ + // save the reference counters + pod_vector ref_count(n_set); + for(size_t i = 0; i < n_set; i++) + ref_count[i] = reference_count(i); + // ------------------------------------------------------------------ + + // ------------------------------------------------------------------ + // count the number of entries in data_ that are used by sets + size_t data_used_by_sets = 0; + for(size_t i = 0; i < n_set; i++) + { size_t start = start_[i]; + if( start > 0 ) + { // check structure for this non-empty set + size_t reference_count = data_[start + 0]; + size_t length = data_[start + 1]; + size_t first = data_[start + 2]; + size_t last = data_[start + 2 + length]; + CPPAD_ASSERT_UNKNOWN( reference_count > 0 ); + CPPAD_ASSERT_UNKNOWN( length > 0 ); + CPPAD_ASSERT_UNKNOWN( first < end_); + CPPAD_ASSERT_UNKNOWN( last == end_); + // + // decrement the reference counter + data_[start]--; + // + // count the entries when find last reference + if( data_[start] == 0 ) + { + // restore reference count + data_[start] = ref_count[i]; + + // number of data_ entries used for this set + data_used_by_sets += number_elements(i) + 3; + } + } + } + // ------------------------------------------------------------------ + // count the number of entries in data_ that are used by posts + size_t data_used_by_posts = 0; + for(size_t i = 0; i < n_set; i++) + { size_t post = post_[i]; + if( post > 0 ) + { CPPAD_ASSERT_UNKNOWN( data_[post] > 0 ); + CPPAD_ASSERT_UNKNOWN( data_[post + 1] > 0 ); + CPPAD_ASSERT_UNKNOWN( data_[post + 2] < end_ ); + // + size_t capacity = data_[post + 1]; + data_used_by_posts += capacity + 2; + } + } + // ------------------------------------------------------------------ + size_t data_used = data_used_by_sets + data_used_by_posts; + CPPAD_ASSERT_UNKNOWN( + data_used + data_not_used_ == data_.size() + ); + return; + } +# endif + // ----------------------------------------------------------------- + /*! + Check if one of two sets is a subset of the other set + + \param one_this + is the index in this svec_setvec object of the first set. + + \param two_other + is the index in other svec_setvec object of the second set. + + \param other + is the other svec_setvec object which may be the same as this object. + + \return + If zero, niether set is a subset of the other. + If one, then one is a subset of two and they are not equal. + If two, then two is a subset of one and they are not equal. + If three, then the sets are equal. + */ + size_t is_subset( + size_t one_this , + size_t two_other , + const svec_setvec& other ) const + { + CPPAD_ASSERT_UNKNOWN( one_this < start_.size() ); + CPPAD_ASSERT_UNKNOWN( two_other < other.start_.size() ); + CPPAD_ASSERT_UNKNOWN( end_ == other.end_ ); + // + // start + size_t start_one = start_[one_this]; + size_t start_two = other.start_[two_other]; + // + if( start_one == 0 ) + { // set one is empty + if( start_two == 0 ) + { // set two is empty + return 3; + } + // set one is empty and two is not empty + return 1; + } + if( start_two == 0 ) + { // set two is empty and one is not empty + return 2; + } + // + // data index + size_t index_one = start_one + 2; + size_t index_two = start_two + 2; + // + // value + size_t value_one = data_[index_one]; + size_t value_two = other.data_[index_two]; + // + bool one_subset = true; + bool two_subset = true; + // + size_t value_union = std::min(value_one, value_two); + while( (one_subset | two_subset) & (value_union < end_) ) + { // + if( value_one > value_union ) + two_subset = false; + else + { // value_one <= value_two and value_one < end_ + value_one = data_[++index_one]; + } + // + if( value_two > value_union ) + one_subset = false; + else + { // value_two <= value_one and value_two < end_ + value_two = other.data_[++index_two]; + } + value_union = std::min(value_one, value_two); + } + if( one_subset ) + { if( two_subset ) + { // sets are equal + return 3; + } + // one is a subset of two + return 1; + } + if( two_subset ) + { // two is a subset of one + return 2; + } + // + // neither is a subset + return 0; + } + // ----------------------------------------------------------------- + /*! + Does garbage collection when indicated. + + This routine should be called when more entries are not being used. + If a significant propotion are not being used, the data structure + will be compacted. + + The size of data_ should equal the number of entries used by the sets + plus the number of entries that are not being used data_not_used_. + Note that data_[0] never gets used. + */ + void collect_garbage(void) + { if( data_not_used_ < data_.size() / 2 + 100) + return; + check_data_structure(); + // + // number of sets including empty ones + size_t n_set = start_.size(); + // + // use temporary to hold copy of data_ and start_ + pod_vector data_tmp(1); // data_tmp[0] will not be used + pod_vector start_tmp(n_set); + // + for(size_t i = 0; i < n_set; i++) + { size_t start = start_[i]; + if( start == 0 ) + start_tmp[i] = 0; + else + { // check if this set has already been copied + if( data_[start] == 0 ) + { // starting address in data_tmp has been stored here + start_tmp[i] = data_[start + 1]; + } + else + { size_t tmp_start = data_tmp.extend(2); + start_tmp[i] = tmp_start; + data_tmp[tmp_start + 0] = data_[start + 0]; + data_tmp[tmp_start + 1] = data_[start + 1]; + // + for(size_t j = 2; data_[start + j] != end_; ++j) + data_tmp.push_back( data_[start + j] ); + data_tmp.push_back(end_); + // + // flag that indicates this set already copied + data_[start] = 0; + // + // store the starting address here + data_[start + 1] = tmp_start; + } + } + } + + // swap the tmp and old data vectors + start_.swap(start_tmp); + data_.swap(data_tmp); + + // all of the elements, except the first, are used + data_not_used_ = 1; + } + // ----------------------------------------------------------------- + /*! + Assign a set equal to the union of a set and a vector; + + \param target + is the index in this svec_setvec object of the set being assinged. + + \param left + is the index in this svec_setvec object of the + left operand for the union operation. + It is OK for target and left to be the same value. + + \param right + is a vector of size_t, sorted in accending order. + right operand for the union operation. + Elements can be repeated in right, but are not be repeated in the + resulting set. + All of the elements must have value less than end(); + */ + void binary_union( + size_t target , + size_t left , + const pod_vector& right ) + { CPPAD_ASSERT_UNKNOWN( post_[left] == 0 ); + // + CPPAD_ASSERT_UNKNOWN( target < start_.size() ); + CPPAD_ASSERT_UNKNOWN( left < start_.size() ); + + size_t start_left = start_[left]; + // ------------------------------------------------------------------- + // Check if right is a subset of left so that we used reference count + // and not make copies of identical sets. + // + // initialize index for left and right sets + size_t current_left = start_left; + size_t current_right = 0; + // + // initialize value_left + size_t value_left = end_; + if( current_left > 0 ) + { // advance from reference counter to data + current_left = current_left + 2; + value_left = data_[current_left]; + CPPAD_ASSERT_UNKNOWN( value_left < end_); + } + // + // initialize value_right + size_t value_right = end_; + if( right.size() > 0 ) + value_right = right[current_right]; + // + bool subset = true; + while( subset & (value_right < end_) ) + { while( value_left < value_right ) + { // advance left + value_left = data_[++current_left]; + } + if( value_right < value_left ) + subset = false; + else + { // advance right + ++current_right; + if( current_right == right.size() ) + value_right = end_; + else + value_right = right[current_right]; + } + } + // + if( subset ) + { // target = left will use reference count for identical sets + assignment(target, left, *this); + return; + } + + // ------------------------------------------------------------------- + // number of elements that will be deleted by removing old version + // of target + size_t number_lost = drop(target); + + // drop any posting for the target set + size_t post = post_[target]; + if( post > 0 ) + { CPPAD_ASSERT_UNKNOWN( target != left ); + size_t capacity = data_[post + 1]; + number_lost += capacity + 2; + post_[target] = 0; + } + // + // start new version of target + size_t start = data_.extend(2); + start_[target] = start; + data_[start] = 1; // reference count + // data_[start + 1] = length is not yet known + // + // initialize value_left + current_left = start_left; + value_left = end_; + if( current_left > 0 ) + { // advance from reference counter to data + current_left = current_left + 2; + value_left = data_[current_left]; + CPPAD_ASSERT_UNKNOWN( value_left < end_); + } + // + // initialize value_right + value_right = end_; + if( right.size() > 0 ) + value_right = right[current_right]; + // + // merge + while( (value_left < end_) | (value_right < end_) ) + { if( value_left == value_right) + { // advance left so left and right are no longer equal + ++current_left; + value_left = data_[current_left]; + CPPAD_ASSERT_UNKNOWN( value_right < value_left ); + } + // + if( value_left < value_right ) + { // value_left case + CPPAD_ASSERT_UNKNOWN( value_left < end_ ); + data_.push_back( value_left ); + // + // advance left + ++current_left; + value_left = data_[current_left]; + } + else + { CPPAD_ASSERT_UNKNOWN( value_right < value_left ) + // value_right case + CPPAD_ASSERT_UNKNOWN( value_right < end_); + data_.push_back( value_right ); + // + // advance right (skip values equal to this one) + size_t previous_value = value_right; + while( value_right == previous_value ) + { ++current_right; + if( current_right == right.size() ) + value_right = end_; + else + { value_right = right[current_right]; + CPPAD_ASSERT_UNKNOWN( value_right < end_ ); + } + } + } + } + // make end of target list + data_.push_back( end_ ); + // + // reference count, length, and end_ are not elements of set + CPPAD_ASSERT_UNKNOWN( data_.size() > start + 3 ); + size_t length = data_.size() - (start + 3); + data_[start + 1] = length; + // + + // adjust data_not_used_ + data_not_used_ += number_lost; + collect_garbage(); + } +public: + /// declare a const iterator + typedef svec_setvec_const_iterator const_iterator; + // ----------------------------------------------------------------- + /*! + Default constructor (no sets) + */ + svec_setvec(void) : + end_(0) , + data_not_used_(0) , + data_(0) , + start_(0) , + post_(0) + { } + // ----------------------------------------------------------------- + /// Destructor + ~svec_setvec(void) + { check_data_structure(); + } + // ----------------------------------------------------------------- + /*! + Using copy constructor is a programing (not user) error + + \param v + vector of sets that we are attempting to make a copy of. + */ + svec_setvec(const svec_setvec& v) + { // Error: Probably a svec_setvec argument has been passed by value + CPPAD_ASSERT_UNKNOWN(false); + } + // ----------------------------------------------------------------- + /*! + Assignement operator. + + \param other + this svec_setvec with be set to a deep copy of other. + */ + void operator=(const svec_setvec& other) + { end_ = other.end_; + data_not_used_ = other.data_not_used_; + data_ = other.data_; + start_ = other.start_; + post_ = other.post_; + } + // ----------------------------------------------------------------- + /*! + swap (used by move semantics version of ADFun assignment operator) + + \param other + this sparse::list_setvec with be swapped with other. + + \par vector_of_sets + This public member function is not yet part of + the vector_of_sets concept. + */ + void swap(svec_setvec& other) + { // size_t objects + std::swap(end_ , other.end_); + std::swap(data_not_used_ , other.data_not_used_); + + // pod_vectors + data_.swap( other.data_); + start_.swap( other.start_); + post_.swap( other.post_); + } + // ----------------------------------------------------------------- + /*! + Start a new vector of sets. + + \param n_set + is the number of sets in this vector of sets. + \li + If n_set is zero, any memory currently allocated for this object + is freed. + \li + If n_set is non-zero, a vector of n_set sets is created and all + the sets are initilaized as empty. + + \param end + is the maximum element plus one (the minimum element is 0). + If n_set is zero, end must also be zero. + */ + void resize(size_t n_set, size_t end) + { check_data_structure(); + + if( n_set == 0 ) + { CPPAD_ASSERT_UNKNOWN(end == 0 ); + // + // restore object to start after constructor + // (no memory allocated for this object) + data_.clear(); + start_.clear(); + post_.clear(); + data_not_used_ = 0; + end_ = 0; + // + return; + } + end_ = end; + // + start_.resize(n_set); + post_.resize(n_set); + for(size_t i = 0; i < n_set; i++) + { start_[i] = 0; + post_[i] = 0; + } + // + data_.resize(1); // first element is not used + data_not_used_ = 1; + } + // ----------------------------------------------------------------- + /*! + Return number of elements in a set. + + \param i + is the index of the set we are checking number of the elements of. + */ + size_t number_elements(size_t i) const + { CPPAD_ASSERT_UNKNOWN( post_[i] == 0 ); + // + size_t start = start_[i]; + if( start == 0 ) + return 0; + return data_[start + 1]; + } + // ------------------------------------------------------------------ + /*! + Post an element for delayed addition to a set. + + \param i + is the index for this set in the vector of sets. + + \param element + is the value of the element that we are posting. + The same element may be posted multiple times. + + \par + It is faster to post multiple elements to set i and then call + process_post(i) then to add each element individually. + It is an error to call any member function, + that depends on the value of set i, + before processing the posts to set i. + */ + void post_element(size_t i, size_t element) + { CPPAD_ASSERT_UNKNOWN( i < start_.size() ); + CPPAD_ASSERT_UNKNOWN( element < end_ ); + + size_t post = post_[i]; + if( post == 0 ) + { // minimum capacity for an post vector + size_t min_capacity = 10; + size_t post_new = data_.extend(min_capacity + 2); + data_[post_new] = 1; // length + data_[post_new + 1] = min_capacity; // capacity + data_[post_new + 2] = element; + post_[i] = post_new; + } + else + { size_t length = data_[post]; + size_t capacity = data_[post + 1]; + if( length == capacity ) + { + size_t post_new = data_.extend( 2 * capacity ); + // + data_[post_new] = length + 1; + data_[post_new + 1] = 2 * capacity; + // + for(size_t j = 0; j < length; j++) + data_[post_new + 2 + j] = data_[post + 2 + j]; + data_[post_new + 2 + length] = element; + // + post_[i] = post_new; + size_t number_lost = length + 2; + data_not_used_ += number_lost; + } + else + { data_[post] = length + 1; + data_[post + 2 + length] = element; + } + } + + // check amount of data_not_used_ + collect_garbage(); + + return; + } + // ----------------------------------------------------------------- + /*! + process post entries for a specific set. + + \param i + index of the set for which we are processing the post entries. + + \par post_ + Upon call, post_[i] is location in data_ of the elements that get + added to the i-th set. Upon return, post_[i] is zero. + */ + void process_post(size_t i) + { // start + size_t start = start_[i]; + // post + size_t post = post_[i]; + // + // check if there are no elements to process + if( post == 0 ) + return; + // + // sort the elements that need to be processed + size_t length_post = data_[post]; + size_t capacity_post = data_[post + 1]; + size_t* first_post = data_.data() + post + 2; + size_t* last_post = first_post + length_post; + std::sort(first_post, last_post); + // ------------------------------------------------------------------- + // check if posted elements are a subset of set + // + // first element of the set + size_t current_set = start; + size_t value_set = end_; + if( start > 0 ) + { current_set = start + 2; + value_set = data_[current_set]; + } + // + // first element to post + size_t* current_post = first_post; + size_t value_post = *current_post; + // + bool subset = true; + while( subset & (value_post != end_) ) + { while( value_set < value_post ) + value_set = data_[++current_set]; + if( value_post < value_set ) + subset = false; + else + { ++current_post; + if( current_post == last_post ) + value_post = end_; + else + value_post = *current_post; + } + } + // + if( subset ) + { // drop the post_ elements + post_[i] = 0; + // + size_t number_lost = capacity_post + 2; + data_not_used_ += number_lost; + collect_garbage(); + // + // nothing else to do + return; + } + // ------------------------------------------------------------------- + // number of element that will be lost by removing old i-th set + size_t number_lost = drop(i); + + // start new version of i-th set + size_t start_new = data_.extend(2); + start_[i] = start_new; + data_[start_new] = 1; // reference count + // data[start_new + 1] = length_new is not yet known + // + // first element of the set + current_set = start; + value_set = end_; + if( start > 0 ) + { current_set = start + 2; + value_set = data_[current_set]; + } + // + // first element to process + current_post = first_post; + value_post = *current_post; + // + // merge + while( (value_set < end_) | (current_post != last_post ) ) + { if( value_set == value_post ) + { // advance left so left and right are no longer equal + ++current_set; + value_set = data_[current_set]; + CPPAD_ASSERT_UNKNOWN( value_post < value_set ); + } + // + if( value_set < value_post ) + { // add value_set + CPPAD_ASSERT_UNKNOWN( value_set < end_ ); + data_.push_back( value_set ); + // + // advance set + ++current_set; + value_set = data_[current_set]; + } + else + { CPPAD_ASSERT_UNKNOWN( value_post < value_set ) + // add value_post + CPPAD_ASSERT_UNKNOWN( value_post < end_); + data_.push_back( value_post ); + // + // advance post (skip values equal to this one) + size_t value_previous = value_post; + while( value_post == value_previous ) + { ++current_post; + if( current_post == last_post ) + value_post = end_; + else + value_post = *current_post; + } + } + } + // make end of target list + data_.push_back( end_ ); + // + // reference count, length, and end_ are not elements of set + CPPAD_ASSERT_UNKNOWN( data_.size() > start_new + 3 ); + size_t length_new = data_.size() - (start_new + 3); + data_[start_new + 1] = length_new; + CPPAD_ASSERT_UNKNOWN( data_[start_new + length_new + 2] == end_ ); + // + // drop to post_ elements for this set + post_[i] = 0; + // + number_lost += capacity_post + 2; + data_not_used_ += number_lost; + collect_garbage(); + // + return; + } + // ----------------------------------------------------------------- + /*! + Add one element to a set. + + \param i + is the index for this set in the vector of sets. + + \param element + is the element we are adding to the set. + */ + void add_element(size_t i, size_t element) + { CPPAD_ASSERT_UNKNOWN( i < start_.size() ); + CPPAD_ASSERT_UNKNOWN( element < end_ ); + + // check if element is already in the set + if( is_element(i, element) ) + return; + + // check for case where old set is empty + size_t start = start_[i]; + if( start == 0 ) + { start = data_.extend(4); + start_[i] = start; + data_[start] = 1; // reference count + data_[start + 1] = 1; // length + data_[start + 2] = element; // the element + data_[start + 3] = end_; // end marker + return; + } + // + size_t number_lost = drop(i); + // + // start of new set + size_t length = data_[start + 1]; + size_t new_start = data_.extend(2); + data_[new_start] = 1; // reference count + data_[new_start + 1] = length + 1; // new length + // + size_t count = 0; + size_t value = data_[start + 2 + count]; + // before new element + while( value < element) + { data_.push_back( value ); + ++count; + value = data_[start + 2 + count]; + } + CPPAD_ASSERT_UNKNOWN( element < value ) + // new element + data_.push_back( element ); + // after new element + while( value < end_ ) + { data_.push_back( value ); + ++count; + value = data_[start + 2 + count]; + } + data_.push_back( end_ ); + + // + // connect up new set + start_[i] = new_start; + + // adjust data_not_used_ + data_not_used_ += number_lost; + collect_garbage(); + // + return; + } + // ----------------------------------------------------------------- + /*! + Check if an element is in a set. + + \param i + is the index for this set in the vector of sets. + + \param element + is the element we are checking to see if it is in the set. + */ + bool is_element(size_t i, size_t element) const + { CPPAD_ASSERT_UNKNOWN( post_[i] == 0 ); + CPPAD_ASSERT_UNKNOWN( element < end_ ); + // + size_t start = start_[i]; + if( start == 0 ) + return false; + // + size_t length = data_[start + 1]; + const size_t* first = data_.data() + start + 2; + const size_t* last = first + length; + if( length < 10 ) + { bool result = false; + while( last > first ) + result |= *(--last) == element; + return result; + } + // + return std::binary_search(first, last, element); + } + // ----------------------------------------------------------------- + /*! + Assign the empty set to one of the sets. + + \param target + is the index of the set we are setting to the empty set. + + \par data_not_used_ + increments this value by number of data_ elements that are lost + (unlinked) by this operation. + */ + void clear(size_t target) + { + // number of data_ elements used for this set + size_t number_lost = drop( target ); + + // set target to empty set + start_[target] = 0; + + // drop the posted elements + if( post_[target] != 0 ) + { size_t capacity = post_[target + 1]; + number_lost += capacity + 2; + // + post_[target] = 0; + } + + // adjust data_not_used_ + data_not_used_ += number_lost; + collect_garbage(); + } + // ----------------------------------------------------------------- + /*! + Assign one set equal to another set. + + \param this_target + is the index in this svec_setvec object of the set being assinged. + + \param other_source + is the index in the other svec_setvec object of the + set that we are using as the value to assign to the target set. + + \param other + is the other svec_setvec object (which may be the same as this + svec_setvec object). This must have the same value for end_. + + \par data_not_used_ + increments this value by number of elements lost. + */ + void assignment( + size_t this_target , + size_t other_source , + const svec_setvec& other ) + { CPPAD_ASSERT_UNKNOWN( other.post_[ other_source ] == 0 ); + // + CPPAD_ASSERT_UNKNOWN( this_target < start_.size() ); + CPPAD_ASSERT_UNKNOWN( other_source < other.start_.size() ); + CPPAD_ASSERT_UNKNOWN( end_ == other.end_ ); + + // check if we are assigning a set to itself + if( (this == &other) & (this_target == other_source) ) + return; + + // number of elements that will be deleted by this operation + size_t number_lost = drop(this_target); + + // drop any posting for the target set + size_t post = post_[this_target]; + if( post > 0 ) + { // do not need to worry about target being same as source + size_t capacity = data_[post + 1]; + number_lost += capacity + 2; + post_[this_target] = 0; + } + + // If this and other are the same, use another reference to same list + size_t other_start = other.start_[other_source]; + if( this == &other ) + { CPPAD_ASSERT_UNKNOWN( this_target != other_source ); + start_[this_target] = other_start; + if( other_start != 0 ) + { // increment reference count + data_[other_start]++; + } + } + else if( other_start == 0 ) + { // the target list is empty + start_[this_target] = 0; + } + else + { // make a copy of the other list in this svec_setvec + size_t length = other.data_[other_start + 1]; + size_t this_start = data_.extend(2); + start_[this_target] = this_start; + data_[this_start] = 1; // reference count + data_[this_start + 1] = length; // length + for(size_t j = 0; j < length; ++j) + data_.push_back( other.data_[other_start + 2 + j] ); + data_.push_back(end_); + } + + // adjust data_not_used_ + data_not_used_ += number_lost; + collect_garbage(); + } + // ----------------------------------------------------------------- + /*! + Assign a set equal to the union of two other sets. + + \param this_target + is the index in this svec_setvec object of the set being assinged. + + \param this_left + is the index in this svec_setvec object of the + left operand for the union operation. + It is OK for this_target and this_left to be the same value. + + \param other_right + is the index in the other svec_setvec object of the + right operand for the union operation. + It is OK for this_target and other_right to be the same value. + + \param other + is the other svec_setvec object (which may be the same as this + svec_setvec object). + */ + void binary_union( + size_t this_target , + size_t this_left , + size_t other_right , + const svec_setvec& other ) + { CPPAD_ASSERT_UNKNOWN( post_[this_left] == 0 ); + CPPAD_ASSERT_UNKNOWN( other.post_[ other_right ] == 0 ); + // + CPPAD_ASSERT_UNKNOWN( this_target < start_.size() ); + CPPAD_ASSERT_UNKNOWN( this_left < start_.size() ); + CPPAD_ASSERT_UNKNOWN( other_right < other.start_.size() ); + CPPAD_ASSERT_UNKNOWN( end_ == other.end_ ); + + // check if one of the two operands is a subset of the the other + size_t subset = is_subset(this_left, other_right, other); + + // case where right is a subset of left or right and left are equal + if( subset == 2 || subset == 3 ) + { assignment(this_target, this_left, *this); + return; + } + // case where the left is a subset of right and they are not equal + if( subset == 1 ) + { assignment(this_target, other_right, other); + return; + } + // if niether case holds, then both left and right are non-empty + CPPAD_ASSERT_UNKNOWN( reference_count(this_left) > 0 ); + CPPAD_ASSERT_UNKNOWN( other.reference_count(other_right) > 0 ); + + // must get all the start indices before modify start_this + // (in case start_this is the same as start_left or start_right) + size_t start_left = start_[this_left]; + size_t start_right = other.start_[other_right]; + + // number of list elements that will be deleted by this operation + size_t number_lost = drop(this_target); + + // drop any posting for the target set + size_t post = post_[this_target]; + if( post > 0 ) + { // do not need to worry about target being same as left or right + size_t capacity = data_[post + 1]; + number_lost += capacity + 2; + post_[this_target] = 0; + } + + // start the new list + size_t start = data_.extend(2); + start_[this_target] = start; + data_[start] = 1; // reference count + // data_[start + 1] = length is not yet known + + // initilaize left + CPPAD_ASSERT_UNKNOWN( start_left != 0 ); + size_t current_left = start_left + 2; + size_t value_left = data_[current_left]; + CPPAD_ASSERT_UNKNOWN( value_left < end_ ); + + // initilaize right + CPPAD_ASSERT_UNKNOWN( start_right != 0 ); + size_t current_right = start_right + 2; + size_t value_right = other.data_[current_right]; + CPPAD_ASSERT_UNKNOWN( value_right < end_ ); + + + CPPAD_ASSERT_UNKNOWN( value_left < end_ && value_right < end_ ); + while( (value_left < end_) | (value_right < end_) ) + { if( value_left == value_right ) + { // advance right so left and right are no longer equal + ++current_right; + value_right = other.data_[current_right]; + } + if( value_left < value_right ) + { data_.push_back( value_left ); + // advance left to its next element + ++current_left; + value_left = data_[current_left]; + } + else + { CPPAD_ASSERT_UNKNOWN( value_right < value_left ) + data_.push_back( value_right ); + // advance right to its next element + ++current_right; + value_right = other.data_[current_right]; + } + } + // make end of target list + data_.push_back( end_ ); + // + // reference count, length, and end_ are not elements of set + CPPAD_ASSERT_UNKNOWN( data_.size() > start + 3 ); + size_t length = data_.size() - (start + 3); + data_[start + 1] = length; + + // adjust data_not_used_ + data_not_used_ += number_lost; + collect_garbage(); + } + // ----------------------------------------------------------------- + /*! + Assign a set equal to the intersection of two other sets. + + \param this_target + is the index in this svec_setvec object of the set being assinged. + + \param this_left + is the index in this svec_setvec object of the + left operand for the intersection operation. + It is OK for this_target and this_left to be the same value. + + \param other_right + is the index in the other svec_setvec object of the + right operand for the intersection operation. + It is OK for this_target and other_right to be the same value. + + \param other + is the other svec_setvec object (which may be the same as this + svec_setvec object). + */ + void binary_intersection( + size_t this_target , + size_t this_left , + size_t other_right , + const svec_setvec& other ) + { CPPAD_ASSERT_UNKNOWN( post_[this_left] == 0 ); + CPPAD_ASSERT_UNKNOWN( other.post_[ other_right ] == 0 ); + // + CPPAD_ASSERT_UNKNOWN( this_target < start_.size() ); + CPPAD_ASSERT_UNKNOWN( this_left < start_.size() ); + CPPAD_ASSERT_UNKNOWN( other_right < other.start_.size() ); + CPPAD_ASSERT_UNKNOWN( end_ == other.end_ ); + // + // check if one of the two operands is a subset of the the other + size_t subset = is_subset(this_left, other_right, other); + + // case where left is a subset of right or left and right are equal + if( subset == 1 || subset == 3 ) + { assignment(this_target, this_left, *this); + return; + } + // case where the right is a subset of left and they are not equal + if( subset == 2 ) + { assignment(this_target, other_right, other); + return; + } + // if niether case holds, then both left and right are non-empty + CPPAD_ASSERT_UNKNOWN( reference_count(this_left) > 0 ); + CPPAD_ASSERT_UNKNOWN( other.reference_count(other_right) > 0 ); + + // must get all the start indices before modify start_this + // (in case start_this is the same as start_left or start_right) + size_t start_left = start_[this_left]; + size_t start_right = other.start_[other_right]; + + + // number of list elements that will be deleted by this operation + size_t number_lost = drop(this_target); + + // drop any posting for the target set + size_t post = post_[this_target]; + if( post > 0 ) + { // do not need to worry about target being same as left or right + size_t capacity = data_[post + 1]; + number_lost += capacity + 2; + post_[this_target] = 0; + } + + // initialize intersection as empty + size_t start = 0; + start_[this_target] = start; + + // initilaize left + CPPAD_ASSERT_UNKNOWN( start_left != 0 ); + size_t current_left = start_left + 2; + size_t value_left = data_[current_left]; + CPPAD_ASSERT_UNKNOWN( value_left < end_ ); + + // initilaize right + CPPAD_ASSERT_UNKNOWN( start_right != 0 ); + size_t current_right = start_right + 2; + size_t value_right = other.data_[current_right]; + CPPAD_ASSERT_UNKNOWN( value_right < end_ ); + + while( (value_left < end_) & (value_right < end_) ) + { if( value_left == value_right ) + { if( start == 0 ) + { // this is the first element in the intersection + start = data_.extend(2); + start_[this_target] = start; + data_[start] = 1; // reference count + // data_[start + 1] = length is not yet known + } + data_.push_back( value_left ); + // + // advance left to its next element + ++current_left; + value_left = data_[current_left]; + } + if( value_left > value_right ) + { // advance right + ++current_right; + value_right = other.data_[current_right]; + } + if( value_right > value_left ) + { // advance left + ++current_left; + value_left = data_[current_left]; + } + } + if( start != 0 ) + { data_.push_back(end_); + CPPAD_ASSERT_UNKNOWN( data_.size() > start + 3 ); + size_t length = data_.size() - (start + 3); + data_[start + 1] = length; + } + + // adjust data_not_used_ + data_not_used_ += number_lost; + collect_garbage(); + } + // ----------------------------------------------------------------- + /*! Fetch n_set for vector of sets object. + + \return + Number of from sets for this vector of sets object + */ + size_t n_set(void) const + { return start_.size(); } + // ----------------------------------------------------------------- + /*! Fetch end for this vector of sets object. + + \return + is the maximum element value plus one (the minimum element value is 0). + */ + size_t end(void) const + { return end_; } + // ----------------------------------------------------------------- + /*! Amount of memory used by this vector of sets + + \return + The amount of memory in units of type unsigned char memory. + */ + size_t memory(void) const + { return data_.capacity() * sizeof(size_t); + } + /*! + Print the vector of sets (used for debugging) + */ + void print(void) const; +}; +// ========================================================================= +/*! +cons_iterator for one set of positive integers in a svec_setvec object. + +All the public member functions for this class are also in the +sparse::pack_setvec_const_iterator and sparse::list_setvec_const_iterator classes. +This defines the CppAD vector_of_sets iterator concept. +*/ +class svec_setvec_const_iterator { +private: + /// data for the entire vector of sets + const pod_vector& data_; + + /// Possible elements in a list are 0, 1, ..., end_ - 1; + const size_t end_; + + /// data index of next entry, zero for no more entries + size_t data_index_; +public: + /// construct a const_iterator for a set in a svec_setvec object + svec_setvec_const_iterator (const svec_setvec& vec_set, size_t i) + : + data_( vec_set.data_ ) , + end_ ( vec_set.end_ ) + { CPPAD_ASSERT_UNKNOWN( vec_set.post_[i] == 0 ); + // + size_t start = vec_set.start_[i]; + if( start == 0 ) + { data_index_ = 0; + } + else + { // data index of the first element in the set + data_index_ = start + 2; + CPPAD_ASSERT_UNKNOWN( data_[data_index_] < end_ ); + } + } + + /// advance to next element in this list + svec_setvec_const_iterator& operator++(void) + { if( data_index_ != 0 ) + { ++data_index_; + if( data_[data_index_] == end_ ) + data_index_ = 0; + } + return *this; + } + + /// obtain value of this element of the set of positive integers + /// (end_ for no such element) + size_t operator*(void) + { if( data_index_ == 0 ) + return end_; + return data_[data_index_]; + } +}; +// ========================================================================= +/*! +Print the vector of sets (used for debugging) +*/ +inline void svec_setvec::print(void) const +{ std::cout << "svec_setvec:\n"; + for(size_t i = 0; i < n_set(); i++) + { std::cout << "set[" << i << "] = {"; + const_iterator itr(*this, i); + while( *itr != end() ) + { std::cout << *itr; + if( *(++itr) != end() ) + std::cout << ","; + } + std::cout << "}\n"; + } + return; +} + +/*! +Copy a user vector of sets sparsity pattern to an internal svec_setvec object. + +\tparam SetVector +is a simple vector with elements of type std::set. + +\param internal +The input value of sparisty does not matter. +Upon return it contains the same sparsity pattern as user +(or the transposed sparsity pattern). + +\param user +sparsity pattern that we are placing internal. + +\param n_set +number of sets (rows) in the internal sparsity pattern. + +\param end +end of set value (number of columns) in the interanl sparsity pattern. + +\param transpose +if true, the user sparsity patter is the transposed. + +\param error_msg +is the error message to display if some values in the user sparstiy +pattern are not valid. +*/ +template +void sparsity_user2internal( + svec_setvec& internal , + const SetVector& user , + size_t n_set , + size_t end , + bool transpose , + const char* error_msg ) +{ +# ifndef NDEBUG + if( transpose ) + CPPAD_ASSERT_KNOWN( end == size_t( user.size() ), error_msg); + if( ! transpose ) + CPPAD_ASSERT_KNOWN( n_set == size_t( user.size() ), error_msg); +# endif + + // iterator for user set + std::set::const_iterator itr; + + // size of internal sparsity pattern + internal.resize(n_set, end); + + if( transpose ) + { // transposed pattern case + for(size_t j = 0; j < end; j++) + { itr = user[j].begin(); + while(itr != user[j].end()) + { size_t i = *itr++; + CPPAD_ASSERT_KNOWN(i < n_set, error_msg); + internal.add_element(i, j); + } + } + } + else + { for(size_t i = 0; i < n_set; i++) + { itr = user[i].begin(); + while(itr != user[i].end()) + { size_t j = *itr++; + CPPAD_ASSERT_KNOWN( j < end, error_msg); + internal.add_element(i, j); + } + } + } + return; +} + +} } } // END_CPPAD_LOCAL_SPARSE_NAMESPACE +# endif diff --git a/build-config/cppad/include/cppad/local/sparse/unary_op.hpp b/build-config/cppad/include/cppad/local/sparse/unary_op.hpp new file mode 100644 index 00000000..f2e5383a --- /dev/null +++ b/build-config/cppad/include/cppad/local/sparse/unary_op.hpp @@ -0,0 +1,317 @@ +# ifndef CPPAD_LOCAL_SPARSE_UNARY_OP_HPP +# define CPPAD_LOCAL_SPARSE_UNARY_OP_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +// BEGIN_CPPAD_LOCAL_SPARSE_NAMESPACE +namespace CppAD { namespace local { namespace sparse { +/*! +\file sparse_unary_op.hpp +Forward and reverse mode sparsity patterns for unary operators. +*/ + + +/*! +Forward mode Jacobian sparsity pattern for all unary operators. + +The C++ source code corresponding to a unary operation has the form +\verbatim + z = fun(x) +\endverbatim +where fun is a C++ unary function, or it has the form +\verbatim + z = x op q +\endverbatim +where op is a C++ binary unary operator and q is a parameter. + +\tparam Vector_set +is the type used for vectors of sets. It can be either +sparse::pack_setvec or sparse::list_setvec. + +\param i_z +variable index corresponding to the result for this operation; +i.e., z. + +\param i_x +variable index corresponding to the argument for this operator; +i.e., x. + + +\param sparsity +\b Input: The set with index arg[0] in sparsity +is the sparsity bit pattern for x. +This identifies which of the independent variables the variable x +depends on. +\n +\n +\b Output: The set with index i_z in sparsity +is the sparsity bit pattern for z. +This identifies which of the independent variables the variable z +depends on. +\n + +\par Checked Assertions: +\li i_x < i_z +*/ + +template +void for_jac_unary_op( + size_t i_z , + size_t i_x , + Vector_set& sparsity ) +{ + // check assumptions + CPPAD_ASSERT_UNKNOWN( i_x < i_z ); + + sparsity.assignment(i_z, i_x, sparsity); +} +/*! +Reverse mode Jacobian sparsity pattern for all unary operators. + +The C++ source code corresponding to a unary operation has the form +\verbatim + z = fun(x) +\endverbatim +where fun is a C++ unary function, or it has the form +\verbatim + z = x op q +\endverbatim +where op is a C++ bianry operator and q is a parameter. + +This routine is given the sparsity patterns +for a function G(z, y, ... ) +and it uses them to compute the sparsity patterns for +\verbatim + H( x , w , u , ... ) = G[ z(x) , x , w , u , ... ] +\endverbatim + +\tparam Vector_set +is the type used for vectors of sets. It can be either +sparse::pack_setvec or sparse::list_setvec. + + +\param i_z +variable index corresponding to the result for this operation; +i.e. the row index in sparsity corresponding to z. + +\param i_x +variable index corresponding to the argument for this operator; +i.e. the row index in sparsity corresponding to x. + +\param sparsity +\b Input: +The set with index i_z in sparsity +is the sparsity bit pattern for G with respect to the variable z. +\n +\b Input: +The set with index i_x in sparsity +is the sparsity bit pattern for G with respect to the variable x. +\n +\b Output: +The set with index i_x in sparsity +is the sparsity bit pattern for H with respect to the variable x. + +\par Checked Assertions: +\li i_x < i_z +*/ + +template +void rev_jac_unary_op( + size_t i_z , + size_t i_x , + Vector_set& sparsity ) +{ + // check assumptions + CPPAD_ASSERT_UNKNOWN( i_x < i_z ); + + sparsity.binary_union(i_x, i_x, i_z, sparsity); + + return; +} +// --------------------------------------------------------------------------- +/*! +Reverse mode Hessian sparsity pattern for linear unary operators. + +The C++ source code corresponding to this operation is +\verbatim + z = fun(x) +\endverbatim +where fun is a linear functions; e.g. abs, or +\verbatim + z = x op q +\endverbatim +where op is a C++ binary operator and q is a parameter. + +\copydetails CppAD::local::reverse_sparse_hessian_unary_op +*/ +template +void rev_hes_lin_unary_op( + size_t i_z , + size_t i_x , + bool* rev_jacobian , + const Vector_set& for_jac_sparsity , + Vector_set& rev_hes_sparsity ) +{ + // check assumptions + CPPAD_ASSERT_UNKNOWN( i_x < i_z ); + + // check for no effect + if( ! rev_jacobian[i_z] ) + return; + + rev_hes_sparsity.binary_union(i_x, i_x, i_z, rev_hes_sparsity); + + rev_jacobian[i_x] = true; + return; +} + +/*! +Reverse mode Hessian sparsity pattern for non-linear unary operators. + +The C++ source code corresponding to this operation is +\verbatim + z = fun(x) +\endverbatim +where fun is a non-linear functions; e.g. sin. or +\verbatim + z = q / x +\endverbatim +where q is a parameter. + + +\copydetails CppAD::local::reverse_sparse_hessian_unary_op +*/ +template +void rev_hes_nl_unary_op( + size_t i_z , + size_t i_x , + bool* rev_jacobian , + const Vector_set& for_jac_sparsity , + Vector_set& rev_hes_sparsity ) +{ + // check assumptions + CPPAD_ASSERT_UNKNOWN( i_x < i_z ); + + // check for no effect + if( ! rev_jacobian[i_z] ) + return; + + rev_hes_sparsity.binary_union(i_x, i_x, i_z, rev_hes_sparsity); + rev_hes_sparsity.binary_union(i_x, i_x, i_x, for_jac_sparsity); + + rev_jacobian[i_x] = true; + return; +} +// --------------------------------------------------------------------------- +/* +$begin for_hes_nl_unary_op$$ +$spell + hes + nl + op + np + numvar + Jacobian +$$ + +$section Forward Hessian Sparsity for Non-linear Unary Operators$$ + +$head Syntax$$ +$codei%local::for_hes_nl_unary_op( + %np1%, %numvar%, %i_v%, %for_sparsity% +)%$$ + +$head Prototype$$ +$srcthisfile% + 0%// BEGIN_for_hes_nl_unary_op%// END_for_hes_nl_unary_op%1 +%$$ + +$head C++ Source$$ +The C++ source code corresponding to this operation is +$codei% + %w% = %fun%( %v% ) +%$$ +where $icode fun$$ is a non-linear function. + +$head np1$$ +This is the number of independent variables plus one; +i.e. size of $icode x$$ plus one. + +$head numvar$$ +This is the total number of variables in the tape. + +$head i_w$$ +is the index of the variable corresponding to the result $icode w$$. + +$head i_v$$ +is the index of the variable corresponding to the argument $icode v$$. + +$head for_sparsity$$ +We have the conditions $icode%np1% = %for_sparsity%.end()%$$ +and $icode%for_sparsity%.n_set() = %np1% + %numvar%$$. + +$subhead Input Jacobian Sparsity$$ +For $icode%i%= 0, ..., %i_w%-1%$$, +the $icode%np1%+%i%$$ row of $icode for_sparsity$$ is the Jacobian sparsity +for the $th i$$ variable. These values do not change. +Note that $icode%i%=0%$$ corresponds to a parameter and +the corresponding Jacobian sparsity is empty. + +$subhead Input Hessian Sparsity$$ +For $icode%j%=1, ..., %n%$$, +the $th j$$ row of $icode for_sparsity$$ is the Hessian sparsity +before including the function $latex w(x)$$. + +$subhead Output Jacobian Sparsity$$ +the $icode i_w$$ row of $icode for_sparsity$$ is the Jacobian sparsity +for the variable $icode w$$. + +$subhead Output Hessian Sparsity$$ +For $icode%j%=1, ..., %n%$$, +the $th j$$ row of $icode for_sparsity$$ is the Hessian sparsity +after including the function $latex w(x)$$. + +$end +*/ +// BEGIN_for_hes_nl_unary_op +template +void for_hes_nl_unary_op( + size_t np1 , + size_t numvar , + size_t i_w , + size_t i_v , + Vector_set& for_sparsity ) +// END_for_hes_nl_unary_op +{ CPPAD_ASSERT_UNKNOWN( i_v < i_w ); + CPPAD_ASSERT_UNKNOWN( i_w < numvar ); + CPPAD_ASSERT_UNKNOWN( for_sparsity.end() == np1 ); + CPPAD_ASSERT_UNKNOWN( for_sparsity.n_set() == np1 + numvar ); + CPPAD_ASSERT_UNKNOWN( for_sparsity.number_elements(np1) == 0 ); + + // set Jacobian sparsity J(i_w) + for_sparsity.assignment(np1 + i_w, np1 + i_v, for_sparsity); + + // set of independent variables that v depends on + typename Vector_set::const_iterator itr(for_sparsity, i_v + np1); + + // loop over independent variables with non-zero partial for v + size_t i_x = *itr; + while( i_x < np1 ) + { // N(i_x) = N(i_x) union J(i_v) + for_sparsity.binary_union(i_x, i_x, i_v + np1, for_sparsity); + i_x = *(++itr); + } + return; +} + +} } } // END_CPPAD_LOCAL_SPARSE_NAMESPACE +# endif diff --git a/build-config/cppad/include/cppad/local/sqrt_op.hpp b/build-config/cppad/include/cppad/local/sqrt_op.hpp new file mode 100644 index 00000000..a99ea5e9 --- /dev/null +++ b/build-config/cppad/include/cppad/local/sqrt_op.hpp @@ -0,0 +1,193 @@ +# ifndef CPPAD_LOCAL_SQRT_OP_HPP +# define CPPAD_LOCAL_SQRT_OP_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-17 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + + +namespace CppAD { namespace local { // BEGIN_CPPAD_LOCAL_NAMESPACE +/*! +\file sqrt_op.hpp +Forward and reverse mode calculations for z = sqrt(x). +*/ + + +/*! +Compute forward mode Taylor coefficient for result of op = SqrtOp. + +The C++ source code corresponding to this operation is +\verbatim + z = sqrt(x) +\endverbatim + +\copydetails CppAD::local::forward_unary1_op +*/ +template +void forward_sqrt_op( + size_t p , + size_t q , + size_t i_z , + size_t i_x , + size_t cap_order , + Base* taylor ) +{ + // check assumptions + CPPAD_ASSERT_UNKNOWN( NumArg(SqrtOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( NumRes(SqrtOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( q < cap_order ); + CPPAD_ASSERT_UNKNOWN( p <= q ); + + // Taylor coefficients corresponding to argument and result + Base* x = taylor + i_x * cap_order; + Base* z = taylor + i_z * cap_order; + + size_t k; + if( p == 0 ) + { z[0] = sqrt( x[0] ); + p++; + } + for(size_t j = p; j <= q; j++) + { + z[j] = Base(0.0); + for(k = 1; k < j; k++) + z[j] -= Base(double(k)) * z[k] * z[j-k]; + z[j] /= Base(double(j)); + z[j] += x[j] / Base(2.0); + z[j] /= z[0]; + } +} + +/*! +Multiple direction forward mode Taylor coefficient for op = SqrtOp. + +The C++ source code corresponding to this operation is +\verbatim + z = sqrt(x) +\endverbatim + +\copydetails CppAD::local::forward_unary1_op_dir +*/ +template +void forward_sqrt_op_dir( + size_t q , + size_t r , + size_t i_z , + size_t i_x , + size_t cap_order , + Base* taylor ) +{ + // check assumptions + CPPAD_ASSERT_UNKNOWN( NumArg(SqrtOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( NumRes(SqrtOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( 0 < q ); + CPPAD_ASSERT_UNKNOWN( q < cap_order ); + + // Taylor coefficients corresponding to argument and result + size_t num_taylor_per_var = (cap_order-1) * r + 1; + Base* z = taylor + i_z * num_taylor_per_var; + Base* x = taylor + i_x * num_taylor_per_var; + + size_t m = (q-1) * r + 1; + for(size_t ell = 0; ell < r; ell++) + { z[m+ell] = Base(0.0); + for(size_t k = 1; k < q; k++) + z[m+ell] -= Base(double(k)) * z[(k-1)*r+1+ell] * z[(q-k-1)*r+1+ell]; + z[m+ell] /= Base(double(q)); + z[m+ell] += x[m+ell] / Base(2.0); + z[m+ell] /= z[0]; + } +} + +/*! +Compute zero order forward mode Taylor coefficient for result of op = SqrtOp. + +The C++ source code corresponding to this operation is +\verbatim + z = sqrt(x) +\endverbatim + +\copydetails CppAD::local::forward_unary1_op_0 +*/ +template +void forward_sqrt_op_0( + size_t i_z , + size_t i_x , + size_t cap_order , + Base* taylor ) +{ + // check assumptions + CPPAD_ASSERT_UNKNOWN( NumArg(SqrtOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( NumRes(SqrtOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( 0 < cap_order ); + + // Taylor coefficients corresponding to argument and result + Base* x = taylor + i_x * cap_order; + Base* z = taylor + i_z * cap_order; + + z[0] = sqrt( x[0] ); +} +/*! +Compute reverse mode partial derivatives for result of op = SqrtOp. + +The C++ source code corresponding to this operation is +\verbatim + z = sqrt(x) +\endverbatim + +\copydetails CppAD::local::reverse_unary1_op +*/ + +template +void reverse_sqrt_op( + size_t d , + size_t i_z , + size_t i_x , + size_t cap_order , + const Base* taylor , + size_t nc_partial , + Base* partial ) +{ + // check assumptions + CPPAD_ASSERT_UNKNOWN( NumArg(SqrtOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( NumRes(SqrtOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( d < cap_order ); + CPPAD_ASSERT_UNKNOWN( d < nc_partial ); + + // Taylor coefficients and partials corresponding to argument + Base* px = partial + i_x * nc_partial; + + // Taylor coefficients and partials corresponding to result + const Base* z = taylor + i_z * cap_order; + Base* pz = partial + i_z * nc_partial; + + + Base inv_z0 = Base(1.0) / z[0]; + + // number of indices to access + size_t j = d; + size_t k; + while(j) + { + + // scale partial w.r.t. z[j] + pz[j] = azmul(pz[j], inv_z0); + + pz[0] -= azmul(pz[j], z[j]); + px[j] += pz[j] / Base(2.0); + for(k = 1; k < j; k++) + pz[k] -= azmul(pz[j], z[j-k]); + --j; + } + px[0] += azmul(pz[0], inv_z0) / Base(2.0); +} + +} } // END_CPPAD_LOCAL_NAMESPACE +# endif diff --git a/build-config/cppad/include/cppad/local/std_set.hpp b/build-config/cppad/include/cppad/local/std_set.hpp new file mode 100644 index 00000000..a894fe3b --- /dev/null +++ b/build-config/cppad/include/cppad/local/std_set.hpp @@ -0,0 +1,52 @@ +# ifndef CPPAD_LOCAL_STD_SET_HPP +# define CPPAD_LOCAL_STD_SET_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-18 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +# include + +// needed before one can use CPPAD_ASSERT_FIRST_CALL_NOT_PARALLEL +# include + +namespace CppAD { namespace local { // BEGIN_CPPAD_LOCAL_NAMESPACE +/*! +\file std_set.hpp +Two constant standard sets (currently used for concept checking). +*/ + +/*! +A standard set with one element. +*/ +template +const std::set& one_element_std_set(void) +{ CPPAD_ASSERT_FIRST_CALL_NOT_PARALLEL; + static std::set one; + if( one.empty() ) + one.insert(1); + return one; +} +/*! +A standard set with a two elements. +*/ +template +const std::set& two_element_std_set(void) +{ CPPAD_ASSERT_FIRST_CALL_NOT_PARALLEL; + static std::set two; + if( two.empty() ) + { two.insert(1); + two.insert(2); + } + return two; +} + +} } // END_CPPAD_LOCAL_NAMESPACE +# endif diff --git a/build-config/cppad/include/cppad/local/store_op.hpp b/build-config/cppad/include/cppad/local/store_op.hpp new file mode 100644 index 00000000..f7989bbb --- /dev/null +++ b/build-config/cppad/include/cppad/local/store_op.hpp @@ -0,0 +1,489 @@ +# ifndef CPPAD_LOCAL_STORE_OP_HPP +# define CPPAD_LOCAL_STORE_OP_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +namespace CppAD { namespace local { // BEGIN_CPPAD_LOCAL_NAMESPACE +/* +$begin store_op_var$$ +$spell + pv + vp + vv + Vec + op + var + isvar + ind + Taylor + arg + num + Addr +$$ +$section Changing an Element in a Variable VecAD Vector$$ + +$head See Also$$ +$cref/op_code_var store/op_code_var/Store/$$. + +$head Syntax$$ +$codei%forward_store_%IV%_op_0( + %i_z%, + %arg%, + %num_par%, + %parameter%, + %cap_order%, + %taylor%, + %vec_ad2isvar%, + %vec_ad2index% +) +%$$ +where the index type $icode I$$ and the value being stored type $icode V$$ +are $code p$$ (for parameter) or $code v$$ (for variable). + +$head Prototype$$ +$srcthisfile% + 0%// BEGIN_FORWARD_STORE_PP_OP_0%// END_FORWARD_STORE_PP_OP_0%1 +%$$ +The prototype for +$code forward_store_pv_op_0$$, +$code forward_store_vp_op_0$$, and +$code forward_store_vv_op_0$$, +are the same except for the function name. + +$head Notation$$ + +$subhead v$$ +We use $icode v$$ to denote the $cref VecAD$$ vector for this operation. + +$subhead x$$ +We use $icode x$$ to denote the $codei%AD%<%Base%>%$$ +index for this operation. + +$subhead i_vec$$ +We use $icode i_vec$$ to denote the $code size_t$$ value +corresponding to $icode x$$. + +$subhead n_load$$ +This is the number of load instructions in this recording. + +$subhead n_all$$ +This is the number of values in the single array that includes +all the vectors together with the size of each vector. + +$head Base$$ +base type for the operator; i.e., this operation was recorded +using AD and computations by this routine are done using type Base. + +$head i_z$$ +is the AD variable index corresponding to the result of this load operation. + +$head arg$$ + +$subhead arg[0]$$ +is the offset of this VecAD vector relative to the beginning +of the $icode vec_ad2isvar$$ and $icode vec_ad2index$$ arrays. + +$subhead arg[1]$$ +If this is +$code forward_load_p_op_0$$ ($code forward_load_v_op_0$$) +$icode%arg%[%1%]%$$ is the parameter index (variable index) +corresponding to $cref/i_vec/load_op_var/Notation/i_vec/$$. + +$subhead arg[2]$$ +Is the index of this VecAD load instruction in the +$icode load_op2var$$ array. + +$head num_par$$ +is the number of parameters in this recording. + +$head parameter$$ +This is the vector of parameters for this recording which has size +$icode num_par$$. + +$head cap_order$$ +number of columns in the matrix containing the Taylor coefficients. + +$head taylor$$ +Is the matrix of Taylor coefficients for all the variables. + +$head vec_ad2isvar$$ +This vector has size $icode n_all$$ and +the input values of its elements does not matter. +If the value being stored is a parameter (variable), +$icode%vec_ad2isvar%[ %arg%[0] + %i_vec% ]%$$ +is set to false (true). + +$head vec_ad2index$$ +This array has size $icode n_all$$ +and the input value of its elements does not matter. +If the value being stored is a parameter (variable), +$icode%vec_ad2index%[ %arg%[0] + %i_vec% ]%$$ +is set to the parameter (variable) index +corresponding to the value being stored. + +$end +*/ +// BEGIN_FORWARD_STORE_PP_OP_0 +template +void forward_store_pp_op_0( + size_t i_z , + const addr_t* arg , + size_t num_par , + const Base* parameter , + size_t cap_order , + const Base* taylor , + bool* vec_ad2isvar , + size_t* vec_ad2index ) +// END_FORWARD_STORE_PP_OP_0 +{ addr_t i_vec = addr_t( Integer( parameter[ arg[1] ] ) ); + CPPAD_ASSERT_KNOWN( + size_t(i_vec) < vec_ad2index[ arg[0] - 1 ] , + "VecAD: zero order forward dynamic parameter index out of range" + ); + CPPAD_ASSERT_UNKNOWN( NumArg(StppOp) == 3 ); + CPPAD_ASSERT_UNKNOWN( NumRes(StppOp) == 0 ); + CPPAD_ASSERT_UNKNOWN( 0 < arg[0] ); + CPPAD_ASSERT_UNKNOWN( size_t(arg[2]) < num_par ); + + vec_ad2isvar[ arg[0] + i_vec ] = false; + vec_ad2index[ arg[0] + i_vec ] = size_t(arg[2]); +} +template +void forward_store_pv_op_0( + size_t i_z , + const addr_t* arg , + size_t num_par , + const Base* parameter , + size_t cap_order , + const Base* taylor , + bool* vec_ad2isvar , + size_t* vec_ad2index ) +{ addr_t i_vec = addr_t( Integer( parameter[ arg[1] ] ) ); + CPPAD_ASSERT_KNOWN( + size_t(i_vec) < vec_ad2index[ arg[0] - 1 ] , + "VecAD: zero order forward dynamic parameter index out of range" + ); + CPPAD_ASSERT_UNKNOWN( NumArg(StpvOp) == 3 ); + CPPAD_ASSERT_UNKNOWN( NumRes(StpvOp) == 0 ); + CPPAD_ASSERT_UNKNOWN( 0 < arg[0] ); + + vec_ad2isvar[ arg[0] + i_vec ] = true; + vec_ad2index[ arg[0] + i_vec ] = size_t(arg[2]); +} +template +void forward_store_vp_op_0( + size_t i_z , + const addr_t* arg , + size_t num_par , + size_t cap_order , + const Base* taylor , + bool* vec_ad2isvar , + size_t* vec_ad2index ) +{ + addr_t i_vec = addr_t(Integer( taylor[ size_t(arg[1]) * cap_order + 0 ] )); + CPPAD_ASSERT_KNOWN( + size_t(i_vec) < vec_ad2index[ arg[0] - 1 ] , + "VecAD: zero order forward variable index out of range" + ); + + CPPAD_ASSERT_UNKNOWN( NumArg(StvpOp) == 3 ); + CPPAD_ASSERT_UNKNOWN( NumRes(StvpOp) == 0 ); + CPPAD_ASSERT_UNKNOWN( 0 < arg[0] ); + CPPAD_ASSERT_UNKNOWN( size_t(arg[2]) < num_par ); + + vec_ad2isvar[ arg[0] + i_vec ] = false; + vec_ad2index[ arg[0] + i_vec ] = size_t(arg[2]); +} +template +void forward_store_vv_op_0( + size_t i_z , + const addr_t* arg , + size_t num_par , + size_t cap_order , + const Base* taylor , + bool* vec_ad2isvar , + size_t* vec_ad2index ) +{ + addr_t i_vec = addr_t(Integer( taylor[ size_t(arg[1]) * cap_order + 0 ] )); + CPPAD_ASSERT_KNOWN( + size_t(i_vec) < vec_ad2index[ arg[0] - 1 ] , + "VecAD: index during zero order forward sweep is out of range" + ); + + CPPAD_ASSERT_UNKNOWN( NumArg(StvpOp) == 3 ); + CPPAD_ASSERT_UNKNOWN( NumRes(StvpOp) == 0 ); + CPPAD_ASSERT_UNKNOWN( 0 < arg[0] ); + + vec_ad2isvar[ arg[0] + i_vec ] = true; + vec_ad2index[ arg[0] + i_vec ] = size_t(arg[2]); +} +// --------------------------------------------------------------------------- +/* +============================================================================== + +The C++ source code corresponding to this operation is +\verbatim + v[x] = y +\endverbatim +where v is a VecAD vector, x is an AD object, +and y is AD or Base objects. +We define the index corresponding to v[x] by +\verbatim + i_v_x = vec_ad2index[ arg[0] + i_vec ] +\endverbatim +where i_vec is defined under the heading arg[1] below: + +============================================================================== +*/ +/*! +Shared documnetation for sparsity operations corresponding to +op = StpvOp or StvvOp (not called). + +\tparam Vector_set +is the type used for vectors of sets. It can be either +sparse::pack_setvec or sparse::list_setvec. + +\param op +is the code corresponding to this operator; +i.e., StpvOp, StvpOp, or StvvOp. + +\param arg +\n + arg[0] +is the offset corresponding to this VecAD vector in the combined array. +\n +\n + arg[2] +\n +The set with index arg[2] in var_sparsity +is the sparsity pattern corresponding to y. +(Note that arg[2] > 0 because y is a variable.) + +\param num_combined +is the total number of elements in the VecAD address array. + +\param combined + combined [ arg[0] - 1 ] +is the index of the set in vecad_sparsity corresponding +to the sparsity pattern for the vector v. +We use the notation i_v below which is defined by +\verbatim + i_v = combined[ arg[0] - 1 ] +\endverbatim + +\param var_sparsity +The set with index arg[2] in var_sparsity +is the sparsity pattern for y. +This is an input for forward mode operations. +For reverse mode operations: +The sparsity pattern for v is added to the spartisy pattern for y. + +\param vecad_sparsity +The set with index i_v in vecad_sparsity +is the sparsity pattern for v. +This is an input for reverse mode operations. +For forward mode operations, the sparsity pattern for y is added +to the sparsity pattern for the vector v. + +\par Checked Assertions +\li NumArg(op) == 3 +\li NumRes(op) == 0 +\li 0 < arg[0] +\li arg[0] < num_combined +\li arg[2] < var_sparsity.n_set() +\li i_v < vecad_sparsity.n_set() +*/ +template +void sparse_store_op( + OpCode op , + const addr_t* arg , + size_t num_combined , + const size_t* combined , + Vector_set& var_sparsity , + Vector_set& vecad_sparsity ) +{ + // This routine is only for documentaiton, it should not be used + CPPAD_ASSERT_UNKNOWN( false ); +} + + + +/*! +Forward mode sparsity operations for StpvOp and StvvOp + + +The C++ source code corresponding to this operation is +\verbatim + v[x] = y +\endverbatim +where v is a VecAD vector, x is an AD object, +and y is AD or Base objects. +We define the index corresponding to v[x] by +\verbatim + i_v_x = vec_ad2index[ arg[0] + i_vec ] +\endverbatim +where i_vec is defined under the heading arg[1] below: + + +\param dependency +is this a dependency (or sparsity) calculation. + +\copydetails CppAD::local::sparse_store_op +*/ +template +void forward_sparse_store_op( + bool dependency , + OpCode op , + const addr_t* arg , + size_t num_combined , + const size_t* combined , + Vector_set& var_sparsity , + Vector_set& vecad_sparsity ) +{ + CPPAD_ASSERT_UNKNOWN( NumArg(op) == 3 ); + CPPAD_ASSERT_UNKNOWN( NumRes(op) == 0 ); + CPPAD_ASSERT_UNKNOWN( 0 < arg[0] ); + CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) < num_combined ); + size_t i_v = combined[ arg[0] - 1 ]; + CPPAD_ASSERT_UNKNOWN( i_v < vecad_sparsity.n_set() ); + CPPAD_ASSERT_UNKNOWN( size_t(arg[2]) < var_sparsity.n_set() ); + + if( dependency & ( (op == StvvOp) | (op == StvpOp) ) ) + vecad_sparsity.binary_union(i_v, i_v, size_t(arg[1]), var_sparsity); + + if( (op == StpvOp) | (op == StvvOp ) ) + vecad_sparsity.binary_union(i_v, i_v, size_t(arg[2]), var_sparsity); + + return; +} + +/*! +Reverse mode sparsity operations for StpvOp, StvpOp, and StvvOp + + +The C++ source code corresponding to this operation is +\verbatim + v[x] = y +\endverbatim +where v is a VecAD vector, x is an AD object, +and y is AD or Base objects. +We define the index corresponding to v[x] by +\verbatim + i_v_x = vec_ad2index[ arg[0] + i_vec ] +\endverbatim +where i_vec is defined under the heading arg[1] below: + + +This routine is given the sparsity patterns for +G(v[x], y , w , u ... ) and it uses them to compute the +sparsity patterns for +\verbatim + H(y , w , u , ... ) = G[ v[x], y , w , u , ... ] +\endverbatim + +\param dependency +is this a dependency (or sparsity) calculation. + +\copydetails CppAD::local::sparse_store_op +*/ +template +void reverse_sparse_jacobian_store_op( + bool dependency , + OpCode op , + const addr_t* arg , + size_t num_combined , + const size_t* combined , + Vector_set& var_sparsity , + Vector_set& vecad_sparsity ) +{ + CPPAD_ASSERT_UNKNOWN( NumArg(op) == 3 ); + CPPAD_ASSERT_UNKNOWN( NumRes(op) == 0 ); + CPPAD_ASSERT_UNKNOWN( 0 < arg[0] ); + CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) < num_combined ); + size_t i_v = combined[ arg[0] - 1 ]; + CPPAD_ASSERT_UNKNOWN( i_v < vecad_sparsity.n_set() ); + CPPAD_ASSERT_UNKNOWN( size_t(arg[2]) < var_sparsity.n_set() ); + + if( dependency & ( (op == StvpOp) | (op == StvvOp) ) ) + var_sparsity.binary_union( size_t(arg[1]), size_t(arg[1]), i_v, vecad_sparsity); + if( (op == StpvOp) | (op == StvvOp) ) + var_sparsity.binary_union( size_t(arg[2]), size_t(arg[2]), i_v, vecad_sparsity); + + return; +} + +/*! +Reverse mode sparsity operations for StpvOp and StvvOp + + +The C++ source code corresponding to this operation is +\verbatim + v[x] = y +\endverbatim +where v is a VecAD vector, x is an AD object, +and y is AD or Base objects. +We define the index corresponding to v[x] by +\verbatim + i_v_x = vec_ad2index[ arg[0] + i_vec ] +\endverbatim +where i_vec is defined under the heading arg[1] below: + + +This routine is given the sparsity patterns for +G(v[x], y , w , u ... ) +and it uses them to compute the sparsity patterns for +\verbatim + H(y , w , u , ... ) = G[ v[x], y , w , u , ... ] +\endverbatim + +\copydetails CppAD::local::sparse_store_op + +\param var_jacobian + var_jacobian[ arg[2] ] +is false (true) if the Jacobian of G with respect to y is always zero +(may be non-zero). + +\param vecad_jacobian + vecad_jacobian[i_v] +is false (true) if the Jacobian with respect to x is always zero +(may be non-zero). +On input, it corresponds to the function G, +and on output it corresponds to the function H. +*/ +template +void reverse_sparse_hessian_store_op( + OpCode op , + const addr_t* arg , + size_t num_combined , + const size_t* combined , + Vector_set& var_sparsity , + Vector_set& vecad_sparsity , + bool* var_jacobian , + bool* vecad_jacobian ) +{ + CPPAD_ASSERT_UNKNOWN( NumArg(op) == 3 ); + CPPAD_ASSERT_UNKNOWN( NumRes(op) == 0 ); + CPPAD_ASSERT_UNKNOWN( 0 < arg[0] ); + CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) < num_combined ); + size_t i_v = combined[ arg[0] - 1 ]; + CPPAD_ASSERT_UNKNOWN( i_v < vecad_sparsity.n_set() ); + CPPAD_ASSERT_UNKNOWN( size_t(arg[2]) < var_sparsity.n_set() ); + + var_sparsity.binary_union( size_t(arg[2]), size_t(arg[2]), i_v, vecad_sparsity); + + var_jacobian[ arg[2] ] |= vecad_jacobian[i_v]; + + return; +} + +} } // END_CPPAD_LOCAL_NAMESPACE +# endif diff --git a/build-config/cppad/include/cppad/local/sub_op.hpp b/build-config/cppad/include/cppad/local/sub_op.hpp new file mode 100644 index 00000000..23c373ef --- /dev/null +++ b/build-config/cppad/include/cppad/local/sub_op.hpp @@ -0,0 +1,500 @@ +# ifndef CPPAD_LOCAL_SUB_OP_HPP +# define CPPAD_LOCAL_SUB_OP_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-18 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +namespace CppAD { namespace local { // BEGIN_CPPAD_LOCAL_NAMESPACE +/*! +\file sub_op.hpp +Forward and reverse mode calculations for z = x - y. +*/ + +// --------------------------- Subvv ----------------------------------------- +/*! +Compute forward mode Taylor coefficients for result of op = SubvvOp. + +The C++ source code corresponding to this operation is +\verbatim + z = x - y +\endverbatim +In the documentation below, +this operations is for the case where both x and y are variables +and the argument parameter is not used. + +\copydetails CppAD::local::forward_binary_op +*/ + +template +void forward_subvv_op( + size_t p , + size_t q , + size_t i_z , + const addr_t* arg , + const Base* parameter , + size_t cap_order , + Base* taylor ) +{ + // check assumptions + CPPAD_ASSERT_UNKNOWN( NumArg(SubvvOp) == 2 ); + CPPAD_ASSERT_UNKNOWN( NumRes(SubvvOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( q < cap_order ); + CPPAD_ASSERT_UNKNOWN( p <= q ); + + // Taylor coefficients corresponding to arguments and result + Base* x = taylor + size_t(arg[0]) * cap_order; + Base* y = taylor + size_t(arg[1]) * cap_order; + Base* z = taylor + i_z * cap_order; + + for(size_t d = p; d <= q; d++) + z[d] = x[d] - y[d]; +} +/*! +Multiple directions forward mode Taylor coefficients for op = SubvvOp. + +The C++ source code corresponding to this operation is +\verbatim + z = x - y +\endverbatim +In the documentation below, +this operations is for the case where both x and y are variables +and the argument parameter is not used. + +\copydetails CppAD::local::forward_binary_op_dir +*/ + +template +void forward_subvv_op_dir( + size_t q , + size_t r , + size_t i_z , + const addr_t* arg , + const Base* parameter , + size_t cap_order , + Base* taylor ) +{ + // check assumptions + CPPAD_ASSERT_UNKNOWN( NumArg(SubvvOp) == 2 ); + CPPAD_ASSERT_UNKNOWN( NumRes(SubvvOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( 0 < q ); + CPPAD_ASSERT_UNKNOWN( q < cap_order ); + + // Taylor coefficients corresponding to arguments and result + size_t num_taylor_per_var = (cap_order-1) * r + 1; + size_t m = (q-1) * r + 1; + Base* x = taylor + size_t(arg[0]) * num_taylor_per_var + m; + Base* y = taylor + size_t(arg[1]) * num_taylor_per_var + m; + Base* z = taylor + i_z * num_taylor_per_var + m; + + for(size_t ell = 0; ell < r; ell++) + z[ell] = x[ell] - y[ell]; +} + +/*! +Compute zero order forward mode Taylor coefficients for result of op = SubvvOp. + +The C++ source code corresponding to this operation is +\verbatim + z = x - y +\endverbatim +In the documentation below, +this operations is for the case where both x and y are variables +and the argument parameter is not used. + +\copydetails CppAD::local::forward_binary_op_0 +*/ + +template +void forward_subvv_op_0( + size_t i_z , + const addr_t* arg , + const Base* parameter , + size_t cap_order , + Base* taylor ) +{ + // check assumptions + CPPAD_ASSERT_UNKNOWN( NumArg(SubvvOp) == 2 ); + CPPAD_ASSERT_UNKNOWN( NumRes(SubvvOp) == 1 ); + + // Taylor coefficients corresponding to arguments and result + Base* x = taylor + size_t(arg[0]) * cap_order; + Base* y = taylor + size_t(arg[1]) * cap_order; + Base* z = taylor + i_z * cap_order; + + z[0] = x[0] - y[0]; +} + +/*! +Compute reverse mode partial derivatives for result of op = SubvvOp. + +The C++ source code corresponding to this operation is +\verbatim + z = x - y +\endverbatim +In the documentation below, +this operations is for the case where both x and y are variables +and the argument parameter is not used. + +\copydetails CppAD::local::reverse_binary_op +*/ + +template +void reverse_subvv_op( + size_t d , + size_t i_z , + const addr_t* arg , + const Base* parameter , + size_t cap_order , + const Base* taylor , + size_t nc_partial , + Base* partial ) +{ + // check assumptions + CPPAD_ASSERT_UNKNOWN( NumArg(SubvvOp) == 2 ); + CPPAD_ASSERT_UNKNOWN( NumRes(SubvvOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( d < cap_order ); + CPPAD_ASSERT_UNKNOWN( d < nc_partial ); + + // Partial derivatives corresponding to arguments and result + Base* px = partial + size_t(arg[0]) * nc_partial; + Base* py = partial + size_t(arg[1]) * nc_partial; + Base* pz = partial + i_z * nc_partial; + + // number of indices to access + size_t i = d + 1; + while(i) + { --i; + px[i] += pz[i]; + py[i] -= pz[i]; + } +} + +// --------------------------- Subpv ----------------------------------------- +/*! +Compute forward mode Taylor coefficients for result of op = SubpvOp. + +The C++ source code corresponding to this operation is +\verbatim + z = x - y +\endverbatim +In the documentation below, +this operations is for the case where x is a parameter and y is a variable. + +\copydetails CppAD::local::forward_binary_op +*/ + +template +void forward_subpv_op( + size_t p , + size_t q , + size_t i_z , + const addr_t* arg , + const Base* parameter , + size_t cap_order , + Base* taylor ) +{ + // check assumptions + CPPAD_ASSERT_UNKNOWN( NumArg(SubpvOp) == 2 ); + CPPAD_ASSERT_UNKNOWN( NumRes(SubpvOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( q < cap_order ); + CPPAD_ASSERT_UNKNOWN( p <= q ); + + // Taylor coefficients corresponding to arguments and result + Base* y = taylor + size_t(arg[1]) * cap_order; + Base* z = taylor + i_z * cap_order; + + // Paraemter value + Base x = parameter[ arg[0] ]; + if( p == 0 ) + { z[0] = x - y[0]; + p++; + } + for(size_t d = p; d <= q; d++) + z[d] = - y[d]; +} +/*! +Multiple directions forward mode Taylor coefficients for op = SubpvOp. + +The C++ source code corresponding to this operation is +\verbatim + z = x - y +\endverbatim +In the documentation below, +this operations is for the case where x is a parameter and y is a variable. + +\copydetails CppAD::local::forward_binary_op_dir +*/ + +template +void forward_subpv_op_dir( + size_t q , + size_t r , + size_t i_z , + const addr_t* arg , + const Base* parameter , + size_t cap_order , + Base* taylor ) +{ + // check assumptions + CPPAD_ASSERT_UNKNOWN( NumArg(SubpvOp) == 2 ); + CPPAD_ASSERT_UNKNOWN( NumRes(SubpvOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( 0 < q ); + CPPAD_ASSERT_UNKNOWN( q < cap_order ); + + // Taylor coefficients corresponding to arguments and result + size_t num_taylor_per_var = (cap_order-1) * r + 1; + size_t m = (q-1) * r + 1; + Base* y = taylor + size_t(arg[1]) * num_taylor_per_var + m; + Base* z = taylor + i_z * num_taylor_per_var + m; + + // Paraemter value + for(size_t ell = 0; ell < r; ell++) + z[ell] = - y[ell]; +} +/*! +Compute zero order forward mode Taylor coefficient for result of op = SubpvOp. + +The C++ source code corresponding to this operation is +\verbatim + z = x - y +\endverbatim +In the documentation below, +this operations is for the case where x is a parameter and y is a variable. + +\copydetails CppAD::local::forward_binary_op_0 +*/ + +template +void forward_subpv_op_0( + size_t i_z , + const addr_t* arg , + const Base* parameter , + size_t cap_order , + Base* taylor ) +{ + // check assumptions + CPPAD_ASSERT_UNKNOWN( NumArg(SubpvOp) == 2 ); + CPPAD_ASSERT_UNKNOWN( NumRes(SubpvOp) == 1 ); + + // Paraemter value + Base x = parameter[ arg[0] ]; + + // Taylor coefficients corresponding to arguments and result + Base* y = taylor + size_t(arg[1]) * cap_order; + Base* z = taylor + i_z * cap_order; + + z[0] = x - y[0]; +} + +/*! +Compute reverse mode partial derivative for result of op = SubpvOp. + +The C++ source code corresponding to this operation is +\verbatim + z = x - y +\endverbatim +In the documentation below, +this operations is for the case where x is a parameter and y is a variable. + +\copydetails CppAD::local::reverse_binary_op +*/ + +template +void reverse_subpv_op( + size_t d , + size_t i_z , + const addr_t* arg , + const Base* parameter , + size_t cap_order , + const Base* taylor , + size_t nc_partial , + Base* partial ) +{ + // check assumptions + CPPAD_ASSERT_UNKNOWN( NumArg(SubvvOp) == 2 ); + CPPAD_ASSERT_UNKNOWN( NumRes(SubvvOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( d < cap_order ); + CPPAD_ASSERT_UNKNOWN( d < nc_partial ); + + // Partial derivatives corresponding to arguments and result + Base* py = partial + size_t(arg[1]) * nc_partial; + Base* pz = partial + i_z * nc_partial; + + // number of indices to access + size_t i = d + 1; + while(i) + { --i; + py[i] -= pz[i]; + } +} + +// --------------------------- Subvp ----------------------------------------- +/*! +Compute forward mode Taylor coefficients for result of op = SubvvOp. + +The C++ source code corresponding to this operation is +\verbatim + z = x - y +\endverbatim +In the documentation below, +this operations is for the case where x is a variable and y is a parameter. + +\copydetails CppAD::local::forward_binary_op +*/ + +template +void forward_subvp_op( + size_t p , + size_t q , + size_t i_z , + const addr_t* arg , + const Base* parameter , + size_t cap_order , + Base* taylor ) +{ + // check assumptions + CPPAD_ASSERT_UNKNOWN( NumArg(SubvpOp) == 2 ); + CPPAD_ASSERT_UNKNOWN( NumRes(SubvpOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( q < cap_order ); + CPPAD_ASSERT_UNKNOWN( p <= q ); + + // Taylor coefficients corresponding to arguments and result + Base* x = taylor + size_t(arg[0]) * cap_order; + Base* z = taylor + i_z * cap_order; + + // Parameter value + Base y = parameter[ arg[1] ]; + if( p == 0 ) + { z[0] = x[0] - y; + p++; + } + for(size_t d = p; d <= q; d++) + z[d] = x[d]; +} +/*! +Multiple directions forward mode Taylor coefficients for op = SubvvOp. + +The C++ source code corresponding to this operation is +\verbatim + z = x - y +\endverbatim +In the documentation below, +this operations is for the case where x is a variable and y is a parameter. + +\copydetails CppAD::local::forward_binary_op_dir +*/ + +template +void forward_subvp_op_dir( + size_t q , + size_t r , + size_t i_z , + const addr_t* arg , + const Base* parameter , + size_t cap_order , + Base* taylor ) +{ + // check assumptions + CPPAD_ASSERT_UNKNOWN( NumArg(SubvpOp) == 2 ); + CPPAD_ASSERT_UNKNOWN( NumRes(SubvpOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( 0 < q ); + CPPAD_ASSERT_UNKNOWN( q < cap_order ); + + // Taylor coefficients corresponding to arguments and result + size_t num_taylor_per_var = (cap_order-1) * r + 1; + Base* x = taylor + size_t(arg[0]) * num_taylor_per_var; + Base* z = taylor + i_z * num_taylor_per_var; + + // Parameter value + size_t m = (q-1) * r + 1; + for(size_t ell = 0; ell < r; ell++) + z[m+ell] = x[m+ell]; +} + +/*! +Compute zero order forward mode Taylor coefficients for result of op = SubvvOp. + +The C++ source code corresponding to this operation is +\verbatim + z = x - y +\endverbatim +In the documentation below, +this operations is for the case where x is a variable and y is a parameter. + +\copydetails CppAD::local::forward_binary_op_0 +*/ + +template +void forward_subvp_op_0( + size_t i_z , + const addr_t* arg , + const Base* parameter , + size_t cap_order , + Base* taylor ) +{ + // check assumptions + CPPAD_ASSERT_UNKNOWN( NumArg(SubvpOp) == 2 ); + CPPAD_ASSERT_UNKNOWN( NumRes(SubvpOp) == 1 ); + + // Parameter value + Base y = parameter[ arg[1] ]; + + // Taylor coefficients corresponding to arguments and result + Base* x = taylor + size_t(arg[0]) * cap_order; + Base* z = taylor + i_z * cap_order; + + z[0] = x[0] - y; +} + +/*! +Compute reverse mode partial derivative for result of op = SubvpOp. + +The C++ source code corresponding to this operation is +\verbatim + z = x - y +\endverbatim +In the documentation below, +this operations is for the case where x is a variable and y is a parameter. + +\copydetails CppAD::local::reverse_binary_op +*/ + +template +void reverse_subvp_op( + size_t d , + size_t i_z , + const addr_t* arg , + const Base* parameter , + size_t cap_order , + const Base* taylor , + size_t nc_partial , + Base* partial ) +{ + // check assumptions + CPPAD_ASSERT_UNKNOWN( NumArg(SubvpOp) == 2 ); + CPPAD_ASSERT_UNKNOWN( NumRes(SubvpOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( d < cap_order ); + CPPAD_ASSERT_UNKNOWN( d < nc_partial ); + + // Partial derivatives corresponding to arguments and result + Base* px = partial + size_t(arg[0]) * nc_partial; + Base* pz = partial + i_z * nc_partial; + + // number of indices to access + size_t i = d + 1; + while(i) + { --i; + px[i] += pz[i]; + } +} + +} } // END_CPPAD_LOCAL_NAMESPACE +# endif diff --git a/build-config/cppad/include/cppad/local/subgraph/arg_variable.hpp b/build-config/cppad/include/cppad/local/subgraph/arg_variable.hpp new file mode 100644 index 00000000..1ec1f8c2 --- /dev/null +++ b/build-config/cppad/include/cppad/local/subgraph/arg_variable.hpp @@ -0,0 +1,112 @@ +# ifndef CPPAD_LOCAL_SUBGRAPH_ARG_VARIABLE_HPP +# define CPPAD_LOCAL_SUBGRAPH_ARG_VARIABLE_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-18 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +# include + +// BEGIN_CPPAD_LOCAL_SUBGRAPH_NAMESPACE +namespace CppAD { namespace local { namespace subgraph { +/*! +\file arg_variable.hpp +Determine arguments that are variables. +*/ + +/*! +Determine the set of arguments, for an operator, that are variables. + +\tparam Addr +Type used for indices in random iterator. + +\param random_itr +is a random iterator for this operation sequence. + +\param i_op +is the operator index. If this operator is part of a atomic function call, +it must be the first AFunOp in the call. (There is a AFunOp at the +beginning and end of each call.) + +\param variable +is the set of argument variables corresponding to this operator. +If the operator is a AFunOp, the arguments are the variables +that are passed into the function call. + +\param work +this is work space used by arg_variable to make subsequent calls +faster. It should not be used by the calling routine. In addition, +it is better if work does not drop out of scope between calls. +*/ +template +void get_argument_variable( + const play::const_random_iterator& random_itr , + size_t i_op , + pod_vector& variable , + pod_vector& work ) +{ + // reset to size zero, but keep allocated memory + variable.resize(0); + // + // operator corresponding to i_op + OpCode op; + const addr_t* op_arg; + size_t i_var; + random_itr.op_info(i_op, op, op_arg, i_var); + // + // partial check of assumptions on atomic function calls + CPPAD_ASSERT_UNKNOWN( + op != FunapOp && op != FunavOp && op != FunrpOp && op != FunrvOp + ); + // + // we assume this is the first AFunOp of the call + if( op == AFunOp ) + { random_itr.op_info(++i_op, op, op_arg, i_var); + while( op != AFunOp ) + { switch(op) + { + case FunavOp: + { CPPAD_ASSERT_NARG_NRES(op, 1, 0); + size_t j_var = size_t( op_arg[0] ); + variable.push_back(j_var); + } + break; + + case FunrvOp: + case FunrpOp: + case FunapOp: + break; + + default: + // cannot find second AFunOp in this call + CPPAD_ASSERT_UNKNOWN(false); + break; + } + random_itr.op_info(++i_op, op, op_arg, i_var); + } + CPPAD_ASSERT_UNKNOWN( variable.size() > 0 ); + return; + } + // is_variable is a reference to work with a better name + pod_vector& is_variable(work); + arg_is_variable(op, op_arg, is_variable); + size_t num_arg = is_variable.size(); + for(size_t j = 0; j < num_arg; ++j) + { if( is_variable[j] ) + { size_t j_var = size_t( op_arg[j] ); + variable.push_back(j_var); + } + } + return; +} + +} } } // END_CPPAD_LOCAL_SUBGRAPH_NAMESPACE + +# endif diff --git a/build-config/cppad/include/cppad/local/subgraph/entire_call.hpp b/build-config/cppad/include/cppad/local/subgraph/entire_call.hpp new file mode 100644 index 00000000..c448837f --- /dev/null +++ b/build-config/cppad/include/cppad/local/subgraph/entire_call.hpp @@ -0,0 +1,76 @@ +# ifndef CPPAD_LOCAL_SUBGRAPH_ENTIRE_CALL_HPP +# define CPPAD_LOCAL_SUBGRAPH_ENTIRE_CALL_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-18 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +# include + +// BEGIN_CPPAD_LOCAL_SUBGRAPH_NAMESPACE +namespace CppAD { namespace local { namespace subgraph { +/*! +\file entire_call.hpp +include entire function call in a subgraph +*/ +// =========================================================================== +/*! +Convert from just firt AFunOp to entire atomic function call in a subgraph. + +\tparam Addr +Type used for indices in the random iterator. + +\param random_itr +is a random iterator for this operation sequence. + +\param subgraph +It a set of operator indices in this recording. +If the corresponding operator is a AFunOp, it assumed to be the +first one in the corresponding atomic function call. +The other call operators are included in the subgraph. +*/ +template +void entire_call( + const play::const_random_iterator& random_itr , + pod_vector& subgraph ) +{ + // add extra operators corresponding to rest of atomic function calls + size_t n_sub = subgraph.size(); + for(size_t k = 0; k < n_sub; ++k) + { size_t i_op = size_t( subgraph[k] ); + // + if( random_itr.get_op(i_op) == AFunOp ) + { // This is the first AFunOp of this atomic function call + while( random_itr.get_op(++i_op) != AFunOp ) + { switch(random_itr.get_op(i_op)) + { + case FunavOp: + case FunrvOp: + case FunrpOp: + case FunapOp: + subgraph.push_back( addr_t(i_op) ); + break; + + default: + // cannot find second AFunOp in this call + CPPAD_ASSERT_UNKNOWN(false); + break; + } + } + // THis is the second AFunOp of this atomic function call + subgraph.push_back( addr_t(i_op) ); + } + } + +} + +} } } // END_CPPAD_LOCAL_SUBGRAPH_NAMESPACE + +# endif diff --git a/build-config/cppad/include/cppad/local/subgraph/get_rev.hpp b/build-config/cppad/include/cppad/local/subgraph/get_rev.hpp new file mode 100644 index 00000000..4f99660b --- /dev/null +++ b/build-config/cppad/include/cppad/local/subgraph/get_rev.hpp @@ -0,0 +1,165 @@ +# ifndef CPPAD_LOCAL_SUBGRAPH_GET_REV_HPP +# define CPPAD_LOCAL_SUBGRAPH_GET_REV_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +# include +# include +# include + +// BEGIN_CPPAD_LOCAL_SUBGRAPH_NAMESPACE +namespace CppAD { namespace local { namespace subgraph { +/*! +\file get_rev.hpp +Get subgraph corresponding to a dependent variable. +*/ + +// =========================================================================== +/*! +Get the subgraph corresponding to a dependent variables +(and a selected set of independent variables). + +\tparam Addr +Type used for indices in the random iterator. + +\param random_itr +is a random iterator for this operation sequence. + +\param dep_taddr +is the vector mapping user dependent variable indices +to the correpsonding variable in the recording. + +\param i_dep +is the user index for his dependent variable; +that i_dep < n_dep_. + +\param subgraph +the input size and contents of this vector do not matter. +Repeated calls with the same subgraph vector should reduce +the amount of memory allocation. +Upon return it contains the operator indices for the subgraph +corresponding to the dependent and the selected independent variables. +Only selected independent variable operators InvOp are included +in the subgraph. +Furthermore the operator indices in subgraph are unique; i.e., +if i_op != j_op then subgraph[i_op] != subgraph[j_op]. + +\par map_user_op_ +This vector must be set. + +\par in_subgraph_ +has size equal to the number of operators in play. +If in_subgraph[i_op] <= n_dep_, +the result for this operator depends on the selected independent variables. +In addition, upon input, there is no i_op such that in_subgraph[i_op] == i_dep. +Note that for atomic function call operators i_op, +\code + n_dep_ < in_subgraph[i_op] +\endcode +except for the first AFunOp in the atomic function call sequence. +For the first AFunOp, +\code + in_subgraph[i_op] <= n_dep_ +\endcode +if any result for the atomic function call +depends on the selected independent variables. +Except for UserOP, only operators with NumRes(op) > 0 are included +in the dependency; e.g., comparison operators are not included. +Upon return, some of the i_op for which in_subgraph[i_op] <= n_dep_, +will be changed to in_subgraph[i_op] = i_dep. + +\par process_range_ +The value process_range_[i_dep] is checked to make sure it is false. +It is then set to have value true. +*/ +template +void subgraph_info::get_rev( + const play::const_random_iterator& random_itr , + const pod_vector& dep_taddr , + addr_t i_dep , + pod_vector& subgraph ) +{ // check sizes + CPPAD_ASSERT_UNKNOWN( map_user_op_.size() == n_op_ ); + + // process_range_ + CPPAD_ASSERT_UNKNOWN( process_range_[i_dep] == false ); + process_range_[i_dep] = true; + + // special value; see init_rev_in_subgraph + addr_t depend_yes = addr_t( n_dep_ ); + + // assumption on i_dep + CPPAD_ASSERT_UNKNOWN( i_dep < depend_yes ); + + // start with an empty subgraph for this dependent variable + subgraph.resize(0); + + // tape index corresponding to this dependent variable + size_t i_var = dep_taddr[i_dep]; + + // operator corresponding to this dependent variable + size_t i_op = random_itr.var2op(i_var); + i_op = size_t( map_user_op_[i_op] ); + + // if this variable depends on the selected indepent variables + // process its subgraph + CPPAD_ASSERT_UNKNOWN( in_subgraph_[i_op] != i_dep ) + if( in_subgraph_[i_op] <= depend_yes ) + { subgraph.push_back( addr_t(i_op) ); + in_subgraph_[i_op] = i_dep; + } + + // space used to return set of arguments that are variables + pod_vector argument_variable; + + // temporary space used by get_argument_variable + pod_vector work; + + // scan all the operators in this subgraph + size_t sub_index = 0; + while(sub_index < subgraph.size() ) + { // this operator connected to this dependent and selected independent + i_op = size_t( subgraph[sub_index] ); + CPPAD_ASSERT_UNKNOWN( in_subgraph_[i_op] == i_dep ); + // + // There must be a result for this operator +# ifndef NDEBUG + OpCode op = random_itr.get_op(i_op); + CPPAD_ASSERT_UNKNOWN(op == AFunOp || NumRes(op) > 0 ); +# endif + // + // which variables are connected to this operator + get_argument_variable(random_itr, i_op, argument_variable, work); + for(size_t j = 0; j < argument_variable.size(); ++j) + { // add the corresponding operators to the subgraph + size_t j_var = argument_variable[j]; + size_t j_op = random_itr.var2op(j_var); + j_op = size_t( map_user_op_[j_op] ); + bool add = in_subgraph_[j_op] <= depend_yes; + add &= in_subgraph_[j_op] != i_dep; + if( random_itr.get_op(j_op) == InvOp ) + { CPPAD_ASSERT_UNKNOWN( j_op == j_var ); + add &= select_domain_[j_var - 1]; + } + if( add ) + { subgraph.push_back( addr_t(j_op) ); + in_subgraph_[j_op] = i_dep; + } + } + // we are done scaning this subgraph operator + ++sub_index; + } +} + +} } } // END_CPPAD_LOCAL_SUBGRAPH_NAMESPACE + +# endif diff --git a/build-config/cppad/include/cppad/local/subgraph/info.hpp b/build-config/cppad/include/cppad/local/subgraph/info.hpp new file mode 100644 index 00000000..d0a8fea8 --- /dev/null +++ b/build-config/cppad/include/cppad/local/subgraph/info.hpp @@ -0,0 +1,334 @@ +# ifndef CPPAD_LOCAL_SUBGRAPH_INFO_HPP +# define CPPAD_LOCAL_SUBGRAPH_INFO_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-18 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +# include +# include +# include + +// BEGIN_CPPAD_LOCAL_SUBGRAPH_NAMESPACE +namespace CppAD { namespace local { namespace subgraph { +/*! +\file info.hpp +subgraph information attached to a operation sequence +*/ + +/// class for maintaining subgraph information attached to on ADFun object. +class subgraph_info { +private: + // ----------------------------------------------------------------------- + // private member data set by constructor, resize, and assign + // ----------------------------------------------------------------------- + /// number of independent variables for this function + size_t n_ind_; + + /// number of dependent variables for this function + size_t n_dep_; + + /// number of operatros in operation sequence + size_t n_op_; + + /// number of variables in operation sequence + size_t n_var_; + + // ----------------------------------------------------------------------- + // private member data set by set_map_user_op + // ----------------------------------------------------------------------- + + /// Mapping atomic call operators to AFunOp that begins call sequence, + /// other operators are not changed by the map. + /// (size zero after construtor or resize) + pod_vector map_user_op_; + + // ----------------------------------------------------------------------- + // other private member data + // ----------------------------------------------------------------------- + + /// flags which operatiors are in subgraph + /// (size zero or n_op_). + pod_vector in_subgraph_; + + /// flags which dependent variables are selected + pod_vector select_domain_; + + /// flags which dependent variables have been processed since + /// the previous init_rev + pod_vector process_range_; + +public: + // ----------------------------------------------------------------------- + // const public functions + // ----------------------------------------------------------------------- + /// number of independent variables + size_t n_ind(void) const + { return n_ind_; } + + /// number of dependent variables + size_t n_dep(void) const + { return n_dep_; } + + /// number of operators + size_t n_op(void) const + { return n_op_; } + + // number of variables + size_t n_var(void) const + { return n_var_; } + + /// map atomic function calls to first operator in the call + const pod_vector& map_user_op(void) const + { return map_user_op_; } + + /// previous select_domain argument to init_rev + const pod_vector& select_domain(void) const + { return select_domain_; } + + /// dependent variables that have been processed since previous init_rev + const pod_vector& process_range(void) const + { return process_range_; } + + /// amount of memory corresonding to this object + size_t memory(void) const + { size_t sum = map_user_op_.size() * sizeof(addr_t); + sum += in_subgraph_.size() * sizeof(addr_t); + sum += select_domain_.size() * sizeof(bool); + sum += process_range_.size() * sizeof(bool); + return sum; + } + + /// free memory used for calculating subgraph + void clear(void) + { map_user_op_.clear(); + in_subgraph_.clear(); + select_domain_.clear(); + process_range_.clear(); + } + // ----------------------------------------------------------------------- + /*! + check that the value of map_user_op is OK for this operation sequence + + \param play + is the player for this operation sequence. + + \return + is true, if map_user_op has the correct value for this operation sequence + (is the same as it would be after a set_map_user_op). + */ + template + bool check_map_user_op(const player* play) const + { if( map_user_op_.size() != n_op_ ) + return false; + bool ok = true; + size_t i_op = 0; + while( i_op < n_op_ ) + { OpCode op = play->GetOp(i_op); + ok &= map_user_op_[i_op] == addr_t( i_op ); + if( op == AFunOp ) + { addr_t begin = addr_t( i_op ); + op = play->GetOp(++i_op); + while( op != AFunOp ) + { CPPAD_ASSERT_UNKNOWN( + op==FunapOp || op==FunavOp || op==FunrpOp || op==FunrvOp + ); + ok &= map_user_op_[i_op] == begin; + op = play->GetOp(++i_op); + } + ok &= map_user_op_[i_op] == begin; + } + ++i_op; + } + return ok; + } + // ----------------------------------------------------------------------- + // non const public functions + // ----------------------------------------------------------------------- + + /// flag which operators that are in the subgraph + pod_vector& in_subgraph(void) + { return in_subgraph_; } + + + /// default constructor (all sizes are zero) + subgraph_info(void) + : n_ind_(0), n_dep_(0), n_op_(0), n_var_(0) + { CPPAD_ASSERT_UNKNOWN( map_user_op_.size() == 0 ); + CPPAD_ASSERT_UNKNOWN( in_subgraph_.size() == 0 ); + } + // ----------------------------------------------------------------------- + /// assignment operator + void operator=(const subgraph_info& info) + { n_ind_ = info.n_ind_; + n_dep_ = info.n_dep_; + n_op_ = info.n_op_; + n_var_ = info.n_var_; + map_user_op_ = info.map_user_op_; + in_subgraph_ = info.in_subgraph_; + select_domain_ = info.select_domain_; + process_range_ = info.process_range_; + return; + } + // ----------------------------------------------------------------------- + /// swap + /// (used for move semantics version of ADFun assignment) + void swap(subgraph_info& info) + { // size_t objects + std::swap(n_ind_ , info.n_ind_); + std::swap(n_dep_ , info.n_dep_); + std::swap(n_op_ , info.n_op_); + std::swap(n_var_ , info.n_var_); + // + // pod_vectors + map_user_op_.swap( info.map_user_op_); + in_subgraph_.swap( info.in_subgraph_); + select_domain_.swap( info.select_domain_); + process_range_.swap( info.process_range_); + // + return; + } + // ----------------------------------------------------------------------- + /*! + set sizes for this object (the default sizes are zero) + + \param n_ind + number of indepent variables. + + \param n_dep + number of dependent variables. + + \param n_op + number of operators. + + \param n_var + number of variables. + + \par map_user_op_ + is resized to zero. + + \par in_subgraph_ + is resized to zero. + */ + void resize(size_t n_ind, size_t n_dep, size_t n_op, size_t n_var) + { CPPAD_ASSERT_UNKNOWN( + n_op <= size_t( std::numeric_limits::max() ) + ); + // n_ind_ + n_ind_ = n_ind; + // n_dep_ + n_dep_ = n_dep; + // n_op_ + n_op_ = n_op; + // n_var_ + n_var_ = n_var; + + // + // map_user_op_ + map_user_op_.resize(0); + // + // in_subgraph_ + in_subgraph_.resize(0); + // + return; + } + // ----------------------------------------------------------------------- + /*! + set the value of map_user_op for this operation sequence + + \param play + is the player for this operation sequence. It must same number of + operators and variables as this subgraph_info object. + + \par map_user_op_ + This size of map_user_op_ must be zero when this function is called + (which is true after a resize operation). + This function sets its size to the number of operations in play. + We use the term user OpCocde for the any one of the following: + AFunOp, FunapOp, FunavOp, FunrpOp, or FunrvOp. Suppose + \code + OpCodce op_i = play->GetOp(i_op); + size_t j_op = map_user_op[i_op]; + OpCode op_j = play->GetOP(j_op); + \endcode + If op is a user OpCode, j_op is the index of the first operator + in the corresponding atomic function call and op_j == AFunOp. + Otherwise j_op == i_op; + + */ + template + void set_map_user_op(const player* play) + { CPPAD_ASSERT_UNKNOWN( map_user_op_.size() == 0 ); + // + CPPAD_ASSERT_UNKNOWN( n_op_ == play->num_op_rec() ); + CPPAD_ASSERT_UNKNOWN( n_var_ == play->num_var_rec() ); + // + // resize map_user_op_ + map_user_op_.resize(n_op_); + // + // set map_user_op for each operator + for(size_t i_op = 0; i_op < n_op_; ++i_op) + { // this operator + OpCode op = play->GetOp(i_op); + // + // value of map_user_op when op is not in atomic function call) + map_user_op_[i_op] = addr_t( i_op ); + // + if( op == AFunOp ) + { // first AFunOp in an atomic function call sequence + // + // All operators in this atomic call sequence will be + // mapped to the AFunOp that begins this call. + addr_t begin = addr_t( i_op ); + op = play->GetOp(++i_op); + while( op != AFunOp ) + { CPPAD_ASSERT_UNKNOWN( + op==FunapOp || op==FunavOp || op==FunrpOp || op==FunrvOp + ); + // map this operator to the beginning of the call + map_user_op_[i_op] = begin; + op = play->GetOp(++i_op); + } + // map the second AFunOp to the beginning of the call + map_user_op_[i_op] = begin; + } + } + return; + } + // ----------------------------------------------------------------------- + // see init_rev.hpp + template + void init_rev( + const play::const_random_iterator& random_itr , + const BoolVector& select_domain + ); + template + void init_rev( + player* play , + const BoolVector& select_domain + ); + // ----------------------------------------------------------------------- + // see get_rev.hpp + template + void get_rev( + const play::const_random_iterator& random_itr , + const pod_vector& dep_taddr , + addr_t i_dep , + pod_vector& subgraph + ); +}; + +} } } // END_CPPAD_LOCAL_SUBGRAPH_NAMESPACE + +// routines that operate on in_subgraph +# include +# include + +# endif diff --git a/build-config/cppad/include/cppad/local/subgraph/init_rev.hpp b/build-config/cppad/include/cppad/local/subgraph/init_rev.hpp new file mode 100644 index 00000000..9d7b65c7 --- /dev/null +++ b/build-config/cppad/include/cppad/local/subgraph/init_rev.hpp @@ -0,0 +1,225 @@ +# ifndef CPPAD_LOCAL_SUBGRAPH_INIT_REV_HPP +# define CPPAD_LOCAL_SUBGRAPH_INIT_REV_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +# include + +// BEGIN_CPPAD_LOCAL_SUBGRAPH_NAMESPACE +namespace CppAD { namespace local { namespace subgraph { +/*! +\file init_rev.hpp +initialize for a reverse mode subgraph calculation +*/ + +// ----------------------------------------------------------------------- +/*! +Initialize in_subgraph corresponding to a single dependent variable +(and a selected set of independent variables). + +\tparam Addr +is the type used for indices in the random iterator. + +\param random_itr +Is a random iterator for this operation sequence. + +\param select_domain +is a vector with, size equal to the number of independent variables +in the recording. It determines the selected independent variables. + +\par in_subgraph_ +We use depend_yes (depend_no) for the value n_dep_ (n_dep_ + 1). +The important properties are that depend_yes < depend_no and +for a valid indpendent variable index i_ind < depend_yes. +The input size and elements of in_subgraph_ do not matter. +If in_subgraph_[i_op] == depend_yes (depend_no), +the result for this operator depends (does not depend) +on the selected independent variables. +Note that for atomic function call operators i_op, +in_subgraph[i_op] is depend_no except for the first AFunOp in the +atomic function call sequence. For the first AFunOp, +it is depend_yes (depend_no) if any of the results for the call sequence +depend (do not depend) on the selected independent variables. +Except for UserOP, only operators with NumRes(op) > 0 have in_subgraph_ +value depend_yes; +e.g., comparison operators have in_subgraph_ value depend_no. + +\par select_domain_ +This vector is is set equal to the select_domain argument. + +\par process_range_ +This vector is to to size n_dep_ and its values are set to false +*/ +template +void subgraph_info::init_rev( + const local::play::const_random_iterator& random_itr , + const BoolVector& select_domain ) +{ + // check sizes + CPPAD_ASSERT_UNKNOWN( map_user_op_.size() == n_op_ ); + CPPAD_ASSERT_UNKNOWN( random_itr.num_op() == n_op_ ); + CPPAD_ASSERT_UNKNOWN( size_t( select_domain.size() ) == n_ind_ ); + + // depend_yes and depend_no + addr_t depend_yes = addr_t( n_dep_ ); + addr_t depend_no = addr_t( n_dep_ + 1 ); + + // select_domain_ + select_domain_.resize(n_ind_); + for(size_t j = 0; j < n_ind_; ++j) + select_domain_[j] = select_domain[j]; + + // process_range_ + process_range_.resize(n_dep_); + for(size_t i = 0; i < n_dep_; ++i) + process_range_[i] = false; + + // set in_subgraph to have proper size + in_subgraph_.resize(n_op_); + + // space used to return set of arguments that are variables + pod_vector argument_variable; + + // temporary space used by get_argument_variable + pod_vector work; + +# ifndef NDEBUG + size_t count_independent = 0; +# endif + bool begin_atomic_call = false; + for(size_t i_op = 0; i_op < n_op_; ++i_op) + { OpCode op = random_itr.get_op(i_op); + // + // default value for this operator + in_subgraph_[i_op] = depend_no; + // + switch(op) + { case InvOp: + CPPAD_ASSERT_UNKNOWN( NumRes(op) > 0 ); + CPPAD_ASSERT_UNKNOWN( i_op > 0 ); + { // get user index for this independent variable + size_t j = i_op - 1; + CPPAD_ASSERT_UNKNOWN( j < n_ind_ ); + // + // set in_subgraph_[i_op] + if( select_domain[j] ) + in_subgraph_[i_op] = depend_yes; + } +# ifndef NDEBUG + ++count_independent; +# endif + break; + + // only mark both first AFunOp for each call as depending + // on the selected independent variables + case AFunOp: + begin_atomic_call = ! begin_atomic_call; + if( begin_atomic_call ) + { get_argument_variable(random_itr, i_op, argument_variable, work); + for(size_t j = 0; j < argument_variable.size(); ++j) + { size_t j_var = argument_variable[j]; + size_t j_op = random_itr.var2op(j_var); + j_op = size_t( map_user_op_[j_op] ); + CPPAD_ASSERT_UNKNOWN( j_op < i_op ); + if( in_subgraph_[j_op] == depend_yes ) + in_subgraph_[i_op] = depend_yes; + } + } + break; + + // skip FunrvOp (gets mapped to first AFunOp in this call) + case FunrvOp: + CPPAD_ASSERT_UNKNOWN( NumRes(op) > 0 ); + break; + + default: + // Except for AFunOp, only include when NumRes(op) > 0. + if( NumRes(op) > 0 ) + { get_argument_variable(random_itr, i_op, argument_variable, work); + for(size_t j = 0; j < argument_variable.size(); ++j) + { size_t j_var = argument_variable[j]; + size_t j_op = random_itr.var2op(j_var); + j_op = size_t( map_user_op_[j_op] ); + CPPAD_ASSERT_UNKNOWN( j_op < i_op ); + if( in_subgraph_[j_op] == depend_yes ) + in_subgraph_[i_op] = depend_yes; + } + } + break; + } + } + CPPAD_ASSERT_UNKNOWN( + count_independent == size_t(select_domain.size()) + ); + // + return; +} +// ----------------------------------------------------------------------- +/*! +Initialize in_subgraph corresponding to a single dependent variable +(and a selected set of independent variables). + +\tparam Addr +is the type used for indices in the random iterator. + +\tparam Base +this recording was made using ADFun + +\param play +is a player for this ADFun object. + +\param select_domain +is a vector with, size equal to the number of independent variables +in the recording. It determines the selected independent variables. + +\par in_subgraph_ +We use depend_yes (depend_no) for the value n_dep_ (n_dep_ + 1). +The important properties are that depend_yes < depend_no and +for a valid indpendent variable index i_ind < depend_yes. +The input size and elements of in_subgraph_ do not matter. +If in_subgraph_[i_op] == depend_yes (depend_no), +the result for this operator depends (does not depend) +on the selected independent variables. +Note that for atomic function call operators i_op, +in_subgraph[i_op] is depend_no except for the first AFunOp in the +atomic function call sequence. For the first AFunOp, +it is depend_yes (depend_no) if any of the results for the call sequence +depend (do not depend) on the selected independent variables. +Except for UserOP, only operators with NumRes(op) > 0 have in_subgraph_ +value depend_yes; +e.g., comparison operators have in_subgraph_ value depend_no. + +\par select_domain_ +This vector is is set equal to the select_domain argument. + +\par process_range_ +This vector is to to size n_dep_ and its values are set to false +*/ +template +void subgraph_info::init_rev( + player* play , + const BoolVector& select_domain ) +{ + // get random access iterator for this player + play->template setup_random(); + local::play::const_random_iterator random_itr = + play->template get_random(); + // + init_rev(random_itr, select_domain); + // + return; +} + + +} } } // END_CPPAD_LOCAL_SUBGRAPH_NAMESPACE + +# endif diff --git a/build-config/cppad/include/cppad/local/subgraph/sparsity.hpp b/build-config/cppad/include/cppad/local/subgraph/sparsity.hpp new file mode 100644 index 00000000..1d2b8a07 --- /dev/null +++ b/build-config/cppad/include/cppad/local/subgraph/sparsity.hpp @@ -0,0 +1,191 @@ +# ifndef CPPAD_LOCAL_SUBGRAPH_SPARSITY_HPP +# define CPPAD_LOCAL_SUBGRAPH_SPARSITY_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-18 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +# include +# include +# include +# include + +// BEGIN_CPPAD_LOCAL_SUBGRAPH_NAMESPACE +namespace CppAD { namespace local { namespace subgraph { +/*! +\file sparsity.hpp +Compute dependency sparsity pattern using subgraph technique. +*/ +// =========================================================================== +/*! +Compute dependency sparsity pattern for an ADFun function. + +\tparam Addr +type used for indices in random iterator +(must correspond to play->addr_type()) + +\tparam Base +the operation sequence was recorded using AD. + +\tparam BoolVector +a simple vector class with elements of type bool. + +\param play +is the operation sequence corresponding to the ADFun function. +It is effectively const except that play->setup_random() is called. + + +\param sub_info +is the subgraph information for this ADFun object. + +\param dep_taddr +mapping from user dependent variable index to variable index in play +(must have size sub_info.n_dep()). + +\param select_domain +only the selected independent variables will be included in the sparsity +pattern (must have size sub_info.n_ind()). + +\param select_range +only the selected dependent variables will be included in the sparsity pattern +(must have size sub_info.n_dep()). + +\param row_out +The input size and elements of row_out do not matter. +We use number of non-zeros (nnz) to denote the number of elements +in row_out. For k = 0 , ... , nnz-1, row_out[k] is the row index +of the k-th no-zero element of the dependency sparsitiy pattern for +the function corresponding to the recording. +\code + 0 <= row_out[k] < dep_taddr.size() + select_range[ row_out[k] ] == true +\endcode + +\param col_out +The input size and elements of col_out do not matter. +Upon return is has the same size as row_out; i.e., nnz. +For k = 0 , ... , nnz-1, col_out[k] is the column index +of the k-th no-zero element of the dependency sparsitiy pattern for +the function corresponding to the recording. +\code + 0 <= col_out[k] < sub_info.n_ind() + select_domain[ col_out[k] ] == true +\endcode + +\par AFunOp +All of the inputs and outputs for an atomic function call are considered +to be connected. +2DO: It would be good to use the sparsity patters for atomic function calls +to to make the sparsity pattern more efficient. +*/ + +template +void subgraph_sparsity( + player* play , + subgraph_info& sub_info , + const pod_vector& dep_taddr , + const BoolVector& select_domain , + const BoolVector& select_range , + pod_vector& row_out , + pod_vector& col_out ) +{ + // get random access iterator for this player + play->template setup_random(); + local::play::const_random_iterator random_itr = + play->template get_random(); + + // check dimension assumptions + CPPAD_ASSERT_UNKNOWN( + dep_taddr.size() == sub_info.n_dep() + ); + CPPAD_ASSERT_UNKNOWN( + size_t(select_domain.size()) == sub_info.n_ind() + ); + CPPAD_ASSERT_UNKNOWN( + size_t(select_range.size()) == sub_info.n_dep() + ); + + // number of dependent variables + size_t n_dep = dep_taddr.size(); + CPPAD_ASSERT_UNKNOWN( size_t(select_range.size()) == n_dep ); + + // start with an empty sparsity pattern + row_out.resize(0); + col_out.resize(0); + + // map_user_op + if( sub_info.map_user_op().size() == 0 ) + sub_info.set_map_user_op(play); + else + { CPPAD_ASSERT_UNKNOWN( sub_info.check_map_user_op(play) ); + } + CPPAD_ASSERT_UNKNOWN( + sub_info.map_user_op().size() == play->num_op_rec() + ); + + // subgraph of operators that are are connected to one of the selected + // dependent variables and depend on the selected independent variables + pod_vector subgraph; + + // initialize a reverse mode subgraph calculation + sub_info.init_rev(random_itr, select_domain); + CPPAD_ASSERT_UNKNOWN( + sub_info.in_subgraph().size() == play->num_op_rec() + ); + // +# ifndef NDEBUG + addr_t depend_yes = addr_t( n_dep ); +# endif + + // for each of the selected dependent variables +# ifndef NDEBUG + addr_t depend_no = addr_t( n_dep + 1 ); +# endif + CPPAD_ASSERT_UNKNOWN( depend_yes < depend_no ); + CPPAD_ASSERT_UNKNOWN( NumRes(BeginOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( NumRes(InvOp) == 1 ); + for(size_t i_dep = 0; i_dep < n_dep; ++i_dep) if( select_range[i_dep] ) + { CPPAD_ASSERT_UNKNOWN( i_dep < size_t( depend_yes ) ); + // + // subgraph of operators connected to i_dep + sub_info.get_rev( + random_itr, dep_taddr, addr_t(i_dep), subgraph + ); + // + for(size_t k = 0; k < subgraph.size(); k++) + { size_t i_op = size_t( subgraph[k] ); + // + // operator corresponding to this index + OpCode op = play->GetOp(i_op); + // + // This version of the subgraph only has first AFunOp + // for each atomic functionc all. + CPPAD_ASSERT_UNKNOWN( NumRes(op) > 0 || op == AFunOp ); + // + // independent variable entries correspond to sparsity pattern + if( op == InvOp ) + { CPPAD_ASSERT_NARG_NRES(op, 0, 1); + // i_var is equal i_op becasue BeginOp and InvOp have 1 result + size_t i_var = i_op; // tape index for this variable + size_t i_ind = i_var - 1; // user index for this variable + CPPAD_ASSERT_UNKNOWN( random_itr.var2op(i_var) == i_op ); + CPPAD_ASSERT_UNKNOWN( select_domain[i_ind] ); + // + // put this pair in the sparsity pattern + row_out.push_back(i_dep); + col_out.push_back(i_ind); + } + } + } +} + +} } } // END_CPPAD_LOCAL_SUBGRAPH_NAMESPACE + +# endif diff --git a/build-config/cppad/include/cppad/local/sweep/call_atomic.hpp b/build-config/cppad/include/cppad/local/sweep/call_atomic.hpp new file mode 100644 index 00000000..39f9a8e0 --- /dev/null +++ b/build-config/cppad/include/cppad/local/sweep/call_atomic.hpp @@ -0,0 +1,902 @@ +# ifndef CPPAD_LOCAL_SWEEP_CALL_ATOMIC_HPP +# define CPPAD_LOCAL_SWEEP_CALL_ATOMIC_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +# include +# include +# include + +// BEGIN_CPAPD_LOCAL_SWEEP_NAMESPACE +namespace CppAD { namespace local { namespace sweep { +/*! +\file call_atomic.hpp +Callbacks to atomic functions corresponding to atomic_index. +*/ +// ---------------------------------------------------------------------------- +/*! +Forward mode callback to atomic functions. + +\tparam Base +Is the type corresponding to the Taylor coefficients. + +\tparam RecBase +Is the type corresponding to this atomic function. + +\param parameter_x [in] +contains the values, in afun(ax, ay), for arguments that are parameters. + +\param type_x [in] +what is the type, in afun(ax, ay), for each component of x. + +\param need_y +specifies which components of taylor_y are necessary. + +\param order_low [in] +lowerest order for this forward mode calculation. + +\param order_up [in] +highest order for this forward mode calculation. + +\param atom_index [in] +is the index, in local::atomic_index, corresponding to this atomic function. + +\param atom_old [in] +is the extra id information for this atomic function in the atomic_one case. + +\param taylor_x [in] +Taylor coefficients corresponding to x. + +\param taylor_y [out] +Taylor coefficient corresponding to y. +*/ +template +void call_atomic_forward( + const vector& parameter_x , + const vector& type_x , + size_t need_y , + size_t order_low , + size_t order_up , + size_t atom_index , + size_t atom_old , + const vector& taylor_x , + vector& taylor_y ) +{ CPPAD_ASSERT_UNKNOWN( 0 < atom_index ); + bool set_null = false; + size_t type = 0; // set to avoid warning + std::string* name_ptr = nullptr; + void* v_ptr = nullptr; // set to avoid warning + local::atomic_index(set_null, atom_index, type, name_ptr, v_ptr); +# ifndef NDEBUG + bool ok = v_ptr != nullptr; + if( ok ) + { + if( type == 2 ) + { atomic_base* afun = + reinterpret_cast< atomic_base* >(v_ptr); + afun->set_old(atom_old); + vector empty; + ok = afun->forward( + order_low, order_up, empty, empty, taylor_x, taylor_y + ); + } + else + { CPPAD_ASSERT_UNKNOWN( type == 3 ); + atomic_three* afun = + reinterpret_cast< atomic_three* >(v_ptr); + ok = afun->forward( + parameter_x, type_x, + need_y, order_low, order_up, taylor_x, taylor_y + ); + } + } + if( ! ok ) + { // now take the extra time to copy the name + std::string name; + local::atomic_index(set_null, atom_index, type, &name, v_ptr); + std::string msg = name; + if( v_ptr == nullptr ) + msg += ": this atomic_three function has been deleted"; + else + msg += ": atomic forward returned false"; + CPPAD_ASSERT_KNOWN(false, msg.c_str() ); + } +# else + if( type == 2 ) + { atomic_base* afun = + reinterpret_cast< atomic_base* >(v_ptr); + vector empty; + afun->set_old(atom_old); + afun->forward( + order_low, order_up, empty, empty, taylor_x, taylor_y + ); + } + else + { atomic_three* afun = + reinterpret_cast< atomic_three* >(v_ptr); + afun->forward( + parameter_x, type_x, + need_y, order_low, order_up, taylor_x, taylor_y + ); + } +# endif +} +// ---------------------------------------------------------------------------- +/*! +Reverse mode callback to atomic functions. + +\tparam Base +Is the type corresponding to the Taylor coefficients. + +\tparam RecBase +Is the type corresponding to this atomic function. + +\param parameter_x [in] +value of the parameter arguments to the atomic function +(other arguments have the value nan). + +\param type_x [in] +type for each component of x (not used by atomic_two interface). + +\param order_up [in] +highest order for this reverse mode calculation. + +\param atom_index [in] +is the index, in local::atomic_index, corresponding to this atomic function. + +\param atom_old [in] +is the extra id information for this atomic function in the atomic_one case. + +\param taylor_x [in] +Taylor coefficients corresponding to x. + +\param taylor_y [in] +Taylor coefficient corresponding to y. + +\param partial_x [out] +Partials w.r.t the x Taylor coefficients. + +\param partial_y [in] +Partials w.r.t the y Taylor coefficients. +*/ +template +void call_atomic_reverse( + const vector& parameter_x , + const vector& type_x , + size_t order_up , + size_t atom_index , + size_t atom_old , + const vector& taylor_x , + const vector& taylor_y , + vector& partial_x , + const vector& partial_y ) +{ CPPAD_ASSERT_UNKNOWN( 0 < atom_index ); + bool set_null = false; + size_t type = 0; // set to avoid warning + std::string* name_ptr = nullptr; + void* v_ptr = nullptr; // set to avoid warning + local::atomic_index(set_null, atom_index, type, name_ptr, v_ptr); +# ifndef NDEBUG + bool ok = v_ptr != nullptr; + if( ok ) + { + if( type == 2 ) + { atomic_base* afun = + reinterpret_cast< atomic_base* >(v_ptr); + afun->set_old(atom_old); + ok = afun->reverse( + order_up, taylor_x, taylor_y, partial_x, partial_y + ); + } + else + { CPPAD_ASSERT_UNKNOWN( type == 3 ); + atomic_three* afun = + reinterpret_cast< atomic_three* >(v_ptr); + ok = afun->reverse( + parameter_x, type_x, + order_up, taylor_x, taylor_y, partial_x, partial_y + ); + } + } + if( ! ok ) + { // now take the extra time to copy the name + std::string name; + local::atomic_index(set_null, atom_index, type, &name, v_ptr); + std::string msg = name; + if( v_ptr == nullptr ) + msg += ": this atomic_three function has been deleted"; + else + msg += ": atomic reverse returned false"; + CPPAD_ASSERT_KNOWN(false, msg.c_str() ); + } +# else + if( type == 2 ) + { atomic_base* afun = + reinterpret_cast< atomic_base* >(v_ptr); + afun->set_old(atom_old); + afun->reverse( + order_up, taylor_x, taylor_y, partial_x, partial_y + ); + } + else + { atomic_three* afun = + reinterpret_cast< atomic_three* >(v_ptr); + afun->reverse( + parameter_x, type_x, + order_up, taylor_x, taylor_y, partial_x, partial_y + ); + } +# endif +} +// ---------------------------------------------------------------------------- +/*! +Forward Jacobian sparsity callback to atomic functions. + +\tparam Base +is the type corresponding to parameter_x +and to this atomic function. + +\tparam InternalSparsity +is the internal type used to represent sparsity; i.e., +sparse::pack_setvec or sparse::list_setvec. + +\param atom_index [in] +is the index, in local::atomic_index, corresponding to this atomic function. + +\param atom_old [in] +is the extra id information for this atomic function in the atomic_one case. + +\param dependency [in] +is this a dependency or sparsity calculation. + +\param parameter_x [in] +value of the parameter arguments to the atomic function +(other arguments have the value nan). + +\param type_x [in] +type for each component of x (not used by atomic_two interface). + +\param x_index [in] +is a mapping from the index of an atomic function argument +to the corresponding variable on the tape. + +\param y_index [in] +is a mapping from the index of an atomic function result +to the corresponding variable on the tape. + +\param var_sparsity [in/out] +On input, for j = 0, ... , n-1, the sparsity pattern with index x_index[j], +is the sparsity for the j-th argument to this atomic function. +On output, for i = 0, ... , m-1, the sparsity pattern with index y_index[i], +is the sparsity for the j-th result for this atomic function. +*/ +template +void call_atomic_for_jac_sparsity( + size_t atom_index , + size_t atom_old , + bool dependency , + const vector& parameter_x , + const vector& type_x , + const pod_vector& x_index , + const pod_vector& y_index , + InternalSparsity& var_sparsity ) +{ CPPAD_ASSERT_UNKNOWN( 0 < atom_index ); + bool set_null = false; + size_t type = 0; // set to avoid warning + std::string* name_ptr = nullptr; + void* v_ptr = nullptr; // set to avoid warning + local::atomic_index(set_null, atom_index, type, name_ptr, v_ptr); +# ifndef NDEBUG + bool ok = v_ptr != nullptr; + if ( ok ) + { + if( type == 2 ) + { atomic_base* afun = + reinterpret_cast< atomic_base* >(v_ptr); + afun->set_old(atom_old); + ok = afun->for_sparse_jac( + parameter_x, x_index, y_index, var_sparsity + ); + } + else + { CPPAD_ASSERT_UNKNOWN( type == 3 ); + atomic_three* afun = + reinterpret_cast< atomic_three* >(v_ptr); + ok = afun->for_jac_sparsity( + dependency, parameter_x, type_x, x_index, y_index, var_sparsity + ); + } + } + if( ! ok ) + { // now take the extra time to copy the name + std::string name; + local::atomic_index( + set_null, atom_index, type, &name, v_ptr + ); + std::string msg = name; + if( v_ptr == nullptr ) + msg += ": this atomic_three function has been deleted"; + else + msg += ": atomic jac_sparsity returned false"; + CPPAD_ASSERT_KNOWN(false, msg.c_str() ); + } +# else + if( type == 2 ) + { atomic_base* afun = + reinterpret_cast< atomic_base* >(v_ptr); + afun->set_old(atom_old); + afun->for_sparse_jac( + parameter_x, x_index, y_index, var_sparsity + ); + } + else + { CPPAD_ASSERT_UNKNOWN( type == 3 ); + atomic_three* afun = + reinterpret_cast< atomic_three* >(v_ptr); + afun->for_jac_sparsity( + dependency, parameter_x, type_x, x_index, y_index, var_sparsity + ); + } +# endif +} +// ---------------------------------------------------------------------------- +/*! +Reverse Jacobian sparsity callback to atomic functions. + +\tparam Base +is the type corresponding to parameter_x +and to this atomic function. + +\tparam InternalSparsity +is the internal type used to represent sparsity; i.e., +sparse::pack_setvec or sparse::list_setvec. + +\param atom_index [in] +is the index, in local::atomic_index, corresponding to this atomic function. + +\param atom_old [in] +is the extra id information for this atomic function in the atomic_one case. + +\param dependency [in] +is this a dependency or sparsity calculation. + +\param parameter_x [in] +value of the parameter arguments to the atomic function +(other arguments have the value nan). + +\param type_x [in] +type for each component of x (not used by atomic_two interface). + +\param x_index [in] +is a mapping from the index of an atomic function argument +to the corresponding variable on the tape. + +\param y_index [in] +is a mapping from the index of an atomic function result +to the corresponding variable on the tape. + +\param var_sparsity [in/out] +On input, for i = 0, ... , m-1, the sparsity pattern with index y_index[i], +is the sparsity for the i-th argument to this atomic function. +On output, for j = 0, ... , n-1, the sparsity pattern with index x_index[j], +the sparsity has been updated to remove y as a function of x. +*/ +template +void call_atomic_rev_jac_sparsity( + size_t atom_index , + size_t atom_old , + bool dependency , + const vector& parameter_x , + const vector& type_x , + const pod_vector& x_index , + const pod_vector& y_index , + InternalSparsity& var_sparsity ) +{ CPPAD_ASSERT_UNKNOWN( 0 < atom_index ); + bool set_null = false; + size_t type = 0; // set to avoid warning + std::string* name_ptr = nullptr; + void* v_ptr = nullptr; // set to avoid warning + local::atomic_index(set_null, atom_index, type, name_ptr, v_ptr); +# ifndef NDEBUG + bool ok = v_ptr != nullptr; + if( ok ) + { + if( type == 2 ) + { atomic_base* afun = + reinterpret_cast< atomic_base* >(v_ptr); + afun->set_old(atom_old); + ok = afun->rev_sparse_jac( + parameter_x, x_index, y_index, var_sparsity + ); + } + else + { CPPAD_ASSERT_UNKNOWN( type == 3 ); + atomic_three* afun = + reinterpret_cast< atomic_three* >(v_ptr); + ok = afun->rev_jac_sparsity( + dependency, parameter_x, type_x, x_index, y_index, var_sparsity + ); + } + } + if( ! ok ) + { // now take the extra time to copy the name + std::string name; + local::atomic_index( + set_null, atom_index, type, &name, v_ptr + ); + std::string msg = name; + if( v_ptr == nullptr ) + msg += ": this atomic_three function has been deleted"; + else + msg += ": atomic jac_sparsity returned false"; + CPPAD_ASSERT_KNOWN(false, msg.c_str() ); + } +# else + if( type == 2 ) + { atomic_base* afun = + reinterpret_cast< atomic_base* >(v_ptr); + afun->set_old(atom_old); + afun->rev_sparse_jac( + parameter_x, x_index, y_index, var_sparsity + ); + } + else + { CPPAD_ASSERT_UNKNOWN( type == 3 ); + atomic_three* afun = + reinterpret_cast< atomic_three* >(v_ptr); + afun->rev_jac_sparsity( + dependency, parameter_x, type_x, x_index, y_index, var_sparsity + ); + } +# endif +} +// ---------------------------------------------------------------------------- +/* +$begin call_atomic_for_hes_sparsiy$$ +$spell + hes + np + numvar + jac + Jacobian + afun + setvec +$$ + +$section Forward Hessian Sparsity Callback to Atomic Functions.$$ + +$head Syntax$$ +$codei%call_atomic_for_hes_sparsity( + %atom_index%, %atom_old%, %parameter_x%, %type_x%, %x_index%, %y_index%, + %np1%, %numvar%, %rev_jac_sparsity%, %for_sparsity% +)%$$ + +$head Prototype$$ +$srcthisfile% +0%// BEGIN_call_atomic_for_hes_sparsity%// END_call_atomic_for_hes_sparsity%1 +%$$ + +$head C++ Source$$ +The C++ source code corresponding to this operation is a +$cref/atomic function call/atomic_three/Syntax/Use Atomic Function/$$ +$codei% + %afun%(%ax%, %ay%) +%$$ +We refer to the corresponding function using $latex y = f(x)$$. + +$head Base$$ +is the type corresponding to $icode parameter_x$$ +and to this atomic function. + +$head InternalSparsity$$ +is the internal type used to represent sparsity; i.e., +$code sparse::pack_setvec$$ or $code sparse::list_setvec$$. + +$head atom_index$$ +is the index, in local::atomic_index, corresponding to this atomic function. + +$head atom_old$$ +is the extra id information for this atomic function in the atomic_one case. + +$head parameter_x$$ +value of the parameter arguments to the atomic function +(other arguments have the value nan). + +$head type_x$$ +type for each component of x (not used by atomic_two interface). + +$head x_index$$ +is a mapping from the index of an atomic function argument +to the corresponding variable on the tape. +We use $icode m_x$$ to denote the maximum value w.r.t $icode i$$ of +$icode%x_index%[%i%]%$$. + +$head y_index$$ +is a mapping from the index of an atomic function result +to the corresponding variable on the tape. +It should hold that $icode%m_i% < y_index%[%i%]%$$ for all $icode i$$. + +$head np1$$ +This is the number of independent variables plus one; +i.e. size of $icode x$$ plus one. + +$head numvar$$ +This is the total number of variables in the tape. + +$head rev_jac_sparsity$$ +For i = 0, ... , m-1, the sparsity pattern with index y_index[i], +is the reverse Jacobian sparsity for the i-th result to this atomic function. +This shows which components of the result affect the function we are +computing the Hessian of. + +$head for_sparsity$$ +We have the conditions $icode%np1% = %for_sparsity%.end()%$$ +and $icode%for_sparsity%.n_set() = %np1% + %numvar%$$. + +$subhead Input Jacobian Sparsity$$ +For $icode%i%= 0, ..., %m_x%$$, +the $icode%np1%+%i%$$ row of $icode for_sparsity$$ is the Jacobian sparsity +for the $th i$$ variable. These values do not change. +Note that $icode%i%=0%$$ corresponds to a parameter and +the corresponding Jacobian sparsity is empty. + +$subhead Input Hessian Sparsity$$ +For $icode%i%=1, ..., %n%$$, +the $th i$$ row of $icode for_sparsity$$ is the Hessian sparsity +before including the function $latex y = f(x)$$. + +$subhead Output Jacobian Sparsity$$ +For $icode%i%=0, ..., %y_index%.size()%$$, +row $icode%np1%+%y_index%[%i%]%$$ +of $icode for_sparsity$$ is the Jacobian sparsity +for the variable with index $icode%y_index%[%i%]%$$. + +$subhead Output Hessian Sparsity$$ +For $icode%i%=1, ..., %n%$$, +the $th i$$ row of $icode for_sparsity$$ is the Hessian sparsity +after including the function $latex y = f(x)$$. + +$end +*/ +// BEGIN_call_atomic_for_hes_sparsity +template +void call_atomic_for_hes_sparsity( + size_t atom_index , + size_t atom_old , + const vector& parameter_x , + const vector& type_x , + const pod_vector& x_index , + const pod_vector& y_index , + size_t np1 , + size_t numvar , + const InternalSparsity& rev_jac_sparsity , + InternalSparsity& for_sparsity ) +// END_call_atomic_for_hes_sparsity +{ CPPAD_ASSERT_UNKNOWN( 0 < atom_index ); + CPPAD_ASSERT_UNKNOWN( for_sparsity.end() == np1 ); + CPPAD_ASSERT_UNKNOWN( for_sparsity.n_set() == np1 + numvar ); + + bool set_null = false; + size_t type = 0; // set to avoid warning + std::string* name_ptr = nullptr; + void* v_ptr = nullptr; // set to avoid warning + local::atomic_index(set_null, atom_index, type, name_ptr, v_ptr); +# ifndef NDEBUG + bool ok = v_ptr != nullptr; + if( ok ) + { + if( type == 2 ) + { atomic_base* afun = + reinterpret_cast< atomic_base* >(v_ptr); + afun->set_old(atom_old); + ok = afun->for_sparse_hes( + parameter_x, + x_index, + y_index, + np1, + numvar, + rev_jac_sparsity, + for_sparsity + ); + } + else + { CPPAD_ASSERT_UNKNOWN( type == 3 ); + atomic_three* afun = + reinterpret_cast< atomic_three* >(v_ptr); + ok = afun->for_hes_sparsity( + parameter_x, + type_x, + x_index, + y_index, + np1, + numvar, + rev_jac_sparsity, + for_sparsity + ); + } + } + if( ! ok ) + { // now take the extra time to copy the name + std::string name; + local::atomic_index( + set_null, atom_index, type, &name, v_ptr + ); + std::string msg = name; + if( v_ptr == nullptr ) + msg += ": this atomic_three function has been deleted"; + else + msg += ": atomic hes_sparsity returned false"; + CPPAD_ASSERT_KNOWN(false, msg.c_str() ); + } +# else + if( type == 2 ) + { atomic_base* afun = + reinterpret_cast< atomic_base* >(v_ptr); + afun->set_old(atom_old); + afun->for_sparse_hes( + parameter_x, + x_index, + y_index, + np1, + numvar, + rev_jac_sparsity, + for_sparsity + ); + } + else + { CPPAD_ASSERT_UNKNOWN( type == 3 ); + atomic_three* afun = + reinterpret_cast< atomic_three* >(v_ptr); + afun->for_hes_sparsity( + parameter_x, + type_x, + x_index, + y_index, + np1, + numvar, + rev_jac_sparsity, + for_sparsity + ); + } +# endif +} +// ---------------------------------------------------------------------------- +/*! +Reverse Hessian sparsity callback to atomic functions. + +\tparam Base +is the type corresponding to parameter_x +and to this atomic function. + +\tparam InternalSparsity +is the internal type used to represent sparsity; i.e., +sparse::pack_setvec or sparse::list_setvec. + +\param atom_index [in] +is the index, in local::atomic_index, corresponding to this atomic function. + +\param atom_old [in] +is the extra id information for this atomic function in the atomic_one case. + +\param parameter_x [in] +value of the parameter arguments to the atomic function +(other arguments have the value nan). + +\param type_x [in] +type for each component of x (not used by atomic_two interface). + +\param x_index [in] +is a mapping from the index of an atomic function argument +to the corresponding variable on the tape. + +\param y_index [in] +is a mapping from the index of an atomic function result +to the corresponding variable on the tape. + +\param for_jac_sparsity +For j = 0, ... , n-1, the sparsity pattern with index x_index[j], +is the forward Jacobian sparsity for the j-th argument to this atomic function. + +\param rev_jac_flag +On input, for i = 0, ... , m-1, rev_jac_flag[ y_index[i] ] is true +if the fuction (we are computing the sparsity for) +depends on the variable y_index[i]. +Upon return, for j = 0, ..., n-1, rev_jac_flag[ x_index[j] ] has been set to +true any of the y_index variables are flagged depnend on x_index[j]. +Otherwise, rev_jac_flag[ x_index[j] ] is not modified. + +\param rev_hes_sparsity +This is the sparsity pattern for the Hessian. +On input, for i = 0, ... , m-1, row y_index[i] is the reverse Hessian sparsity +with one of the partials with respect to to y_index[i]. +Upon return, for j = 0, ..., n-1, the row x_index[j] has been +modified to include components that have a non-zero hessian through +the atomic fucntion with one of the partials w.r.t. x_index[j]. +*/ +template +void call_atomic_rev_hes_sparsity( + size_t atom_index , + size_t atom_old , + const vector& parameter_x , + const vector& type_x , + const pod_vector& x_index , + const pod_vector& y_index , + const InternalSparsity& for_jac_sparsity , + bool* rev_jac_flag , + InternalSparsity& rev_hes_sparsity ) +{ CPPAD_ASSERT_UNKNOWN( 0 < atom_index ); + bool set_null = false; + size_t type = 0; // set to avoid warning + std::string* name_ptr = nullptr; + void* v_ptr = nullptr; // set to avoid warning + local::atomic_index(set_null, atom_index, type, name_ptr, v_ptr); +# ifndef NDEBUG + bool ok = v_ptr != nullptr; + if( ok ) + { + if( type == 2 ) + { atomic_base* afun = + reinterpret_cast< atomic_base* >(v_ptr); + afun->set_old(atom_old); + ok = afun->rev_sparse_hes( + parameter_x, + x_index, + y_index, + for_jac_sparsity, + rev_jac_flag, + rev_hes_sparsity + ); + } + else + { CPPAD_ASSERT_UNKNOWN( type == 3 ); + atomic_three* afun = + reinterpret_cast< atomic_three* >(v_ptr); + ok = afun->rev_hes_sparsity( + parameter_x, + type_x, + x_index, + y_index, + for_jac_sparsity, + rev_jac_flag, + rev_hes_sparsity + ); + } + } + if( ! ok ) + { // now take the extra time to copy the name + std::string name; + local::atomic_index( + set_null, atom_index, type, &name, v_ptr + ); + std::string msg = name; + if( v_ptr == nullptr ) + msg += ": this atomic_three function has been deleted"; + else + msg += ": atomic hes_sparsity returned false"; + CPPAD_ASSERT_KNOWN(false, msg.c_str() ); + } +# else + if( type == 2 ) + { atomic_base* afun = + reinterpret_cast< atomic_base* >(v_ptr); + afun->set_old(atom_old); + afun->rev_sparse_hes( + parameter_x, + x_index, + y_index, + for_jac_sparsity, + rev_jac_flag, + rev_hes_sparsity + ); + } + else + { CPPAD_ASSERT_UNKNOWN( type == 3 ); + atomic_three* afun = + reinterpret_cast< atomic_three* >(v_ptr); + afun->rev_hes_sparsity( + parameter_x, + type_x, + x_index, + y_index, + for_jac_sparsity, + rev_jac_flag, + rev_hes_sparsity + ); + } +# endif +} +// ---------------------------------------------------------------------------- +/*! +Reverse dependency callback to atomic functions. + +\param atom_index [in] +is the index, in local::atomic_index, corresponding to this atomic function. + +\param atom_old [in] +is the extra id information for this atomic function in the atomic_one case. + +\param parameter_x [in] +is the value of the parameters in the corresponding function call +afun(ax, ay). + +\param type_x [in] +is the type for each x component in the corresponding function call +afun(ax, ay). + +\param depend_x [out] +specifies which components of x affect values we are interested in. + +\param depend_y [in] +specifies which components of y affect values we are interested in. +*/ +template +void call_atomic_rev_depend( + size_t atom_index , + size_t atom_old , + const vector& parameter_x , + const vector& type_x , + vector& depend_x , + const vector& depend_y ) +{ CPPAD_ASSERT_UNKNOWN( 0 < atom_index ); + bool set_null = false; + size_t type = 0; // set to avoid warning + std::string* name_ptr = nullptr; + void* v_ptr = nullptr; // set to avoid warning + local::atomic_index(set_null, atom_index, type, name_ptr, v_ptr); +# ifndef NDEBUG + bool ok = v_ptr != nullptr; + if( ok ) + { + if( type == 2 ) + { atomic_base* afun = + reinterpret_cast< atomic_base* >(v_ptr); + afun->set_old(atom_old); + vector empty; + ok = afun->rev_depend(parameter_x, type_x, depend_x, depend_y); + } + else + { CPPAD_ASSERT_UNKNOWN( type == 3 ); + atomic_three* afun = + reinterpret_cast< atomic_three* >(v_ptr); + ok = afun->rev_depend(parameter_x, type_x, depend_x, depend_y); + } + } + if( ! ok ) + { // now take the extra time to copy the name + std::string name; + local::atomic_index(set_null, atom_index, type, &name, v_ptr); + std::string msg = name; + if( v_ptr == nullptr ) + msg += ": this atomic_three function has been deleted"; + else + msg += ": atomic rev_depend returned false"; + CPPAD_ASSERT_KNOWN(false, msg.c_str() ); + } +# else + if( type == 2 ) + { atomic_base* afun = + reinterpret_cast< atomic_base* >(v_ptr); + vector empty; + afun->set_old(atom_old); + afun->rev_depend(parameter_x, type_x, depend_x, depend_y); + } + else + { atomic_three* afun = + reinterpret_cast< atomic_three* >(v_ptr); + afun->rev_depend(parameter_x, type_x, depend_x, depend_y); + } +# endif +} + + +} } } // END_CPAPD_LOCAL_SWEEP_NAMESPACE +# endif diff --git a/build-config/cppad/include/cppad/local/sweep/dev_sweep.omh b/build-config/cppad/include/cppad/local/sweep/dev_sweep.omh new file mode 100644 index 00000000..6ff99178 --- /dev/null +++ b/build-config/cppad/include/cppad/local/sweep/dev_sweep.omh @@ -0,0 +1,24 @@ +----------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 Bradley M. Bell + + CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + + This Source Code may also be made available under the following + Secondary License when the conditions for such availability set forth + in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +----------------------------------------------------------------------------- +$begin dev_sweep$$ + +$section Developer Sweep Documentation$$ + +$childtable% + include/cppad/local/sweep/forward0.hpp% + include/cppad/local/sweep/for_hes.hpp% + include/cppad/local/sweep/rev_jac.hpp% + include/cppad/local/sweep/call_atomic.hpp +%$$ + + +$end diff --git a/build-config/cppad/include/cppad/local/sweep/dynamic.hpp b/build-config/cppad/include/cppad/local/sweep/dynamic.hpp new file mode 100644 index 00000000..a63a42f9 --- /dev/null +++ b/build-config/cppad/include/cppad/local/sweep/dynamic.hpp @@ -0,0 +1,549 @@ +# ifndef CPPAD_LOCAL_SWEEP_DYNAMIC_HPP +# define CPPAD_LOCAL_SWEEP_DYNAMIC_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +# include + +// BEGIN_CPPAD_LOCAL_SWEEP_NAMESPACE +namespace CppAD { namespace local { namespace sweep { +/*! +\file sweep/dynamic.hpp +Under Consruction +*/ + +/*! +\def CPPAD_DYNAMIC_TRACE +This value is either zero or one. +Zero is the normal operational value. +If it is one, a trace for each dynamic parameter is compuation is printed. +Sometimes it is usefull to trace f.new_dynamic with the same +dynamic parameter values as during the recording +(to debug the recording process). +*/ +# define CPPAD_DYNAMIC_TRACE 0 + +/*! +Compute dynamic parameters. + +\tparam Base +The type of the parameters. + +\tparam BaseVector +is a simple vector class with elements of type Base. + +\param ind_dynamic +new value for the independent dynamic parameter vector. + +\param all_par_vec +is the vector of all the parameters. +Ths constant parameters are inputs and the dynamic parameters are outputs. + +\param dyn_par_is +is a vector with the same length as par_vec. +The i-th parameter is dynamic if and only if dyn_par_is[i] is true. + +\param dyn_ind2par_ind +is a vector with length equal to the number of dynamic parameters. +The element dyn_ind2par_ind[j] is the index in all_par_vec corresponding +to the j-th dynamic parameter. +Note that if dyn_par_is[i] is false, the i-th parameter does not +appear in this vector. + +\param dyn_par_op +is a vector with length equal to the number of dynamic parameters. +The element dyn_par_op_[j] is the operator for the j-th dynamic parameter. +Note that if dyn_par_is[i] is false, the i-th parameter does not +have a parameter in this list. + +\param dyn_par_arg +is a vector containing the arguments for the dynamic parameters. +The first argument for the j-th dynamic parameter is dyn_par_arg[k] +where +\code + k = NumArg( dyn_par_op[0] ) + ... + NumArg( dyn_par_op[j-1] ) +\endcode +The arguments for each dynamic parameter have index value +lower than the index value for the parameter. + +\param not_used_rec_base +Specifies RecBase for this call. +*/ +template +void dynamic( + pod_vector_maybe& all_par_vec , + const BaseVector& ind_dynamic , + const pod_vector& dyn_par_is , + const pod_vector& dyn_ind2par_ind , + const pod_vector& dyn_par_op , + const pod_vector& dyn_par_arg , + const RecBase& not_used_rec_base ) +{ + // number of dynamic parameters + size_t num_dynamic_par = dyn_ind2par_ind.size(); + + // vectors used in call to atomic fuctions + vector type_x; + vector taylor_x, taylor_y; +# ifndef NDEBUG + for(size_t j = 0; j < ind_dynamic.size(); ++j) + CPPAD_ASSERT_UNKNOWN( + dyn_par_is[j+1] && op_code_dyn( dyn_par_op[j] ) == ind_dyn + ); +# endif +# if CPPAD_DYNAMIC_TRACE + const char* cond_exp_name[] = { + "CondExpLt", + "CondExpLe", + "CondExpEq", + "CondExpGe", + "CondExpGt", + "CondExpNe" + }; + std::cout + << std::endl + << std::setw(10) << std::left << "index" + << std::setw(10) << std::left << "old" + << std::setw(10) << std::left << "new" + << std::setw(11) << std::left << "op" + << std::setw(26) << std::right << "dynamic i=, constant v=" + << std::endl; +# endif + // used to hold the first two parameter arguments + const Base* par[2]; + for(size_t j = 0; j < 2; ++j) + par[j] = nullptr; + // + // Initialize index in dyn_par_arg + size_t i_arg = 0; + // + // Loop throubh the dynamic parameters + size_t i_dyn = 0; + while(i_dyn < num_dynamic_par) + { // number of dynamic parameters created by this operator + size_t n_dyn = 1; + // + // parameter index for this dynamic parameter + size_t i_par = size_t( dyn_ind2par_ind[i_dyn] ); + // +# if CPPAD_DYNAMIC_TRACE + Base old_value = all_par_vec[i_par]; +# endif + // + // operator for this dynamic parameter + op_code_dyn op = op_code_dyn( dyn_par_op[i_dyn] ); + // + // number of arguments for this operator + size_t n_arg = num_arg_dyn(op); + // + // for unary or binary operators + bool unary_or_binary = true; + unary_or_binary &= op != atom_dyn; + unary_or_binary &= op != cond_exp_dyn; + unary_or_binary &= op != dis_dyn; + unary_or_binary &= op != ind_dyn; + unary_or_binary &= op != result_dyn; + if( unary_or_binary ) + { CPPAD_ASSERT_UNKNOWN( n_arg == 1 || n_arg == 2 ); + for(size_t j = 0; j < n_arg; ++j) + par[j] = & all_par_vec[ dyn_par_arg[i_arg + j] ]; + } + // + switch(op) + { + // --------------------------------------------------------------- + // standard_math_98 + // acos + case acos_dyn: + CPPAD_ASSERT_UNKNOWN( n_arg == 1 ); + all_par_vec[i_par] = acos( *par[0] ); + break; + + // asin + case asin_dyn: + CPPAD_ASSERT_UNKNOWN( n_arg == 1 ); + all_par_vec[i_par] = asin( *par[0] ); + break; + + // atan + case atan_dyn: + CPPAD_ASSERT_UNKNOWN( n_arg == 1 ); + all_par_vec[i_par] = atan( *par[0] ); + break; + + // cos + case cos_dyn: + CPPAD_ASSERT_UNKNOWN( n_arg == 1 ); + all_par_vec[i_par] = cos( *par[0] ); + break; + + // cosh + case cosh_dyn: + CPPAD_ASSERT_UNKNOWN( n_arg == 1 ); + all_par_vec[i_par] = cosh( *par[0] ); + break; + + // ind + case ind_dyn: + CPPAD_ASSERT_UNKNOWN( n_arg == 0 ); + CPPAD_ASSERT_UNKNOWN( i_par == i_dyn + 1 ); + all_par_vec[i_par] = ind_dynamic[i_dyn]; + break; + + // exp + case exp_dyn: + CPPAD_ASSERT_UNKNOWN( n_arg == 1 ); + all_par_vec[i_par] = exp( *par[0] ); + break; + + // fabs + case fabs_dyn: + CPPAD_ASSERT_UNKNOWN( n_arg == 1 ); + all_par_vec[i_par] = fabs( *par[0] ); + break; + + // log + case log_dyn: + CPPAD_ASSERT_UNKNOWN( n_arg == 1 ); + all_par_vec[i_par] = log( *par[0] ); + break; + + // sin + case sin_dyn: + CPPAD_ASSERT_UNKNOWN( n_arg == 1 ); + all_par_vec[i_par] = sin( *par[0] ); + break; + + // sinh + case sinh_dyn: + CPPAD_ASSERT_UNKNOWN( n_arg == 1 ); + all_par_vec[i_par] = sinh( *par[0] ); + break; + + // sqrt + case sqrt_dyn: + CPPAD_ASSERT_UNKNOWN( n_arg == 1 ); + all_par_vec[i_par] = sqrt( *par[0] ); + break; + + // tan + case tan_dyn: + CPPAD_ASSERT_UNKNOWN( n_arg == 1 ); + all_par_vec[i_par] = tan( *par[0] ); + break; + + // tanh + case tanh_dyn: + CPPAD_ASSERT_UNKNOWN( n_arg == 1 ); + all_par_vec[i_par] = tanh( *par[0] ); + break; + + // --------------------------------------------------------------- + // asinh + case asinh_dyn: + CPPAD_ASSERT_UNKNOWN( n_arg == 1 ); + all_par_vec[i_par] = asinh( *par[0] ); + break; + + // acosh + case acosh_dyn: + CPPAD_ASSERT_UNKNOWN( n_arg == 1 ); + all_par_vec[i_par] = acosh( *par[0] ); + break; + + // atanh + case atanh_dyn: + CPPAD_ASSERT_UNKNOWN( n_arg == 1 ); + all_par_vec[i_par] = atanh( *par[0] ); + break; + + // expm1 + case expm1_dyn: + CPPAD_ASSERT_UNKNOWN( n_arg == 1 ); + all_par_vec[i_par] = expm1( *par[0] ); + break; + + // erf + case erf_dyn: + CPPAD_ASSERT_UNKNOWN( n_arg == 1 ); + all_par_vec[i_par] = erf( *par[0] ); + break; + + // erfc + case erfc_dyn: + CPPAD_ASSERT_UNKNOWN( n_arg == 1 ); + all_par_vec[i_par] = erfc( *par[0] ); + break; + + // log1p + case log1p_dyn: + CPPAD_ASSERT_UNKNOWN( n_arg == 1 ); + all_par_vec[i_par] = log1p( *par[0] ); + break; + // --------------------------------------------------------------- + // abs + case abs_dyn: + CPPAD_ASSERT_UNKNOWN( n_arg == 1 ); + all_par_vec[i_par] = fabs( *par[0] ); + break; + + // add + case add_dyn: + CPPAD_ASSERT_UNKNOWN( n_arg == 2 ); + all_par_vec[i_par] = *par[0] + *par[1]; + break; + + // div + case div_dyn: + CPPAD_ASSERT_UNKNOWN( n_arg == 2 ); + all_par_vec[i_par] = *par[0] / *par[1]; + break; + + // mul + case mul_dyn: + CPPAD_ASSERT_UNKNOWN( n_arg == 2 ); + all_par_vec[i_par] = *par[0] * *par[1]; + break; + + // pow + case pow_dyn: + CPPAD_ASSERT_UNKNOWN( n_arg == 2 ); + all_par_vec[i_par] = pow( *par[0], *par[1] ); + break; + + // sign + case sign_dyn: + CPPAD_ASSERT_UNKNOWN( n_arg == 1 ); + all_par_vec[i_par] = sign( *par[0] ); + break; + + // sub + case sub_dyn: + CPPAD_ASSERT_UNKNOWN( n_arg == 2 ); + all_par_vec[i_par] = *par[0] - *par[1]; + break; + + // zmul + case zmul_dyn: + CPPAD_ASSERT_UNKNOWN( n_arg == 2 ); + all_par_vec[i_par] = azmul( *par[0], *par[1] ); + break; + + // --------------------------------------------------------------- + // discrete(index, argument) + case dis_dyn: + CPPAD_ASSERT_UNKNOWN( n_arg == 2 ); + all_par_vec[i_par] = discrete::eval( + size_t( dyn_par_arg[i_arg + 0] ) , // index + all_par_vec[ dyn_par_arg[i_arg + 1] ] // argument + ); +# if CPPAD_DYNAMIC_TRACE + std::cout + << std::setw(10) << std::left << i_par + << std::setw(10) << std::left << old_value + << std::setw(10) << std::left << all_par_vec[i_par] + << "=" + << std::setw(10) << std::right << op_name_dyn(op) + << "(" + << std::setw(12) << std::right << + discrete::name( size_t( dyn_par_arg[i_arg + 0] ) ); + if( dyn_par_is[ dyn_par_arg[i_arg + 1] ] ) + { std::cout << ", i=" << std::setw(10) << std::right + << dyn_par_arg[i_arg + 1]; + } + else + { std::cout << ", v=" << std::setw(10) << std::right + << all_par_vec[ dyn_par_arg[i_arg + 1] ]; + } + std::cout << ")" << std::endl; +# endif + break; + + // --------------------------------------------------------------- + // cond_exp(cop, left, right, if_true, if_false) + // (not yet implemented) + case cond_exp_dyn: + CPPAD_ASSERT_UNKNOWN( n_arg == 5 ); + all_par_vec[i_par] = CondExpOp( + CompareOp( dyn_par_arg[i_arg + 0] ) , // cop + all_par_vec[ dyn_par_arg[i_arg + 1] ] , // left + all_par_vec[ dyn_par_arg[i_arg + 2] ] , // right + all_par_vec[ dyn_par_arg[i_arg + 3] ] , // if_true + all_par_vec[ dyn_par_arg[i_arg + 4] ] // if_false + ); +# if CPPAD_DYNAMIC_TRACE + std::cout + << std::setw(10) << std::left << i_par + << std::setw(10) << std::left << old_value + << std::setw(10) << std::left << all_par_vec[i_par] + << "=" + << std::setw(10) << std::right + << cond_exp_name[ dyn_par_arg[i_arg + 0] ] + << "("; + for(size_t i = 1; i < 5; ++i) + { if( dyn_par_is[ dyn_par_arg[i_arg + i] ] ) + { std::cout << "i=" << std::setw(10) << std::right + << dyn_par_arg[i_arg + i]; + } + else + { std::cout << "v=" << std::setw(10) << std::right + << all_par_vec[ dyn_par_arg[i_arg + i] ]; + } + if( i < 4 ) + std::cout << ","; + } + std::cout << ")" << std::endl; +# endif + break; + // --------------------------------------------------------------- + // atomic function results + case result_dyn: + break; + + // atomic function call + case atom_dyn: + { size_t atom_index = size_t( dyn_par_arg[i_arg + 0] ); + size_t n = size_t( dyn_par_arg[i_arg + 1] ); + size_t m = size_t( dyn_par_arg[i_arg + 2] ); + n_dyn = size_t( dyn_par_arg[i_arg + 3] ); + n_arg = 5 + n + m; + CPPAD_ASSERT_UNKNOWN( + size_t( dyn_par_arg[i_arg + 4 + n + m] ) == n_arg + ); + // + size_t need_y = size_t(dynamic_enum); + size_t order_low = 0; + size_t order_up = 0; + size_t atom_old = 0; // not used + type_x.resize(n); + taylor_x.resize(n); + taylor_y.resize(m); + for(size_t j = 0; j < n; ++j) + { addr_t arg_j = dyn_par_arg[i_arg + 4 + j]; + taylor_x[j] = all_par_vec[ arg_j ]; + if( arg_j == 0 ) + type_x[j] = variable_enum; + else if ( dyn_par_is[arg_j] ) + type_x[j] = dynamic_enum; + else + type_x[j] = constant_enum; + } + call_atomic_forward( + taylor_x, + type_x, + need_y, + order_low, + order_up, + atom_index, + atom_old, + taylor_x, + taylor_y + ); +# if CPPAD_DYNAMIC_TRACE + // get the name of this atomic function + bool set_null = false; + size_t type = 0; // set to avoid warning + std::string name; + void* v_ptr = nullptr; // set to avoid warning + atomic_index( + set_null, atom_index, type, &name, v_ptr + ); + std::cout << "atom_dyn " << name << " arguments\n"; + for(size_t j = 0; j < n; ++j) + { std::cout << "index = " << j + << ", value = " << taylor_x[j] << std::endl; + } + std::cout << "atom_dyn " << name << " results\n"; +# endif +# ifndef NDEBUG + size_t count_dyn = 0; +# endif + for(size_t i = 0; i < m; ++i) + { i_par = size_t( dyn_par_arg[i_arg + 4 + n + i] ); + if( dyn_par_is[i_par] ) + { CPPAD_ASSERT_UNKNOWN( i_par != 0 ); + all_par_vec[i_par] = taylor_y[i]; +# ifndef NDEBUG + ++count_dyn; +# endif +# if CPPAD_DYNAMIC_TRACE + std::cout + << std::setw(10) << std::left << i_par + << std::setw(10) << std::left << old_value + << std::setw(10) << std::left << all_par_vec[i_par] + << "= " << name << "_" << i << std::endl; +# endif + } + } + CPPAD_ASSERT_UNKNOWN( count_dyn == n_dyn ); +# if CPPAD_DYNAMIC_TRACE + std::cout << "end atomic dynamic parameter results\n"; +# endif + } + break; + + // --------------------------------------------------------------- + default: + std::cerr << "op_code_dyn = " << op_name_dyn(op) << std::endl; + CPPAD_ASSERT_UNKNOWN(false); + break; + } +# if CPPAD_DYNAMIC_TRACE + if( + (op != cond_exp_dyn) & + (op != dis_dyn ) & + (op != atom_dyn ) & + (op != result_dyn ) ) + { + std::cout + << std::setw(10) << std::left << i_par + << std::setw(10) << std::left << old_value + << std::setw(10) << std::left << all_par_vec[i_par] + << "=" + << std::setw(10) << std::right << op_name_dyn(op) + << "("; + if( 0 < n_arg ) + { if( dyn_par_is[ dyn_par_arg[i_arg + 0] ] ) + { std::cout << "i=" << std::setw(10) << std::right + << dyn_par_arg[i_arg + 0]; + } + else + { std::cout << "v=" << std::setw(10) << std::right + << all_par_vec[ dyn_par_arg[i_arg + 0] ]; + } + } + if( 1 < n_arg ) + { if( dyn_par_is[ dyn_par_arg[i_arg + 1] ] ) + { std::cout << ", i=" << std::setw(10) << std::right + << dyn_par_arg[i_arg + 1]; + } + else + { std::cout << ", v=" << std::setw(10) << std::right + << all_par_vec[ dyn_par_arg[i_arg + 1] ]; + } + } + std::cout << ")" << std::endl; + } +# endif + i_arg += n_arg; + i_dyn += n_dyn; + } + CPPAD_ASSERT_UNKNOWN( i_arg == dyn_par_arg.size() ) + return; +} + +// preprocessor symbols that are local to this file +# undef CPPAD_DYNAMIC_TRACE + +} } } // END_CPPAD_LOCAL_SWEEP_NAMESPACE + +# endif diff --git a/build-config/cppad/include/cppad/local/sweep/for_hes.hpp b/build-config/cppad/include/cppad/local/sweep/for_hes.hpp new file mode 100644 index 00000000..b9474674 --- /dev/null +++ b/build-config/cppad/include/cppad/local/sweep/for_hes.hpp @@ -0,0 +1,670 @@ +# ifndef CPPAD_LOCAL_SWEEP_FOR_HES_HPP +# define CPPAD_LOCAL_SWEEP_FOR_HES_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +# include + +/* +$begin local_sweep_for_hes$$ +$spell + hes + numvar + jac + Jacobian + num_var + Addr + InvOp + setvec +$$ + +$section Forward Mode Hessian Sparsity Patterns$$ + +$head Syntax$$ +$codei%local::sweep::for_hes( + %play% , + %n% , + %numvar% , + %select_domain% , + %rev_jac_sparse% , + %for_hes_sparse% , + %not_used_rec_base +)%$$ + +$head Prototype$$ +$srcthisfile% + 0%// BEGIN PROTOTYPE%// END PROTOTYPE%1 +%$$ + + +$head Purpose$$ +Given the forward Jacobian sparsity pattern for all the variables, +and the reverse Jacobian sparsity pattern for the dependent variables, +$code for_hes$$ computes the Hessian sparsity pattern for all the independent +variables. + +$head Tracing$$ +This value is either zero or one. Zero is the normal operational value. +If it is one, a trace of Jacobian and Hessian sparsity result for every +operation for every $code for_hes$$ sweep is printed. +The sparsity patterns are printed as binary numbers with 1 (0) meaning that +the corresponding index is (is not) in the set. +$codep */ +# define CPPAD_FOR_HES_TRACE 0 +/* $$ + +$head Addr$$ +Is the type used to record address on this tape +This is allows for smaller tapes when address are smaller. + +$head Base$$ +The operation sequence in $icode play$$ was recorded using +$codei%AD<%Base%>%$$. + +$head RecBase$$ +Is the base type when this function was recorded. +This is different from $icode Base$$ if +this function object was created by $cref base2ad$$. + +$head SetVector$$ +This is a $cref SetVector$$ type. + +$head play$$ +The information stored in play +is a recording of the operations corresponding to a function +$latex F : \B{R}^n \rightarrow \B{R}^m$$ +where $icode m$$ is the number of dependent variables. + +$head n$$ +is the number of independent variables in the tape. + +$head numvar$$ +is the total number of variables in the tape; i.e., +$icode%play%->num_var_rec()%$$. +This is also the number of sets in all the sparsity patterns. + +$head select_domain$$ +is a vector with size $icode n$$ that specifies +which components of the domain to include in the Hessian sparsity pattern. +For $icode%j%= 0, ..., %n%-1%$$, the $th j$$ independent variable +will be included if and only if $icode%select_domain%[%j%]%$$ is true. +This assumes that the order of the independent variables is the same +as the order of the InvOp operators. + +$head rev_jac_sparse$$ +Is a sparsity pattern with size $icode numvar$$ by one. +For $icode%i%=1, %...%, %numvar%-1%$$, +the if the function we are computing the Hessian for has a non-zero +derivative w.r.t. variable with index $icode i$$, +the set with index $icode i$$ has the element zero. +Otherwise it has no elements. + +$head for_hes_sparse$$ +Is a sparsity pattern with size $icode%n%+1+%numvar%$$ by $icode%n%+1%$$. +The set with index zero and the element zero are not used. +The sets with index greater than $icode n$$ +are used for forward Jacobian sparsity. +The forward Hessian sparsity pattern for the variable with index $icode i$$ +corresponds to the set with index $icode i$$ in $icode for_hes_sparse$$. +The number of sets in this sparsity pattern is $icode%n%+1%$$ and the set +with index zero is not used. + +$subhead On Input$$ +For $icode%j%=1, %...%, %n%$$, +the forward Hessian sparsity pattern for the variable with index +$icode i$$ is empty. + +$subhead On Output$$ +For $icode%j%=1, %...%, %n%$$, +the forward Hessian sparsity pattern for the independent dependent variable +with index $icode%j%-1%$$ is given by the set with index $icode j$$ +in $icode for_hes_sparse$$. + +$head not_used_rec_base$$ +This argument is only used to specify the type $icode RecBase$$ for this call. + +$end +*/ + +// BEGIN_CPPAD_LOCAL_SWEEP_NAMESPACE +namespace CppAD { namespace local { namespace sweep { + +// BEGIN PROTOTYPE +template +void for_hes( + const local::player* play , + size_t n , + size_t numvar , + const pod_vector& select_domain , + const SetVector& rev_jac_sparse , + SetVector& for_hes_sparse , + const RecBase& not_used_rec_base ) +// END PROTOTYPE +{ + // length of the parameter vector (used by CppAD assert macros) +# ifndef NDEBUG + const size_t num_par = play->num_par_rec(); +# endif + + // check arguments + size_t np1 = n+1; + CPPAD_ASSERT_UNKNOWN( select_domain.size() == n ); + CPPAD_ASSERT_UNKNOWN( play->num_var_rec() == numvar ); + CPPAD_ASSERT_UNKNOWN( rev_jac_sparse.n_set() == numvar ); + CPPAD_ASSERT_UNKNOWN( for_hes_sparse.n_set() == np1+numvar ); + // + CPPAD_ASSERT_UNKNOWN( rev_jac_sparse.end() == 1 ); + CPPAD_ASSERT_UNKNOWN( for_hes_sparse.end() == np1 ); + // + CPPAD_ASSERT_UNKNOWN( numvar > 0 ); + // + // vecad_sparsity contains a sparsity pattern for each VecAD object. + // vecad_ind maps a VecAD index (beginning of the VecAD object) + // to the index for the corresponding set in vecad_sparsity. + size_t num_vecad_ind = play->num_var_vecad_ind_rec(); + size_t num_vecad_vec = play->num_var_vecad_rec(); + SetVector vecad_sparse; + pod_vector vecad_ind; + pod_vector vecad_jac; + if( num_vecad_vec > 0 ) + { size_t length; + vecad_sparse.resize(num_vecad_vec, np1); + vecad_ind.extend(num_vecad_ind); + vecad_jac.extend(num_vecad_vec); + size_t j = 0; + for(size_t i = 0; i < num_vecad_vec; i++) + { // length of this VecAD + length = play->GetVecInd(j); + // set vecad_ind to proper index for this VecAD + vecad_ind[j] = i; + // make all other values for this vector invalid + for(size_t k = 1; k <= length; k++) + vecad_ind[j+k] = num_vecad_vec; + // start of next VecAD + j += length + 1; + // initialize this vector's reverse jacobian value + vecad_jac[i] = false; + } + CPPAD_ASSERT_UNKNOWN( j == play->num_var_vecad_ind_rec() ); + } + // ------------------------------------------------------------------------ + // work space used by AFunOp. + vector atom_x; //// value of parameter arguments to function + vector type_x; // argument types + pod_vector atom_ix; // variable index (on tape) for each argument + pod_vector atom_iy; // variable index (on tape) for each result + // + // information set by atomic forward (initialization to avoid warnings) + size_t atom_index=0, atom_old=0, atom_m=0, atom_n=0, atom_i=0, atom_j=0; + // information set by atomic forward (necessary initialization) + enum_atom_state atom_state = start_atom; + // ------------------------------------------------------------------------- + // + // pointer to the beginning of the parameter vector + // (used by atomic functions) + CPPAD_ASSERT_UNKNOWN( num_par > 0 ) + const Base* parameter = play->GetPar(); + // + // which parametes are dynamic + const pod_vector& dyn_par_is( play->dyn_par_is() ); + // + // skip the BeginOp at the beginning of the recording + play::const_sequential_iterator itr = play->begin(); + // op_info + OpCode op; + size_t i_var; + const Addr* arg; + itr.op_info(op, arg, i_var); + CPPAD_ASSERT_UNKNOWN( op == BeginOp ); +# if CPPAD_FOR_HES_TRACE + vector atom_funrp; // parameter index for FunrpOp operators + std::cout << std::endl; + CppAD::vectorBool zf_value(np1); + CppAD::vectorBool zh_value(np1 * np1); +# endif + bool flag; // temporary for use in switch cases below + bool more_operators = true; + size_t count_independent = 0; + while(more_operators) + { + // next op + (++itr).op_info(op, arg, i_var); + + // does the Hessian in question have a non-zero derivative + // with respect to this variable + bool include = NumRes(op) > 0; + if( include ) + include = rev_jac_sparse.is_element(i_var, 0); + // + // operators to include even if derivative is zero + include |= op == EndOp; + include |= op == CSkipOp; + include |= op == CSumOp; + include |= op == AFunOp; + include |= op == FunapOp; + include |= op == FunavOp; + include |= op == FunrpOp; + include |= op == FunrvOp; + // + if( include ) switch( op ) + { // operators that should not occurr + // case BeginOp + + // operators that do not affect Jacobian or Hessian + // and where with a fixed number of arguments and results + case CExpOp: + case DisOp: + case LdpOp: + case LdvOp: + case ParOp: + case PriOp: + case SignOp: + case StppOp: + case StpvOp: + case StvpOp: + case StvvOp: + break; + // ------------------------------------------------- + + // independent variable operator: set J(i_var) = { i_var } + case InvOp: + CPPAD_ASSERT_UNKNOWN( for_hes_sparse.number_elements(i_var) == 0 ); + if( select_domain[count_independent] ) + { // Not using post_element becasue only adding one element + // per set + for_hes_sparse.add_element(np1 + i_var, i_var); + } + ++count_independent; + break; + + // ------------------------------------------------- + // linear operators where arg[0] is the only variable + // only assign Jacobian term J(i_var) + case AbsOp: + case DivvpOp: + case SubvpOp: + case ZmulvpOp: + for_hes_sparse.assignment( + np1 + i_var, np1 + size_t(arg[0]), for_hes_sparse + ); + break; + + // ------------------------------------------------- + // linear operators where arg[1] is the only variable + // only assign Jacobian term J(i_var) + case AddpvOp: + case MulpvOp: + case SubpvOp: + for_hes_sparse.assignment( + np1 + i_var, np1 + size_t(arg[1]), for_hes_sparse + ); + break; + + // ------------------------------------------------- + // linear operators where arg[0] and arg[1] are variables + // only assign Jacobian term J(i_var) + case AddvvOp: + case SubvvOp: + for_hes_sparse.binary_union( + np1 + i_var , + np1 + size_t(arg[0]) , + np1 + size_t(arg[1]) , + for_hes_sparse + ); + break; + + // nonlinear unary operators + case AcosOp: + case AsinOp: + case AtanOp: + case CosOp: + case CoshOp: + case ExpOp: + case LogOp: + case SinOp: + case SinhOp: + case SqrtOp: + case TanOp: + case TanhOp: + case AcoshOp: + case AsinhOp: + case AtanhOp: + case Expm1Op: + case Log1pOp: + CPPAD_ASSERT_UNKNOWN( NumArg(op) == 1 ) + sparse::for_hes_nl_unary_op( + np1, numvar, i_var, size_t(arg[0]), for_hes_sparse + ); + break; + // ------------------------------------------------- + + case CSkipOp: + itr.correct_before_increment(); + break; + // ------------------------------------------------- + + case CSumOp: + itr.correct_before_increment(); + break; + // ------------------------------------------------- + + case DivvvOp: + CPPAD_ASSERT_NARG_NRES(op, 2, 1) + sparse::for_hes_div_op( + np1, numvar, i_var, arg, for_hes_sparse + ); + break; + // ------------------------------------------------- + + case DivpvOp: + CPPAD_ASSERT_NARG_NRES(op, 2, 1) + sparse::for_hes_nl_unary_op( + np1, numvar, i_var, size_t(arg[1]), for_hes_sparse + ); + break; + // ------------------------------------------------- + + case EndOp: + CPPAD_ASSERT_NARG_NRES(op, 0, 0); + more_operators = false; + break; + // ------------------------------------------------- + + case ErfOp: + case ErfcOp: + // arg[1] is always the parameter 0 + // arg[2] is always the parameter 2 / sqrt(pi) + CPPAD_ASSERT_NARG_NRES(op, 3, 5); + sparse::for_hes_nl_unary_op( + np1, numvar, i_var, size_t(arg[0]), for_hes_sparse + ); + break; + // ------------------------------------------------- + + // ------------------------------------------------- + // logical comparison operators + case EqppOp: + case EqpvOp: + case EqvvOp: + case LtppOp: + case LtpvOp: + case LtvpOp: + case LtvvOp: + case LeppOp: + case LepvOp: + case LevpOp: + case LevvOp: + case NepvOp: + case NeppOp: + case NevvOp: + CPPAD_ASSERT_NARG_NRES(op, 2, 0); + break; + // ------------------------------------------------- + + case MulvvOp: + CPPAD_ASSERT_NARG_NRES(op, 2, 1) + sparse::for_hes_mul_op( + np1, numvar, i_var, arg, for_hes_sparse + ); + break; + // ------------------------------------------------- + + case PowpvOp: + CPPAD_ASSERT_NARG_NRES(op, 2, 3) + sparse::for_hes_nl_unary_op( + np1, numvar, i_var, size_t(arg[1]), for_hes_sparse + ); + break; + // ------------------------------------------------- + + case PowvpOp: + CPPAD_ASSERT_NARG_NRES(op, 2, 3) + sparse::for_hes_nl_unary_op( + np1, numvar, i_var, size_t(arg[0]), for_hes_sparse + ); + break; + // ------------------------------------------------- + + case PowvvOp: + CPPAD_ASSERT_NARG_NRES(op, 2, 3) + sparse::for_hes_pow_op( + np1, numvar, i_var, arg, for_hes_sparse + ); + break; + // ------------------------------------------------- + + case AFunOp: + // start or end an atomic function call + CPPAD_ASSERT_UNKNOWN( + atom_state == start_atom || atom_state == end_atom + ); + flag = atom_state == start_atom; + play::atom_op_info( + op, arg, atom_index, atom_old, atom_m, atom_n + ); + if( flag ) + { atom_state = arg_atom; + atom_i = 0; + atom_j = 0; + // + atom_x.resize( atom_n ); + type_x.resize( atom_n ); + atom_ix.resize( atom_n ); + atom_iy.resize( atom_m ); +# if CPPAD_FOR_HES_TRACE + atom_funrp.resize( atom_m ); +# endif + } + else + { CPPAD_ASSERT_UNKNOWN( atom_i == atom_m ); + CPPAD_ASSERT_UNKNOWN( atom_j == atom_n ); + atom_state = start_atom; + // + call_atomic_for_hes_sparsity( + atom_index, atom_old, atom_x, type_x, atom_ix, atom_iy, + np1, numvar, rev_jac_sparse, for_hes_sparse + ); + } + break; + + case FunapOp: + // parameter argument for a atomic function + CPPAD_ASSERT_UNKNOWN( NumArg(op) == 1 ); + CPPAD_ASSERT_UNKNOWN( atom_state == arg_atom ); + CPPAD_ASSERT_UNKNOWN( atom_i == 0 ); + CPPAD_ASSERT_UNKNOWN( atom_j < atom_n ); + CPPAD_ASSERT_UNKNOWN( size_t( arg[0] ) < num_par ); + // + atom_x[atom_j] = parameter[arg[0]]; + // argument type + if( dyn_par_is[arg[0]] ) + type_x[atom_j] = dynamic_enum; + else + type_x[atom_j] = constant_enum; + atom_ix[atom_j] = 0; // special variable used for parameters + // + ++atom_j; + if( atom_j == atom_n ) + atom_state = ret_atom; + break; + + case FunavOp: + // variable argument for a atomic function + CPPAD_ASSERT_UNKNOWN( NumArg(op) == 1 ); + CPPAD_ASSERT_UNKNOWN( atom_state == arg_atom ); + CPPAD_ASSERT_UNKNOWN( atom_i == 0 ); + CPPAD_ASSERT_UNKNOWN( atom_j < atom_n ); + // + // arguemnt variables not avaialbe during sparisty calculations + atom_x[atom_j] = CppAD::numeric_limits::quiet_NaN(); + type_x[atom_j] = variable_enum; + atom_ix[atom_j] = size_t(arg[0]); // variable for this argument + // + ++atom_j; + if( atom_j == atom_n ) + atom_state = ret_atom; + break; + + case FunrpOp: + // parameter result for a atomic function + CPPAD_ASSERT_NARG_NRES(op, 1, 0); + CPPAD_ASSERT_UNKNOWN( atom_state == ret_atom ); + CPPAD_ASSERT_UNKNOWN( atom_i < atom_m ); + CPPAD_ASSERT_UNKNOWN( atom_j == atom_n ); + CPPAD_ASSERT_UNKNOWN( size_t( arg[0] ) < num_par ); + // + atom_iy[atom_i] = 0; // special variable used for parameters +# if CPPAD_FOR_HES_TRACE + // remember argument for delayed tracing + atom_funrp[atom_i] = arg[0]; +# endif + ++atom_i; + if( atom_i == atom_m ) + atom_state = end_atom; + break; + + case FunrvOp: + // variable result for a atomic function + CPPAD_ASSERT_NARG_NRES(op, 0, 1); + CPPAD_ASSERT_UNKNOWN( atom_state == ret_atom ); + CPPAD_ASSERT_UNKNOWN( atom_i < atom_m ); + CPPAD_ASSERT_UNKNOWN( atom_j == atom_n ); + // + atom_iy[atom_i] = i_var; // variable index for this result + // + ++atom_i; + if( atom_i == atom_m ) + atom_state = end_atom; + break; + // ------------------------------------------------- + + case ZmulvvOp: + CPPAD_ASSERT_NARG_NRES(op, 2, 1) + sparse::for_hes_mul_op( + np1, numvar, i_var, arg, for_hes_sparse + ); + break; + + // ------------------------------------------------- + + default: + CPPAD_ASSERT_UNKNOWN(0); + } +# if CPPAD_FOR_HES_TRACE + typedef typename SetVector::const_iterator const_iterator; + if( op == AFunOp && atom_state == start_atom ) + { // print operators that have been delayed + CPPAD_ASSERT_UNKNOWN( atom_m == atom_iy.size() ); + CPPAD_ASSERT_UNKNOWN( itr.op_index() > atom_m ); + CPPAD_ASSERT_NARG_NRES(FunrpOp, 1, 0); + CPPAD_ASSERT_NARG_NRES(FunrvOp, 0, 1); + addr_t arg_tmp[1]; + for(size_t k = 0; k < atom_m; k++) + { size_t k_var = atom_iy[k]; + // value for this variable + for(size_t i = 0; i < np1; i++) + { zf_value[i] = false; + for(size_t j = 0; j < np1; j++) + zh_value[i * np1 + j] = false; + } + const_iterator itr_1(for_hes_sparse, np1 + i_var); + size_t j = *itr_1; + while( j < np1 ) + { zf_value[j] = true; + j = *(++itr_1); + } + for(size_t i = 0; i < np1; i++) + { const_iterator itr_2(for_hes_sparse, i); + j = *itr_2; + while( j < np1 ) + { zh_value[i * np1 + j] = true; + j = *(++itr_2); + } + } + OpCode op_tmp = FunrvOp; + if( k_var == 0 ) + { op_tmp = FunrpOp; + arg_tmp[0] = atom_funrp[k]; + } + // k_var is zero when there is no result + printOp( + std::cout, + play, + itr.op_index() - atom_m + k, + k_var, + op_tmp, + arg_tmp + ); + if( k_var > 0 ) printOpResult( + std::cout, + 1, + &zf_value, + 1, + &zh_value + ); + std::cout << std::endl; + } + } + for(size_t i = 0; i < np1; i++) + { zf_value[i] = false; + for(size_t j = 0; j < np1; j++) + zh_value[i * np1 + j] = false; + } + const_iterator itr_1(for_hes_sparse, np1 + i_var); + size_t j = *itr_1; + while( j < np1 ) + { zf_value[j] = true; + j = *(++itr_1); + } + for(size_t i = 0; i < np1; i++) + { const_iterator itr_2(for_hes_sparse, i); + j = *itr_2; + while( j < np1 ) + { zh_value[i * np1 + j] = true; + j = *(++itr_2); + } + } + // must delay print for these cases till after atomic function call + bool delay_print = op == FunrpOp; + delay_print |= op == FunrvOp; + if( ! delay_print ) + { printOp( + std::cout, + play, + itr.op_index(), + i_var, + op, + arg + ); + if( NumRes(op) > 0 && (! delay_print) ) printOpResult( + std::cout, + 1, + &zf_value, + 1, + &zh_value + ); + std::cout << std::endl; + } + } + std::cout << std::endl; +# else + } +# endif + + return; +} +} } } // END_CPPAD_LOCAL_SWEEP_NAMESPACE + +// preprocessor symbols that are local to this file +# undef CPPAD_FOR_HES_TRACE + +# endif diff --git a/build-config/cppad/include/cppad/local/sweep/for_jac.hpp b/build-config/cppad/include/cppad/local/sweep/for_jac.hpp new file mode 100644 index 00000000..228f1047 --- /dev/null +++ b/build-config/cppad/include/cppad/local/sweep/for_jac.hpp @@ -0,0 +1,836 @@ +# ifndef CPPAD_LOCAL_SWEEP_FOR_JAC_HPP +# define CPPAD_LOCAL_SWEEP_FOR_JAC_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +# include +# include +# include +# include + +// BEGIN_CPPAD_LOCAL_SWEEP_NAMESPACE +namespace CppAD { namespace local { namespace sweep { +/*! +\file sweep/for_jac.hpp +Compute Forward mode Jacobian sparsity patterns. +*/ + +/*! +\def CPPAD_FOR_JAC_TRACE +This value is either zero or one. +Zero is the normal operational value. +If it is one, a trace of every for_jac_sweep computation is printed. +*/ +# define CPPAD_FOR_JAC_TRACE 0 + +/*! +Given the sparsity pattern for the independent variables, +ForJacSweep computes the sparsity pattern for all the other variables. + +\tparam Base +this operation sequence was recorded using AD. + +\tparam Vector_set +is the type used for vectors of sets. It can be either +sparse::pack_setvec or sparse::list_setvec. + +\param dependency +Are the derivatives with respect to left and right of the expression below +considered to be non-zero: +\code + CondExpRel(left, right, if_true, if_false) +\endcode +This is used by the optimizer to obtain the correct dependency relations. + +\param n +is the number of independent variables on the tape. + +\param numvar +is the total number of variables on the tape; i.e., + play->num_var_rec(). + +\param play +The information stored in play +is a recording of the operations corresponding to a function +\f[ + F : {\bf R}^n \rightarrow {\bf R}^m +\f] +where \f$ n \f$ is the number of independent variables +and \f$ m \f$ is the number of dependent variables. + +\param var_sparsity +\b Input: For j = 1 , ... , n, +the sparsity pattern for the independent variable with index (j-1) +corresponds to the set with index j in var_sparsity. +\n +\n +\b Output: For i = n + 1 , ... , numvar - 1, +the sparsity pattern for the variable with index i on the tape +corresponds to the set with index i in var_sparsity. + +\par Checked Assertions: +\li numvar == var_sparsity.n_set() +\li numvar == play->num_var_rec() + +\param not_used_rec_base +Specifies RecBase for this call. +*/ + +template +void for_jac( + const local::player* play, + bool dependency , + size_t n , + size_t numvar , + Vector_set& var_sparsity, + const RecBase& not_used_rec_base +) +{ + size_t i, j, k; + + // check numvar argument + CPPAD_ASSERT_UNKNOWN( play->num_var_rec() == numvar ); + CPPAD_ASSERT_UNKNOWN( var_sparsity.n_set() == numvar ); + + // length of the parameter vector (used by CppAD assert macros) + const size_t num_par = play->num_par_rec(); + + // cum_sparsity accumulates sparsity pattern a cumulative sum + size_t limit = var_sparsity.end(); + + // vecad_sparsity contains a sparsity pattern from each VecAD object + // to all the other variables. + // vecad_ind maps a VecAD index (the beginning of the + // VecAD object) to its from index in vecad_sparsity + size_t num_vecad_ind = play->num_var_vecad_ind_rec(); + size_t num_vecad_vec = play->num_var_vecad_rec(); + Vector_set vecad_sparsity; + pod_vector vecad_ind; + if( num_vecad_vec > 0 ) + { size_t length; + vecad_sparsity.resize(num_vecad_vec, limit); + vecad_ind.extend(num_vecad_ind); + j = 0; + for(i = 0; i < num_vecad_vec; i++) + { // length of this VecAD + length = play->GetVecInd(j); + // set to proper index for this VecAD + vecad_ind[j] = i; + for(k = 1; k <= length; k++) + vecad_ind[j+k] = num_vecad_vec; // invalid index + // start of next VecAD + j += length + 1; + } + CPPAD_ASSERT_UNKNOWN( j == play->num_var_vecad_ind_rec() ); + } + + // -------------------------------------------------------------- + // work space used by AFunOp. + vector atom_x; //// value of parameter arguments to function + vector type_x; // argument types + pod_vector atom_ix; // variable index (on tape) for each argument + pod_vector atom_iy; // variable index (on tape) for each result + // + // information set by atomic forward (initialization to avoid warnings) + size_t atom_index=0, atom_old=0, atom_m=0, atom_n=0, atom_i=0, atom_j=0; + // information set by atomic forward (necessary initialization) + enum_atom_state atom_state = start_atom; + // -------------------------------------------------------------- + // + // pointer to the beginning of the parameter vector + // (used by atomic functions) + CPPAD_ASSERT_UNKNOWN( num_par > 0 ) + const Base* parameter = play->GetPar(); + // + // which parametes are dynamic + const pod_vector& dyn_par_is( play->dyn_par_is() ); + // +# if CPPAD_FOR_JAC_TRACE + vector atom_funrp; // parameter index for FunrpOp operators + std::cout << std::endl; + CppAD::vectorBool z_value(limit); +# endif + + // skip the BeginOp at the beginning of the recording + play::const_sequential_iterator itr = play->begin(); + // op_info + OpCode op; + size_t i_var; + const Addr* arg; + itr.op_info(op, arg, i_var); + CPPAD_ASSERT_UNKNOWN( op == BeginOp ); + // + bool more_operators = true; + while(more_operators) + { bool flag; // temporary for use in switch cases. + + // this op + (++itr).op_info(op, arg, i_var); + + // rest of information depends on the case + switch( op ) + { + case AbsOp: + CPPAD_ASSERT_NARG_NRES(op, 1, 1); + sparse::for_jac_unary_op( + i_var, size_t(arg[0]), var_sparsity + ); + break; + // ------------------------------------------------- + + case AddvvOp: + CPPAD_ASSERT_NARG_NRES(op, 2, 1); + sparse::for_jac_binary_op( + i_var, arg, var_sparsity + ); + break; + // ------------------------------------------------- + + case AddpvOp: + CPPAD_ASSERT_NARG_NRES(op, 2, 1); + sparse::for_jac_unary_op( + i_var, size_t(arg[1]), var_sparsity + ); + break; + // ------------------------------------------------- + + case AcosOp: + // sqrt(1 - x * x), acos(x) + CPPAD_ASSERT_NARG_NRES(op, 1, 2); + sparse::for_jac_unary_op( + i_var, size_t(arg[0]), var_sparsity + ); + break; + // ------------------------------------------------- + + case AcoshOp: + // sqrt(x * x - 1), acosh(x) + CPPAD_ASSERT_NARG_NRES(op, 1, 2); + sparse::for_jac_unary_op( + i_var, size_t(arg[0]), var_sparsity + ); + break; + // ------------------------------------------------- + + case AsinOp: + // sqrt(1 - x * x), asin(x) + CPPAD_ASSERT_NARG_NRES(op, 1, 2); + sparse::for_jac_unary_op( + i_var, size_t(arg[0]), var_sparsity + ); + break; + // ------------------------------------------------- + + case AsinhOp: + // sqrt(1 + x * x), asinh(x) + CPPAD_ASSERT_NARG_NRES(op, 1, 2); + sparse::for_jac_unary_op( + i_var, size_t(arg[0]), var_sparsity + ); + break; + // ------------------------------------------------- + + case AtanOp: + // 1 + x * x, atan(x) + CPPAD_ASSERT_NARG_NRES(op, 1, 2); + sparse::for_jac_unary_op( + i_var, size_t(arg[0]), var_sparsity + ); + break; + // ------------------------------------------------- + + case AtanhOp: + // 1 - x * x, atanh(x) + CPPAD_ASSERT_NARG_NRES(op, 1, 2); + sparse::for_jac_unary_op( + i_var, size_t(arg[0]), var_sparsity + ); + break; + // ------------------------------------------------- + + case CSkipOp: + itr.correct_before_increment(); + break; + // ------------------------------------------------- + + case CSumOp: + forward_sparse_jacobian_csum_op( + i_var, arg, var_sparsity + ); + itr.correct_before_increment(); + break; + // ------------------------------------------------- + + case CExpOp: + forward_sparse_jacobian_cond_op( + dependency, i_var, arg, num_par, var_sparsity + ); + break; + // -------------------------------------------------- + + case CosOp: + // sin(x), cos(x) + CPPAD_ASSERT_NARG_NRES(op, 1, 2); + sparse::for_jac_unary_op( + i_var, size_t(arg[0]), var_sparsity + ); + break; + // --------------------------------------------------- + + case CoshOp: + // sinh(x), cosh(x) + CPPAD_ASSERT_NARG_NRES(op, 1, 2); + sparse::for_jac_unary_op( + i_var, size_t(arg[0]), var_sparsity + ); + break; + // ------------------------------------------------- + + case DisOp: + CPPAD_ASSERT_NARG_NRES(op, 2, 1); + // derivative is identically zero but dependency is not + if( dependency ) sparse::for_jac_unary_op( + i_var, size_t(arg[1]), var_sparsity + ); + else + var_sparsity.clear(i_var); + break; + // ------------------------------------------------- + + case DivvvOp: + CPPAD_ASSERT_NARG_NRES(op, 2, 1); + sparse::for_jac_binary_op( + i_var, arg, var_sparsity + ); + break; + // ------------------------------------------------- + + case DivpvOp: + CPPAD_ASSERT_NARG_NRES(op, 2, 1); + sparse::for_jac_unary_op( + i_var, size_t(arg[1]), var_sparsity + ); + break; + // ------------------------------------------------- + + case DivvpOp: + CPPAD_ASSERT_NARG_NRES(op, 2, 1); + sparse::for_jac_unary_op( + i_var, size_t(arg[0]), var_sparsity + ); + break; + // ------------------------------------------------- + + case EndOp: + CPPAD_ASSERT_NARG_NRES(op, 0, 0); + more_operators = false; + break; + // ------------------------------------------------- + + case ErfOp: + case ErfcOp: + // arg[1] is always the parameter 0 + // arg[0] is always the parameter 2 / sqrt(pi) + CPPAD_ASSERT_NARG_NRES(op, 3, 5); + sparse::for_jac_unary_op( + i_var, size_t(arg[0]), var_sparsity + ); + break; + // ------------------------------------------------- + + case ExpOp: + CPPAD_ASSERT_NARG_NRES(op, 1, 1); + sparse::for_jac_unary_op( + i_var, size_t(arg[0]), var_sparsity + ); + break; + // ------------------------------------------------- + + case Expm1Op: + CPPAD_ASSERT_NARG_NRES(op, 1, 1); + sparse::for_jac_unary_op( + i_var, size_t(arg[0]), var_sparsity + ); + break; + // ------------------------------------------------- + + case InvOp: + CPPAD_ASSERT_NARG_NRES(op, 0, 1); + // sparsity pattern is already defined + break; + // ------------------------------------------------- + + case LdpOp: + forward_sparse_load_op( + dependency, + op, + i_var, + arg, + num_vecad_ind, + vecad_ind.data(), + var_sparsity, + vecad_sparsity + ); + break; + // ------------------------------------------------- + + case LdvOp: + forward_sparse_load_op( + dependency, + op, + i_var, + arg, + num_vecad_ind, + vecad_ind.data(), + var_sparsity, + vecad_sparsity + ); + break; + // ------------------------------------------------- + + case EqppOp: + case EqpvOp: + case EqvvOp: + case LtppOp: + case LtpvOp: + case LtvpOp: + case LtvvOp: + case LeppOp: + case LepvOp: + case LevpOp: + case LevvOp: + case NeppOp: + case NepvOp: + case NevvOp: + CPPAD_ASSERT_NARG_NRES(op, 2, 0); + break; + // ------------------------------------------------- + + case LogOp: + CPPAD_ASSERT_NARG_NRES(op, 1, 1); + sparse::for_jac_unary_op( + i_var, size_t(arg[0]), var_sparsity + ); + break; + // ------------------------------------------------- + + case Log1pOp: + CPPAD_ASSERT_NARG_NRES(op, 1, 1); + sparse::for_jac_unary_op( + i_var, size_t(arg[0]), var_sparsity + ); + break; + // ------------------------------------------------- + + case MulpvOp: + CPPAD_ASSERT_NARG_NRES(op, 2, 1); + sparse::for_jac_unary_op( + i_var, size_t(arg[1]), var_sparsity + ); + break; + // ------------------------------------------------- + + case MulvvOp: + CPPAD_ASSERT_NARG_NRES(op, 2, 1); + sparse::for_jac_binary_op( + i_var, arg, var_sparsity + ); + break; + // ------------------------------------------------- + + case ParOp: + CPPAD_ASSERT_NARG_NRES(op, 1, 1); + var_sparsity.clear(i_var); + break; + // ------------------------------------------------- + + case PowvpOp: + CPPAD_ASSERT_NARG_NRES(op, 2, 3); + sparse::for_jac_unary_op( + i_var, size_t(arg[0]), var_sparsity + ); + break; + // ------------------------------------------------- + + case PowpvOp: + CPPAD_ASSERT_NARG_NRES(op, 2, 3); + sparse::for_jac_unary_op( + i_var, size_t(arg[1]), var_sparsity + ); + break; + // ------------------------------------------------- + + case PowvvOp: + CPPAD_ASSERT_NARG_NRES(op, 2, 3); + sparse::for_jac_binary_op( + i_var, arg, var_sparsity + ); + break; + // ------------------------------------------------- + + case PriOp: + CPPAD_ASSERT_NARG_NRES(op, 5, 0); + break; + // ------------------------------------------------- + + case SignOp: + CPPAD_ASSERT_NARG_NRES(op, 1, 1); + // derivative is identically zero but dependency is not + if( dependency ) sparse::for_jac_unary_op( + i_var, size_t(arg[0]), var_sparsity + ); + else + var_sparsity.clear(i_var); + break; + // ------------------------------------------------- + + case SinOp: + // cos(x), sin(x) + CPPAD_ASSERT_NARG_NRES(op, 1, 2); + sparse::for_jac_unary_op( + i_var, size_t(arg[0]), var_sparsity + ); + break; + // ------------------------------------------------- + + case SinhOp: + // cosh(x), sinh(x) + CPPAD_ASSERT_NARG_NRES(op, 1, 2); + sparse::for_jac_unary_op( + i_var, size_t(arg[0]), var_sparsity + ); + break; + // ------------------------------------------------- + + case SqrtOp: + CPPAD_ASSERT_NARG_NRES(op, 1, 1); + sparse::for_jac_unary_op( + i_var, size_t(arg[0]), var_sparsity + ); + break; + // ------------------------------------------------- + + case StppOp: + CPPAD_ASSERT_NARG_NRES(op, 3, 0); + // if both arguments are parameters does not affect sparsity + // or dependency + break; + // ------------------------------------------------- + + case StpvOp: + forward_sparse_store_op( + dependency, + op, + arg, + num_vecad_ind, + vecad_ind.data(), + var_sparsity, + vecad_sparsity + ); + break; + // ------------------------------------------------- + + case StvpOp: + CPPAD_ASSERT_NARG_NRES(op, 3, 0); + forward_sparse_store_op( + dependency, + op, + arg, + num_vecad_ind, + vecad_ind.data(), + var_sparsity, + vecad_sparsity + ); + break; + // ------------------------------------------------- + + case StvvOp: + forward_sparse_store_op( + dependency, + op, + arg, + num_vecad_ind, + vecad_ind.data(), + var_sparsity, + vecad_sparsity + ); + break; + // ------------------------------------------------- + + case SubvvOp: + CPPAD_ASSERT_NARG_NRES(op, 2, 1); + sparse::for_jac_binary_op( + i_var, arg, var_sparsity + ); + break; + // ------------------------------------------------- + + case SubpvOp: + CPPAD_ASSERT_NARG_NRES(op, 2, 1); + sparse::for_jac_unary_op( + i_var, size_t(arg[1]), var_sparsity + ); + break; + // ------------------------------------------------- + + case SubvpOp: + CPPAD_ASSERT_NARG_NRES(op, 2, 1); + sparse::for_jac_unary_op( + i_var, size_t(arg[0]), var_sparsity + ); + break; + // ------------------------------------------------- + + case TanOp: + // tan(x)^2, tan(x) + CPPAD_ASSERT_NARG_NRES(op, 1, 2); + sparse::for_jac_unary_op( + i_var, size_t(arg[0]), var_sparsity + ); + break; + // ------------------------------------------------- + + case TanhOp: + // tanh(x)^2, tanh(x) + CPPAD_ASSERT_NARG_NRES(op, 1, 2); + sparse::for_jac_unary_op( + i_var, size_t(arg[0]), var_sparsity + ); + break; + // ------------------------------------------------- + + case AFunOp: + // start or end an atomic function call + CPPAD_ASSERT_UNKNOWN( + atom_state == start_atom || atom_state == end_atom + ); + flag = atom_state == start_atom; + play::atom_op_info( + op, arg, atom_index, atom_old, atom_m, atom_n + ); + if( flag ) + { atom_state = arg_atom; + atom_i = 0; + atom_j = 0; + // + atom_x.resize( atom_n ); + type_x.resize( atom_n ); + atom_ix.resize( atom_n ); + atom_iy.resize( atom_m ); +# if CPPAD_FOR_JAC_TRACE + atom_funrp.resize( atom_m ); +# endif + } + else + { CPPAD_ASSERT_UNKNOWN( atom_i == atom_m ); + CPPAD_ASSERT_UNKNOWN( atom_j == atom_n ); + atom_state = start_atom; + // + call_atomic_for_jac_sparsity( + atom_index, + atom_old, + dependency, + atom_x, + type_x, + atom_ix, + atom_iy, + var_sparsity + ); + } + break; + + case FunapOp: + // parameter argument for a atomic function + CPPAD_ASSERT_UNKNOWN( NumArg(op) == 1 ); + CPPAD_ASSERT_UNKNOWN( atom_state == arg_atom ); + CPPAD_ASSERT_UNKNOWN( atom_i == 0 ); + CPPAD_ASSERT_UNKNOWN( atom_j < atom_n ); + CPPAD_ASSERT_UNKNOWN( size_t( arg[0] ) < num_par ); + // + atom_x[atom_j] = parameter[arg[0]]; + // argument type + if( dyn_par_is[arg[0]] ) + type_x[atom_j] = dynamic_enum; + else + type_x[atom_j] = constant_enum; + atom_ix[atom_j] = 0; // special variable used for parameters + // + ++atom_j; + if( atom_j == atom_n ) + atom_state = ret_atom; + break; + + case FunavOp: + // variable argument for a atomic function + CPPAD_ASSERT_UNKNOWN( NumArg(op) == 1 ); + CPPAD_ASSERT_UNKNOWN( atom_state == arg_atom ); + CPPAD_ASSERT_UNKNOWN( atom_i == 0 ); + CPPAD_ASSERT_UNKNOWN( atom_j < atom_n ); + // + // argument variables not avaiable during sparsity calculations + atom_x[atom_j] = CppAD::numeric_limits::quiet_NaN(); + type_x[atom_j] = variable_enum; + atom_ix[atom_j] = size_t(arg[0]); // variable for this argument + // + ++atom_j; + if( atom_j == atom_n ) + atom_state = ret_atom; + break; + + case FunrpOp: + // parameter result for a atomic function + CPPAD_ASSERT_NARG_NRES(op, 1, 0); + CPPAD_ASSERT_UNKNOWN( atom_state == ret_atom ); + CPPAD_ASSERT_UNKNOWN( atom_i < atom_m ); + CPPAD_ASSERT_UNKNOWN( atom_j == atom_n ); + CPPAD_ASSERT_UNKNOWN( size_t( arg[0] ) < num_par ); + // + atom_iy[atom_i] = 0; // special value for parameters +# if CPPAD_FOR_JAC_TRACE + // remember argument for delayed tracing + atom_funrp[atom_i] = arg[0]; +# endif + ++atom_i; + if( atom_i == atom_m ) + atom_state = end_atom; + break; + + case FunrvOp: + // variable result for a atomic function + CPPAD_ASSERT_NARG_NRES(op, 0, 1); + CPPAD_ASSERT_UNKNOWN( atom_state == ret_atom ); + CPPAD_ASSERT_UNKNOWN( atom_i < atom_m ); + CPPAD_ASSERT_UNKNOWN( atom_j == atom_n ); + // + atom_iy[atom_i] = i_var; // variable index for this result + // + ++atom_i; + if( atom_i == atom_m ) + atom_state = end_atom; + break; + // ------------------------------------------------- + + case ZmulpvOp: + CPPAD_ASSERT_NARG_NRES(op, 2, 1); + sparse::for_jac_unary_op( + i_var, size_t(arg[1]), var_sparsity + ); + break; + // ------------------------------------------------- + + case ZmulvpOp: + CPPAD_ASSERT_NARG_NRES(op, 2, 1); + sparse::for_jac_unary_op( + i_var, size_t(arg[0]), var_sparsity + ); + break; + // ------------------------------------------------- + + case ZmulvvOp: + CPPAD_ASSERT_NARG_NRES(op, 2, 1); + sparse::for_jac_binary_op( + i_var, arg, var_sparsity + ); + break; + // ------------------------------------------------- + + default: + CPPAD_ASSERT_UNKNOWN(0); + } +# if CPPAD_FOR_JAC_TRACE + if( op == AFunOp && atom_state == start_atom ) + { // print operators that have been delayed + CPPAD_ASSERT_UNKNOWN( atom_m == atom_iy.size() ); + CPPAD_ASSERT_UNKNOWN( itr.op_index() > atom_m ); + CPPAD_ASSERT_NARG_NRES(FunrpOp, 1, 0); + CPPAD_ASSERT_NARG_NRES(FunrvOp, 0, 1); + addr_t arg_tmp[1]; + for(i = 0; i < atom_m; i++) + { size_t j_var = atom_iy[i]; + // value for this variable + for(j = 0; j < limit; j++) + z_value[j] = false; + typename Vector_set::const_iterator itr(var_sparsity, j_var); + j = *itr; + while( j < limit ) + { z_value[j] = true; + j = *(++itr); + } + OpCode op_tmp = FunrvOp; + if( j_var == 0 ) + { op_tmp = FunrpOp; + arg_tmp[0] = atom_funrp[i]; + } + // j_var is zero when there is no result. + printOp( + std::cout, + play, + itr.op_index() - atom_m + i, + j_var, + op_tmp, + arg_tmp + ); + if( j_var > 0 ) printOpResult( + std::cout, + 1, + &z_value, + 0, + (CppAD::vectorBool *) nullptr + ); + std::cout << std::endl; + } + } + // value for this variable + for(j = 0; j < limit; j++) + z_value[j] = false; + typename Vector_set::const_iterator itr(var_sparsity, i_var); + j = *itr; + while( j < limit ) + { z_value[j] = true; + j = *(++itr); + } + // must delay print for these cases till after atomic function call + bool delay_print = op == FunrpOp; + delay_print |= op == FunrvOp; + if( ! delay_print ) + { printOp( + std::cout, + play, + itr.op_index(), + i_var, + op, + arg + ); + if( NumRes(op) > 0 && (! delay_print) ) printOpResult( + std::cout, + 1, + &z_value, + 0, + (CppAD::vectorBool *) nullptr + ); + std::cout << std::endl; + } + } + std::cout << std::endl; +# else + } +# endif + + return; +} + +} } } // END_CPPAD_LOCAL_SWEEP_NAMESPACE + +// preprocessor symbols that are local to this file +# undef CPPAD_FOR_JAC_TRACE + +# endif diff --git a/build-config/cppad/include/cppad/local/sweep/forward0.hpp b/build-config/cppad/include/cppad/local/sweep/forward0.hpp new file mode 100644 index 00000000..44397dd8 --- /dev/null +++ b/build-config/cppad/include/cppad/local/sweep/forward0.hpp @@ -0,0 +1,995 @@ +# ifndef CPPAD_LOCAL_SWEEP_FORWARD0_HPP +# define CPPAD_LOCAL_SWEEP_FORWARD0_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +# include +# include + +// BEGIN_CPPAD_LOCAL_SWEEP_NAMESPACE +namespace CppAD { namespace local { namespace sweep { +/*! +\file sweep/forward0.hpp +Compute zero order forward mode Taylor coefficients. +*/ + +/* + ------------------------------------------------------------------------------ +$begin sweep_forward0$$ +$spell + Taylor + numvar + cskip + op + var + Pri + num + Vec +$$ +$section Compute Zero Order Forward Mode Taylor Coefficients$$ + +$head Syntax$$ +$codei% forward0( + %play%, + %s_out%, + %print%, + %n%, + %numvar%, + %J%, + %taylor%, + %cskip_op%, + %load_op2var%, + %compare_change_count%, + %compare_change_number%, + %compare_change_op_index%, + %not_used_rec_base% +)%$$ + +$head CPPAD_FORWARD0_TRACE$$ +This value is either zero or one. +Zero is the normal operational value. +If it is one, a trace of every zero order forward mode computation is printed. +$srccode%hpp% */ +# define CPPAD_FORWARD0_TRACE 0 +/* %$$ + +$head Base$$ +The type used during the forward mode computations; i.e., the corresponding +recording of operations used the type $codei%AD<%Base%>%$$. + +$head s_out$$ +Is the stream where output corresponding to PriOp operations will +be written. + +$head print$$ +If print is false, +suppress the output that is otherwise generated by the PriOp instructions. + +$head n$$ +is the number of independent variables on the tape. + +$head numvar$$ +is the total number of variables on the tape. +This is also equal to the number of rows in the matrix taylor; i.e., +$icode%play%->num_var_rec()%$$. + +$head play$$ +The information stored in play +is a recording of the operations corresponding to a function +$latex \[ + f : \B{R}^n \rightarrow \B{R}^m +\] $$ +where $icode n$$ is the number of independent variables and +$icode m$$ is the number of dependent variables. + +$head J$$ +Is the number of columns in the coefficient matrix taylor. +This must be greater than or equal one. + +$head taylor$$ +Is the matrix of Taylor coefficients. + +$subhead Input$$ +For $icode%i% = 1 , %...% , %n%$$, +$icode taylor [%i% * %J% + 0]%$$ +is the zero order Taylor coefficient for variable with index +$icode j$$ on the tape (these are the independent variables). + +$subhead Output$$ +For $icode%i% = %n%+1 , %...% , %numvar%-1%$$, +$icode taylor [%i% * %J% + 0]%$$ +is the zero order Taylor coefficient for the variable with +index i on the tape. + +$head cskip_op$$ +Is a vector with size $icode%play%->num_op_rec()%$$. +The input value of the elements does not matter. +Upon return, if $icode%cskip_op%[%i%]%$$ is true, +the operator index $icode i$$ does not affect any of the dependent variable +(given the value of the independent variables). + +$head load_op2var$$ +Is a vector with size $icode%play%->num_var_load_rec()%$$. +The input value of the elements does not matter. +Upon return, +$icode%load_op2var%[%i%]%$$ +is the variable corresponding to the $th i$$ variable VecAD +$cref/load/op_code_var/Load/$$ operator. +Note that even though the VecAD vector is a variable, the load +can correspond to an element that is a parameter in which case +$icode%load_op2var%[%i%]%$$ is zero. + +$head compare_change_count$$ +Is the compare change count value at which $icode compare_change_op_index$$ +is returned. If it is zero, the comparison changes are not counted. + +$head compare_change_number$$ +If $icode compare_change_count$$ is zero, this value is set to zero. +Otherwise, the return value is the number of comparison operations +that have a different result from when the information in +$icode play$$ was recorded. + +$head compare_change_op_index$$ +If $icode compare_change_count$$ is zero, this value is set to zero. +Otherwise it is the operator index (see forward_next) for the +comparison operation that has a different result from when the information in +play was recorded. +This is not the first comparison that is different, +but rather the $icode compare_change_count$$ comparison. + +$head not_used_rec_base$$ +Specifies $icode RecBase$$ for this call. + +$end +*/ + +template +void forward0( + const local::player* play, + std::ostream& s_out, + bool print, + size_t n, + size_t numvar, + size_t J, + Base* taylor, + bool* cskip_op, + pod_vector& load_op2var, + size_t compare_change_count, + size_t& compare_change_number, + size_t& compare_change_op_index, + const RecBase& not_used_rec_base +) +{ CPPAD_ASSERT_UNKNOWN( J >= 1 ); + CPPAD_ASSERT_UNKNOWN( play->num_var_rec() == numvar ); + + // use p, q, r so other forward sweeps can use code defined here + size_t p = 0; + size_t q = 0; + size_t r = 1; + + // initialize the comparison operator counter + if( p == 0 ) + { compare_change_number = 0; + compare_change_op_index = 0; + } + + // If this includes a zero calculation, initialize this information + pod_vector vec_ad2isvar; + pod_vector vec_ad2index; + if( p == 0 ) + { size_t i; + + // this includes order zero calculation, initialize vector indices + size_t num = play->num_var_vecad_ind_rec(); + if( num > 0 ) + { vec_ad2isvar.extend(num); + vec_ad2index.extend(num); + for(i = 0; i < num; i++) + { vec_ad2index[i] = play->GetVecInd(i); + vec_ad2isvar[i] = false; + } + } + // includes zero order, so initialize conditional skip flags + num = play->num_op_rec(); + for(i = 0; i < num; i++) + cskip_op[i] = false; + } + + // information used by atomic function operators + const pod_vector& dyn_par_is( play->dyn_par_is() ); + const size_t need_y = size_t( variable_enum ); + const size_t order_low = p; + const size_t order_up = q; + + // vectors used by atomic function operators + vector atom_par_x; // argument parameter values + vector atom_type_x; // argument type + vector atom_tx; // argument vector Taylor coefficients + vector atom_ty; // result vector Taylor coefficients + // + // information defined by atomic function operators + size_t atom_index=0, atom_old=0, atom_m=0, atom_n=0, atom_i=0, atom_j=0; + enum_atom_state atom_state = start_atom; // proper initialization + + // length of the parameter vector (used by CppAD assert macros) + const size_t num_par = play->num_par_rec(); + + // pointer to the beginning of the parameter vector + CPPAD_ASSERT_UNKNOWN( num_par > 0 ) + const Base* parameter = play->GetPar(); + + // length of the text vector (used by CppAD assert macros) + const size_t num_text = play->num_text_rec(); + + // pointer to the beginning of the text vector + const char* text = nullptr; + if( num_text > 0 ) + text = play->GetTxt(0); + +# if CPPAD_FORWARD0_TRACE + // flag as to when to trace atomic function values + bool atom_trace = false; + + // variable indices for results vector + // (done differently for order zero). + vector atom_iy; +# endif + + // skip the BeginOp at the beginning of the recording + play::const_sequential_iterator itr = play->begin(); + // op_info + OpCode op; + size_t i_var; + const Addr* arg; + itr.op_info(op, arg, i_var); + CPPAD_ASSERT_UNKNOWN( op == BeginOp ); + // +# if CPPAD_FORWARD0_TRACE + std::cout << std::endl; +# endif + bool flag; // a temporary flag to use in switch cases + bool more_operators = true; + while(more_operators) + { + // next op + (++itr).op_info(op, arg, i_var); + CPPAD_ASSERT_UNKNOWN( itr.op_index() < play->num_op_rec() ); + + // check if we are skipping this operation + while( cskip_op[itr.op_index()] ) + { switch(op) + { + case AFunOp: + { // get information for this atomic function call + CPPAD_ASSERT_UNKNOWN( atom_state == start_atom ); + play::atom_op_info( + op, arg, atom_index, atom_old, atom_m, atom_n + ); + // + // skip to the second AFunOp + for(size_t i = 0; i < atom_m + atom_n + 1; ++i) + ++itr; +# ifndef NDEBUG + itr.op_info(op, arg, i_var); + CPPAD_ASSERT_UNKNOWN( op == AFunOp ); +# endif + } + break; + + case CSkipOp: + case CSumOp: + itr.correct_before_increment(); + break; + + default: + break; + } + (++itr).op_info(op, arg, i_var); + } + + // action to take depends on the case + switch( op ) + { + case AbsOp: + forward_abs_op_0(i_var, size_t(arg[0]), J, taylor); + break; + // ------------------------------------------------- + + case AddvvOp: + forward_addvv_op_0(i_var, arg, parameter, J, taylor); + break; + // ------------------------------------------------- + + case AddpvOp: + CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) < num_par ); + forward_addpv_op_0(i_var, arg, parameter, J, taylor); + break; + // ------------------------------------------------- + + case AcosOp: + // sqrt(1 - x * x), acos(x) + CPPAD_ASSERT_UNKNOWN( i_var < numvar ); + forward_acos_op_0(i_var, size_t(arg[0]), J, taylor); + break; + // ------------------------------------------------- + + case AcoshOp: + // sqrt(x * x - 1), acosh(x) + CPPAD_ASSERT_UNKNOWN( i_var < numvar ); + forward_acosh_op_0(i_var, size_t(arg[0]), J, taylor); + break; + // ------------------------------------------------- + + case AsinOp: + // sqrt(1 - x * x), asin(x) + CPPAD_ASSERT_UNKNOWN( i_var < numvar ); + forward_asin_op_0(i_var, size_t(arg[0]), J, taylor); + break; + // ------------------------------------------------- + + case AsinhOp: + // sqrt(1 + x * x), asinh(x) + CPPAD_ASSERT_UNKNOWN( i_var < numvar ); + forward_asinh_op_0(i_var, size_t(arg[0]), J, taylor); + break; + // ------------------------------------------------- + + case AtanOp: + // 1 + x * x, atan(x) + CPPAD_ASSERT_UNKNOWN( i_var < numvar ); + forward_atan_op_0(i_var, size_t(arg[0]), J, taylor); + break; + // ------------------------------------------------- + + case AtanhOp: + // 1 - x * x, atanh(x) + CPPAD_ASSERT_UNKNOWN( i_var < numvar ); + forward_atanh_op_0(i_var, size_t(arg[0]), J, taylor); + break; + // ------------------------------------------------- + + case CExpOp: + // Use the general case with d == 0 + // (could create an optimzied verison for this case) + forward_cond_op_0( + i_var, arg, num_par, parameter, J, taylor + ); + break; + // --------------------------------------------------- + + case CosOp: + // sin(x), cos(x) + CPPAD_ASSERT_UNKNOWN( i_var < numvar ); + forward_cos_op_0(i_var, size_t(arg[0]), J, taylor); + break; + // --------------------------------------------------- + + case CoshOp: + // sinh(x), cosh(x) + CPPAD_ASSERT_UNKNOWN( i_var < numvar ); + forward_cosh_op_0(i_var, size_t(arg[0]), J, taylor); + break; + // ------------------------------------------------- + + case CSkipOp: + forward_cskip_op_0( + i_var, arg, num_par, parameter, J, taylor, cskip_op + ); + itr.correct_before_increment(); + break; + // ------------------------------------------------- + + case CSumOp: + forward_csum_op( + 0, 0, i_var, arg, num_par, parameter, J, taylor + ); + itr.correct_before_increment(); + break; + // ------------------------------------------------- + + case DisOp: + forward_dis_op(p, q, r, i_var, arg, J, taylor); + break; + // ------------------------------------------------- + + case DivvvOp: + forward_divvv_op_0(i_var, arg, parameter, J, taylor); + break; + // ------------------------------------------------- + + case DivpvOp: + CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) < num_par ); + forward_divpv_op_0(i_var, arg, parameter, J, taylor); + break; + // ------------------------------------------------- + + case DivvpOp: + CPPAD_ASSERT_UNKNOWN( size_t(arg[1]) < num_par ); + forward_divvp_op_0(i_var, arg, parameter, J, taylor); + break; + // ------------------------------------------------- + + case EndOp: + CPPAD_ASSERT_NARG_NRES(op, 0, 0); + more_operators = false; + break; + // ------------------------------------------------- + + case EqppOp: + if( compare_change_count ) + { forward_eqpp_op_0( + compare_change_number, arg, parameter + ); + { if( compare_change_count == compare_change_number ) + compare_change_op_index = itr.op_index(); + } + } + break; + // ------------------------------------------------- + + case EqpvOp: + if( compare_change_count ) + { forward_eqpv_op_0( + compare_change_number, arg, parameter, J, taylor + ); + { if( compare_change_count == compare_change_number ) + compare_change_op_index = itr.op_index(); + } + } + break; + // ------------------------------------------------- + + case EqvvOp: + if( compare_change_count ) + { forward_eqvv_op_0( + compare_change_number, arg, parameter, J, taylor + ); + { if( compare_change_count == compare_change_number ) + compare_change_op_index = itr.op_index(); + } + } + break; + // ------------------------------------------------- + + case ErfOp: + case ErfcOp: + forward_erf_op_0(op, i_var, arg, parameter, J, taylor); + break; + // ------------------------------------------------- + + case ExpOp: + forward_exp_op_0(i_var, size_t(arg[0]), J, taylor); + break; + // ------------------------------------------------- + + case Expm1Op: + forward_expm1_op_0(i_var, size_t(arg[0]), J, taylor); + break; + // ------------------------------------------------- + + case InvOp: + CPPAD_ASSERT_NARG_NRES(op, 0, 1); + break; + // --------------------------------------------------- + + case LdpOp: + forward_load_p_op_0( + play, + i_var, + arg, + parameter, + J, + taylor, + vec_ad2isvar.data(), + vec_ad2index.data(), + load_op2var.data() + ); + break; + // ------------------------------------------------- + + case LdvOp: + forward_load_v_op_0( + play, + i_var, + arg, + parameter, + J, + taylor, + vec_ad2isvar.data(), + vec_ad2index.data(), + load_op2var.data() + ); + break; + // ------------------------------------------------- + + case LeppOp: + if( compare_change_count ) + { forward_lepp_op_0( + compare_change_number, arg, parameter + ); + { if( compare_change_count == compare_change_number ) + compare_change_op_index = itr.op_index(); + } + } + break; + // ------------------------------------------------- + case LepvOp: + if( compare_change_count ) + { forward_lepv_op_0( + compare_change_number, arg, parameter, J, taylor + ); + { if( compare_change_count == compare_change_number ) + compare_change_op_index = itr.op_index(); + } + } + break; + // ------------------------------------------------- + + case LevpOp: + if( compare_change_count ) + { forward_levp_op_0( + compare_change_number, arg, parameter, J, taylor + ); + { if( compare_change_count == compare_change_number ) + compare_change_op_index = itr.op_index(); + } + } + break; + // ------------------------------------------------- + + case LevvOp: + if( compare_change_count ) + { forward_levv_op_0( + compare_change_number, arg, parameter, J, taylor + ); + { if( compare_change_count == compare_change_number ) + compare_change_op_index = itr.op_index(); + } + } + break; + // ------------------------------------------------- + + case LogOp: + forward_log_op_0(i_var, size_t(arg[0]), J, taylor); + break; + // ------------------------------------------------- + + case Log1pOp: + forward_log1p_op_0(i_var, size_t(arg[0]), J, taylor); + break; + // ------------------------------------------------- + + case LtppOp: + if( compare_change_count ) + { forward_ltpp_op_0( + compare_change_number, arg, parameter + ); + { if( compare_change_count == compare_change_number ) + compare_change_op_index = itr.op_index(); + } + } + break; + // ------------------------------------------------- + case LtpvOp: + if( compare_change_count ) + { forward_ltpv_op_0( + compare_change_number, arg, parameter, J, taylor + ); + { if( compare_change_count == compare_change_number ) + compare_change_op_index = itr.op_index(); + } + } + break; + // ------------------------------------------------- + + case LtvpOp: + if( compare_change_count ) + { forward_ltvp_op_0( + compare_change_number, arg, parameter, J, taylor + ); + { if( compare_change_count == compare_change_number ) + compare_change_op_index = itr.op_index(); + } + } + break; + // ------------------------------------------------- + + case LtvvOp: + if( compare_change_count ) + { forward_ltvv_op_0( + compare_change_number, arg, parameter, J, taylor + ); + { if( compare_change_count == compare_change_number ) + compare_change_op_index = itr.op_index(); + } + } + break; + // ------------------------------------------------- + + case MulpvOp: + CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) < num_par ); + forward_mulpv_op_0(i_var, arg, parameter, J, taylor); + break; + // ------------------------------------------------- + + case MulvvOp: + forward_mulvv_op_0(i_var, arg, parameter, J, taylor); + break; + // ------------------------------------------------- + + case NeppOp: + if( compare_change_count ) + { forward_nepp_op_0( + compare_change_number, arg, parameter + ); + { if( compare_change_count == compare_change_number ) + compare_change_op_index = itr.op_index(); + } + } + break; + // ------------------------------------------------- + + case NepvOp: + if( compare_change_count ) + { forward_nepv_op_0( + compare_change_number, arg, parameter, J, taylor + ); + { if( compare_change_count == compare_change_number ) + compare_change_op_index = itr.op_index(); + } + } + break; + // ------------------------------------------------- + + case NevvOp: + if( compare_change_count ) + { forward_nevv_op_0( + compare_change_number, arg, parameter, J, taylor + ); + { if( compare_change_count == compare_change_number ) + compare_change_op_index = itr.op_index(); + } + } + break; + // ------------------------------------------------- + + case ParOp: + forward_par_op_0( + i_var, arg, num_par, parameter, J, taylor + ); + break; + // ------------------------------------------------- + + case PowvpOp: + CPPAD_ASSERT_UNKNOWN( size_t(arg[1]) < num_par ); + forward_powvp_op_0(i_var, arg, parameter, J, taylor); + break; + // ------------------------------------------------- + + case PowpvOp: + CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) < num_par ); + forward_powpv_op_0(i_var, arg, parameter, J, taylor); + break; + // ------------------------------------------------- + + case PowvvOp: + forward_powvv_op_0(i_var, arg, parameter, J, taylor); + break; + // ------------------------------------------------- + + case PriOp: + if( print ) forward_pri_0(s_out, + arg, num_text, text, num_par, parameter, J, taylor + ); + break; + // ------------------------------------------------- + + case SignOp: + // cos(x), sin(x) + CPPAD_ASSERT_UNKNOWN( i_var < numvar ); + forward_sign_op_0(i_var, size_t(arg[0]), J, taylor); + break; + // ------------------------------------------------- + + case SinOp: + // cos(x), sin(x) + CPPAD_ASSERT_UNKNOWN( i_var < numvar ); + forward_sin_op_0(i_var, size_t(arg[0]), J, taylor); + break; + // ------------------------------------------------- + + case SinhOp: + // cosh(x), sinh(x) + CPPAD_ASSERT_UNKNOWN( i_var < numvar ); + forward_sinh_op_0(i_var, size_t(arg[0]), J, taylor); + break; + // ------------------------------------------------- + + case SqrtOp: + forward_sqrt_op_0(i_var, size_t(arg[0]), J, taylor); + break; + // ------------------------------------------------- + + case StppOp: + forward_store_pp_op_0( + i_var, + arg, + num_par, + parameter, + J, + taylor, + vec_ad2isvar.data(), + vec_ad2index.data() + ); + break; + // ------------------------------------------------- + + case StpvOp: + forward_store_pv_op_0( + i_var, + arg, + num_par, + parameter, + J, + taylor, + vec_ad2isvar.data(), + vec_ad2index.data() + ); + break; + // ------------------------------------------------- + + case StvpOp: + forward_store_vp_op_0( + i_var, + arg, + num_par, + J, + taylor, + vec_ad2isvar.data(), + vec_ad2index.data() + ); + break; + // ------------------------------------------------- + + case StvvOp: + forward_store_vv_op_0( + i_var, + arg, + num_par, + J, + taylor, + vec_ad2isvar.data(), + vec_ad2index.data() + ); + break; + // ------------------------------------------------- + + case SubvvOp: + forward_subvv_op_0(i_var, arg, parameter, J, taylor); + break; + // ------------------------------------------------- + + case SubpvOp: + CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) < num_par ); + forward_subpv_op_0(i_var, arg, parameter, J, taylor); + break; + // ------------------------------------------------- + + case SubvpOp: + CPPAD_ASSERT_UNKNOWN( size_t(arg[1]) < num_par ); + forward_subvp_op_0(i_var, arg, parameter, J, taylor); + break; + // ------------------------------------------------- + + case TanOp: + // tan(x)^2, tan(x) + CPPAD_ASSERT_UNKNOWN( i_var < numvar ); + forward_tan_op_0(i_var, size_t(arg[0]), J, taylor); + break; + // ------------------------------------------------- + + case TanhOp: + // tanh(x)^2, tanh(x) + CPPAD_ASSERT_UNKNOWN( i_var < numvar ); + forward_tanh_op_0(i_var, size_t(arg[0]), J, taylor); + break; + // ------------------------------------------------- + + case AFunOp: + // start or end an atomic function call + flag = atom_state == start_atom; + play::atom_op_info( + op, arg, atom_index, atom_old, atom_m, atom_n + ); + if( flag ) + { atom_state = arg_atom; + atom_i = 0; + atom_j = 0; + // + atom_par_x.resize(atom_n); + atom_type_x.resize(atom_n); + atom_tx.resize(atom_n); + atom_ty.resize(atom_m); +# if CPPAD_FORWARD0_TRACE + atom_iy.resize(atom_m); +# endif + } + else + { CPPAD_ASSERT_UNKNOWN( atom_i == atom_m ); + CPPAD_ASSERT_UNKNOWN( atom_j == atom_n ); + atom_state = start_atom; +# if CPPAD_FORWARD0_TRACE + atom_trace = true; +# endif + } + break; + + case FunapOp: + // parameter argument for an atomic function + CPPAD_ASSERT_UNKNOWN( NumArg(op) == 1 ); + CPPAD_ASSERT_UNKNOWN( atom_state == arg_atom ); + CPPAD_ASSERT_UNKNOWN( atom_i == 0 ); + CPPAD_ASSERT_UNKNOWN( atom_j < atom_n ); + CPPAD_ASSERT_UNKNOWN( size_t( arg[0] ) < num_par ); + // + if( dyn_par_is[ arg[0] ] ) + atom_type_x[atom_j] = dynamic_enum; + else + atom_type_x[atom_j] = constant_enum; + atom_par_x[atom_j] = parameter[ arg[0] ]; + atom_tx[atom_j++] = parameter[ arg[0] ]; + // + if( atom_j == atom_n ) + { // call atomic function for this operation + call_atomic_forward( + atom_par_x, atom_type_x, need_y, + order_low, order_up, atom_index, atom_old, atom_tx, atom_ty + ); + atom_state = ret_atom; + } + break; + + case FunavOp: + // variable argument for a atomic function + CPPAD_ASSERT_UNKNOWN( NumArg(op) == 1 ); + CPPAD_ASSERT_UNKNOWN( atom_state == arg_atom ); + CPPAD_ASSERT_UNKNOWN( atom_i == 0 ); + CPPAD_ASSERT_UNKNOWN( atom_j < atom_n ); + // + atom_type_x[atom_j] = variable_enum; + atom_par_x[atom_j] = CppAD::numeric_limits::quiet_NaN(); + atom_tx[atom_j++] = taylor[ size_t(arg[0]) * J + 0 ]; + // + if( atom_j == atom_n ) + { // call atomic function for this operation + call_atomic_forward( + atom_par_x, atom_type_x, need_y, + order_low, order_up, atom_index, atom_old, atom_tx, atom_ty + ); + atom_state = ret_atom; + } + break; + + case FunrpOp: + // parameter result for a atomic function + CPPAD_ASSERT_NARG_NRES(op, 1, 0); + CPPAD_ASSERT_UNKNOWN( atom_state == ret_atom ); + CPPAD_ASSERT_UNKNOWN( atom_i < atom_m ); + CPPAD_ASSERT_UNKNOWN( atom_j == atom_n ); + CPPAD_ASSERT_UNKNOWN( size_t( arg[0] ) < num_par ); +# if CPPAD_FORWARD0_TRACE + atom_iy[atom_i] = 0; +# endif + atom_i++; + if( atom_i == atom_m ) + atom_state = end_atom; + break; + + case FunrvOp: + // variable result for a atomic function + CPPAD_ASSERT_NARG_NRES(op, 0, 1); + CPPAD_ASSERT_UNKNOWN( atom_state == ret_atom ); + CPPAD_ASSERT_UNKNOWN( atom_i < atom_m ); + CPPAD_ASSERT_UNKNOWN( atom_j == atom_n ); +# if CPPAD_FORWARD0_TRACE + atom_iy[atom_i] = i_var; +# endif + taylor[ i_var * J + 0 ] = atom_ty[atom_i++]; + if( atom_i == atom_m ) + atom_state = end_atom; + break; + // ------------------------------------------------- + + case ZmulpvOp: + CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) < num_par ); + forward_zmulpv_op_0(i_var, arg, parameter, J, taylor); + break; + // ------------------------------------------------- + + case ZmulvpOp: + CPPAD_ASSERT_UNKNOWN( size_t(arg[1]) < num_par ); + forward_zmulvp_op_0(i_var, arg, parameter, J, taylor); + break; + // ------------------------------------------------- + + case ZmulvvOp: + forward_zmulvv_op_0(i_var, arg, parameter, J, taylor); + break; + // ------------------------------------------------- + + default: + CPPAD_ASSERT_UNKNOWN(false); + } +# if CPPAD_FORWARD0_TRACE + size_t d = 0; + if( atom_trace ) + { atom_trace = false; + + CPPAD_ASSERT_UNKNOWN( op == AFunOp ); + CPPAD_ASSERT_UNKNOWN( NumArg(FunrvOp) == 0 ); + for(size_t i = 0; i < atom_m; i++) if( atom_iy[i] > 0 ) + { size_t i_tmp = (itr.op_index() + i) - atom_m; + printOp( + std::cout, + play, + i_tmp, + atom_iy[i], + FunrvOp, + nullptr + ); + Base* Z_tmp = taylor + atom_iy[i] * J; + printOpResult( + std::cout, + d + 1, + Z_tmp, + 0, + (Base *) nullptr + ); + std::cout << std::endl; + } + } + Base* Z_tmp = taylor + i_var * J; + if( op != FunrvOp ) + { + printOp( + std::cout, + play, + itr.op_index(), + i_var, + op, + arg + ); + if( NumRes(op) > 0 ) printOpResult( + std::cout, + d + 1, + Z_tmp, + 0, + (Base *) nullptr + ); + std::cout << std::endl; + } + } + std::cout << std::endl; +# else + } +# endif + CPPAD_ASSERT_UNKNOWN( atom_state == start_atom ); + + return; +} + +} } } // END_CPPAD_LOCAL_SWEEP_NAMESPACE + +// preprocessor symbols that are local to this file +# undef CPPAD_FORWARD0_TRACE + +# endif diff --git a/build-config/cppad/include/cppad/local/sweep/forward1.hpp b/build-config/cppad/include/cppad/local/sweep/forward1.hpp new file mode 100644 index 00000000..4ce8d932 --- /dev/null +++ b/build-config/cppad/include/cppad/local/sweep/forward1.hpp @@ -0,0 +1,1086 @@ +# ifndef CPPAD_LOCAL_SWEEP_FORWARD1_HPP +# define CPPAD_LOCAL_SWEEP_FORWARD1_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +# include +# include + +// BEGIN_CPPAD_LOCAL_SWEEP_NAMESPACE +namespace CppAD { namespace local { namespace sweep { +/*! +\file sweep/forward1.hpp +Compute one Taylor coefficient for each order requested. +*/ + +/*! +\def CPPAD_FORWARD1_TRACE +This value is either zero or one. +Zero is the normal operational value. +If it is one, a trace of every forward1sweep computation is printed. +*/ +# define CPPAD_FORWARD1_TRACE 0 + +/*! +Compute arbitrary order forward mode Taylor coefficients. + + +\tparam Base +The type used during the forward mode computations; i.e., the corresponding +recording of operations used the type AD. + +\param s_out +Is the stream where output corresponding to PriOp operations will +be written. + +\param print +If print is false, +suppress the output that is otherwise generated by the c PriOp instructions. + +\param n +is the number of independent variables on the tape. + +\param numvar +is the total number of variables on the tape. +This is also equal to the number of rows in the matrix taylor; i.e., +play->num_var_rec(). + +\param play +The information stored in play +is a recording of the operations corresponding to the function +\f[ + F : {\bf R}^n \rightarrow {\bf R}^m +\f] +where \f$ n \f$ is the number of independent variables and +\f$ m \f$ is the number of dependent variables. + +\param J +Is the number of columns in the coefficient matrix taylor. +This must be greater than or equal one. + + + +\param cskip_op +Is a vector with size play->num_op_rec(). +\n +\n +p = 0 +\n +In this case, +the input value of the elements does not matter. +Upon return, if cskip_op[i] is true, the operator with index i +does not affect any of the dependent variable +(given the value of the independent variables). +\n +\n +p > 0 +\n +In this case cskip_op is not modified and has the same meaning +as its return value above. + +\param load_op2var +is a vector with size play->num_var_load_rec(). +\n +\n +p == 0 +\n +In this case, +The input value of the elements does not matter. +Upon return, +it is the variable index corresponding the result for each load operator. +In the case where the index is zero, +the load operator results in a parameter (not a variable). +Note that the is no variable with index zero on the tape. +\n +\n +p > 0 +\n +In this case load_op2var is not modified and has the meaning +as its return value above. + +\param p +is the lowest order of the Taylor coefficients +that are computed during this call. + +\param q +is the highest order of the Taylor coefficients +that are computed during this call. + +\param taylor +\n +\b Input: +For i = 1 , ... , numvar-1, +k = 0 , ... , p-1, +taylor[ J*i + k] +is the k-th order Taylor coefficient corresponding to +the i-th variable. +\n +\n +\b Input: +For i = 1 , ... , n, +k = p , ... , q, +taylor[ J*j + k] +is the k-th order Taylor coefficient corresponding to +the i-th variable +(these are the independent varaibles). +\n +\n +\b Output: +For i = n+1 , ... , numvar-1, and +k = 0 , ... , p-1, +taylor[ J*i + k] +is the k-th order Taylor coefficient corresponding to +the i-th variable. + + +\param compare_change_count +Is the count value for changing number and op_index during +zero order foward mode. + +\param compare_change_number +If p is non-zero, this value is not changed, otherwise: +If compare_change_count is zero, this value is set to zero, otherwise: +this value is set to the number of comparison operations +that have a different result from when the information in +play was recorded. + +\param compare_change_op_index +if p is non-zero, this value is not changed, otherwise: +If compare_change_count is zero, this value is set to zero. +Otherwise it is the operator index (see forward_next) for the count-th +comparison operation that has a different result from when the information in +play was recorded. + +\param not_used_rec_base +Specifies RecBase for this call. +*/ + +template +void forward1( + const local::player* play, + std::ostream& s_out, + const bool print, + const size_t p, + const size_t q, + const size_t n, + const size_t numvar, + const size_t J, + Base* taylor, + bool* cskip_op, + pod_vector& load_op2var, + size_t compare_change_count, + size_t& compare_change_number, + size_t& compare_change_op_index, + const RecBase& not_used_rec_base +) +{ + // number of directions + const size_t r = 1; + + CPPAD_ASSERT_UNKNOWN( p <= q ); + CPPAD_ASSERT_UNKNOWN( J >= q + 1 ); + CPPAD_ASSERT_UNKNOWN( play->num_var_rec() == numvar ); + + /* + + */ + + // initialize the comparison operator counter + if( p == 0 ) + { compare_change_number = 0; + compare_change_op_index = 0; + } + + // If this includes a zero calculation, initialize this information + pod_vector vec_ad2isvar; + pod_vector vec_ad2index; + if( p == 0 ) + { size_t i; + + // this includes order zero calculation, initialize vector indices + size_t num = play->num_var_vecad_ind_rec(); + if( num > 0 ) + { vec_ad2isvar.extend(num); + vec_ad2index.extend(num); + for(i = 0; i < num; i++) + { vec_ad2index[i] = play->GetVecInd(i); + vec_ad2isvar[i] = false; + } + } + // includes zero order, so initialize conditional skip flags + num = play->num_op_rec(); + for(i = 0; i < num; i++) + cskip_op[i] = false; + } + + // information used by atomic function operators + const pod_vector& dyn_par_is( play->dyn_par_is() ); + const size_t need_y = size_t( variable_enum ); + const size_t order_low = p; + const size_t order_up = q; + + // vectors used by atomic function operators + vector atom_par_x; // argument parameter values + vector atom_type_x; // argument type + vector atom_tx; // argument vector Taylor coefficients + vector atom_ty; // result vector Taylor coefficients + // + // information defined by atomic function operators + size_t atom_index=0, atom_old=0, atom_m=0, atom_n=0, atom_i=0, atom_j=0; + enum_atom_state atom_state = start_atom; // proper initialization + + // length of the parameter vector (used by CppAD assert macros) + const size_t num_par = play->num_par_rec(); + + // pointer to the beginning of the parameter vector + CPPAD_ASSERT_UNKNOWN( num_par > 0 ) + const Base* parameter = play->GetPar(); + + // length of the text vector (used by CppAD assert macros) + const size_t num_text = play->num_text_rec(); + + // pointer to the beginning of the text vector + const char* text = nullptr; + if( num_text > 0 ) + text = play->GetTxt(0); + /* + + */ + // temporary indices + size_t i, k; + + // number of orders for this atomic calculation + // (not needed for order zero) + const size_t atom_q1 = q+1; + + // variable indices for results vector + // (done differently for order zero). + vector atom_iy; + + // skip the BeginOp at the beginning of the recording + play::const_sequential_iterator itr = play->begin(); + // op_info + OpCode op; + size_t i_var; + const Addr* arg; + itr.op_info(op, arg, i_var); + CPPAD_ASSERT_UNKNOWN( op == BeginOp ); + // +# if CPPAD_FORWARD1_TRACE + bool atom_trace = false; + std::cout << std::endl; +# endif + // + bool flag; // a temporary flag to use in switch cases + bool more_operators = true; + while(more_operators) + { + // next op + (++itr).op_info(op, arg, i_var); + CPPAD_ASSERT_UNKNOWN( itr.op_index() < play->num_op_rec() ); + + // check if we are skipping this operation + while( cskip_op[itr.op_index()] ) + { switch(op) + { + case AFunOp: + { // get information for this atomic function call + CPPAD_ASSERT_UNKNOWN( atom_state == start_atom ); + play::atom_op_info( + op, arg, atom_index, atom_old, atom_m, atom_n + ); + // + // skip to the second AFunOp + for(i = 0; i < atom_m + atom_n + 1; ++i) + ++itr; +# ifndef NDEBUG + itr.op_info(op, arg, i_var); + CPPAD_ASSERT_UNKNOWN( op == AFunOp ); +# endif + } + break; + + case CSkipOp: + case CSumOp: + itr.correct_before_increment(); + break; + + default: + break; + } + (++itr).op_info(op, arg, i_var); + } + + // action depends on the operator + switch( op ) + { + case AbsOp: + forward_abs_op(p, q, i_var, size_t(arg[0]), J, taylor); + break; + // ------------------------------------------------- + + case AddvvOp: + forward_addvv_op(p, q, i_var, arg, parameter, J, taylor); + break; + // ------------------------------------------------- + + case AddpvOp: + CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) < num_par ); + forward_addpv_op(p, q, i_var, arg, parameter, J, taylor); + break; + // ------------------------------------------------- + + case AcosOp: + // sqrt(1 - x * x), acos(x) + CPPAD_ASSERT_UNKNOWN( i_var < numvar ); + forward_acos_op(p, q, i_var, size_t(arg[0]), J, taylor); + break; + // ------------------------------------------------- + + case AcoshOp: + // sqrt(x * x - 1), acosh(x) + CPPAD_ASSERT_UNKNOWN( i_var < numvar ); + forward_acosh_op(p, q, i_var, size_t(arg[0]), J, taylor); + break; + // ------------------------------------------------- + + case AsinOp: + // sqrt(1 - x * x), asin(x) + CPPAD_ASSERT_UNKNOWN( i_var < numvar ); + forward_asin_op(p, q, i_var, size_t(arg[0]), J, taylor); + break; + // ------------------------------------------------- + + case AsinhOp: + // sqrt(1 + x * x), asinh(x) + CPPAD_ASSERT_UNKNOWN( i_var < numvar ); + forward_asinh_op(p, q, i_var, size_t(arg[0]), J, taylor); + break; + // ------------------------------------------------- + + case AtanOp: + // 1 + x * x, atan(x) + CPPAD_ASSERT_UNKNOWN( i_var < numvar ); + forward_atan_op(p, q, i_var, size_t(arg[0]), J, taylor); + break; + // ------------------------------------------------- + + case AtanhOp: + // 1 - x * x, atanh(x) + CPPAD_ASSERT_UNKNOWN( i_var < numvar ); + forward_atanh_op(p, q, i_var, size_t(arg[0]), J, taylor); + break; + // ------------------------------------------------- + + case CExpOp: + forward_cond_op( + p, q, i_var, arg, num_par, parameter, J, taylor + ); + break; + // --------------------------------------------------- + + case CosOp: + // sin(x), cos(x) + CPPAD_ASSERT_UNKNOWN( i_var < numvar ); + forward_cos_op(p, q, i_var, size_t(arg[0]), J, taylor); + break; + // --------------------------------------------------- + + case CoshOp: + // sinh(x), cosh(x) + CPPAD_ASSERT_UNKNOWN( i_var < numvar ); + forward_cosh_op(p, q, i_var, size_t(arg[0]), J, taylor); + break; + // ------------------------------------------------- + + case CSkipOp: + if( p == 0 ) + { forward_cskip_op_0( + i_var, arg, num_par, parameter, J, taylor, cskip_op + ); + } + itr.correct_before_increment(); + break; + // ------------------------------------------------- + + case CSumOp: + forward_csum_op( + p, q, i_var, arg, num_par, parameter, J, taylor + ); + itr.correct_before_increment(); + break; + // ------------------------------------------------- + + case DisOp: + forward_dis_op(p, q, r, i_var, arg, J, taylor); + break; + // ------------------------------------------------- + + case DivvvOp: + forward_divvv_op(p, q, i_var, arg, parameter, J, taylor); + break; + // ------------------------------------------------- + + case DivpvOp: + CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) < num_par ); + forward_divpv_op(p, q, i_var, arg, parameter, J, taylor); + break; + // ------------------------------------------------- + + case DivvpOp: + CPPAD_ASSERT_UNKNOWN( size_t(arg[1]) < num_par ); + forward_divvp_op(p, q, i_var, arg, parameter, J, taylor); + break; + // ------------------------------------------------- + + case EndOp: + CPPAD_ASSERT_NARG_NRES(op, 0, 0); + more_operators = false; + break; + // ------------------------------------------------- + + case EqppOp: + if( compare_change_count ) + { forward_eqpp_op_0( + compare_change_number, arg, parameter + ); + { if( compare_change_count == compare_change_number ) + compare_change_op_index = itr.op_index(); + } + } + break; + // ------------------------------------------------- + + case EqpvOp: + if( ( p == 0 ) & ( compare_change_count > 0 ) ) + { forward_eqpv_op_0( + compare_change_number, arg, parameter, J, taylor + ); + if( compare_change_count == compare_change_number ) + compare_change_op_index = itr.op_index(); + } + break; + // ------------------------------------------------- + + case EqvvOp: + if( ( p == 0 ) & ( compare_change_count > 0 ) ) + { forward_eqvv_op_0( + compare_change_number, arg, parameter, J, taylor + ); + if( compare_change_count == compare_change_number ) + compare_change_op_index = itr.op_index(); + } + break; + // ------------------------------------------------- + + case ErfOp: + case ErfcOp: + forward_erf_op(op, p, q, i_var, arg, parameter, J, taylor); + break; + // ------------------------------------------------- + + case ExpOp: + forward_exp_op(p, q, i_var, size_t(arg[0]), J, taylor); + break; + // --------------------------------------------------- + + case Expm1Op: + forward_expm1_op(p, q, i_var, size_t(arg[0]), J, taylor); + break; + // --------------------------------------------------- + + case InvOp: + CPPAD_ASSERT_NARG_NRES(op, 0, 1); + break; + // ------------------------------------------------- + + case LdpOp: + if( p == 0 ) + { forward_load_p_op_0( + play, + i_var, + arg, + parameter, + J, + taylor, + vec_ad2isvar.data(), + vec_ad2index.data(), + load_op2var.data() + ); + if( p < q ) forward_load_op( + play, + op, + p+1, + q, + r, + J, + i_var, + arg, + load_op2var.data(), + taylor + ); + } + else + forward_load_op( + play, + op, + p, + q, + r, + J, + i_var, + arg, + load_op2var.data(), + taylor + ); + break; + // ------------------------------------------------- + + case LdvOp: + if( p == 0 ) + { forward_load_v_op_0( + play, + i_var, + arg, + parameter, + J, + taylor, + vec_ad2isvar.data(), + vec_ad2index.data(), + load_op2var.data() + ); + if( p < q ) forward_load_op( + play, + op, + p+1, + q, + r, + J, + i_var, + arg, + load_op2var.data(), + taylor + ); + } + else + forward_load_op( + play, + op, + p, + q, + r, + J, + i_var, + arg, + load_op2var.data(), + taylor + ); + break; + // ------------------------------------------------- + + case LeppOp: + if( ( p == 0 ) & ( compare_change_count > 0 ) ) + { forward_lepp_op_0( + compare_change_number, arg, parameter + ); + if( compare_change_count == compare_change_number ) + compare_change_op_index = itr.op_index(); + } + break; + // ------------------------------------------------- + + case LepvOp: + if( ( p == 0 ) & ( compare_change_count > 0 ) ) + { forward_lepv_op_0( + compare_change_number, arg, parameter, J, taylor + ); + if( compare_change_count == compare_change_number ) + compare_change_op_index = itr.op_index(); + } + break; + // ------------------------------------------------- + + case LevpOp: + if( ( p == 0 ) & ( compare_change_count > 0 ) ) + { forward_levp_op_0( + compare_change_number, arg, parameter, J, taylor + ); + if( compare_change_count == compare_change_number ) + compare_change_op_index = itr.op_index(); + } + break; + // ------------------------------------------------- + + case LevvOp: + if( ( p == 0 ) & ( compare_change_count > 0 ) ) + { forward_levv_op_0( + compare_change_number, arg, parameter, J, taylor + ); + if( compare_change_count == compare_change_number ) + compare_change_op_index = itr.op_index(); + } + break; + // ------------------------------------------------- + + case LogOp: + forward_log_op(p, q, i_var, size_t(arg[0]), J, taylor); + break; + // ------------------------------------------------- + + case Log1pOp: + forward_log1p_op(p, q, i_var, size_t(arg[0]), J, taylor); + break; + // ------------------------------------------------- + + case LtppOp: + if( ( p == 0 ) & ( compare_change_count > 0 ) ) + { forward_ltpp_op_0( + compare_change_number, arg, parameter + ); + if( compare_change_count == compare_change_number ) + compare_change_op_index = itr.op_index(); + } + break; + // ------------------------------------------------- + + case LtpvOp: + if( ( p == 0 ) & ( compare_change_count > 0 ) ) + { forward_ltpv_op_0( + compare_change_number, arg, parameter, J, taylor + ); + if( compare_change_count == compare_change_number ) + compare_change_op_index = itr.op_index(); + } + break; + // ------------------------------------------------- + + case LtvpOp: + if( ( p == 0 ) & ( compare_change_count > 0 ) ) + { forward_ltvp_op_0( + compare_change_number, arg, parameter, J, taylor + ); + if( compare_change_count == compare_change_number ) + compare_change_op_index = itr.op_index(); + } + break; + // ------------------------------------------------- + + case LtvvOp: + if( ( p == 0 ) & ( compare_change_count > 0 ) ) + { forward_ltvv_op_0( + compare_change_number, arg, parameter, J, taylor + ); + if( compare_change_count == compare_change_number ) + compare_change_op_index = itr.op_index(); + } + break; + // ------------------------------------------------- + + case MulpvOp: + CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) < num_par ); + forward_mulpv_op(p, q, i_var, arg, parameter, J, taylor); + break; + // ------------------------------------------------- + + case MulvvOp: + forward_mulvv_op(p, q, i_var, arg, parameter, J, taylor); + break; + // ------------------------------------------------- + + case NeppOp: + if( compare_change_count ) + { forward_nepp_op_0( + compare_change_number, arg, parameter + ); + { if( compare_change_count == compare_change_number ) + compare_change_op_index = itr.op_index(); + } + } + break; + // ------------------------------------------------- + + case NepvOp: + if( ( p == 0 ) & ( compare_change_count > 0 ) ) + { forward_nepv_op_0( + compare_change_number, arg, parameter, J, taylor + ); + if( compare_change_count == compare_change_number ) + compare_change_op_index = itr.op_index(); + } + break; + // ------------------------------------------------- + + case NevvOp: + if( ( p == 0 ) & ( compare_change_count > 0 ) ) + { forward_nevv_op_0( + compare_change_number, arg, parameter, J, taylor + ); + if( compare_change_count == compare_change_number ) + compare_change_op_index = itr.op_index(); + } + break; + // ------------------------------------------------- + + case ParOp: + i = p; + if( i == 0 ) + { forward_par_op_0( + i_var, arg, num_par, parameter, J, taylor + ); + i++; + } + while(i <= q) + { taylor[ i_var * J + i] = Base(0.0); + i++; + } + break; + // ------------------------------------------------- + + case PowvpOp: + CPPAD_ASSERT_UNKNOWN( size_t(arg[1]) < num_par ); + forward_powvp_op(p, q, i_var, arg, parameter, J, taylor); + break; + // ------------------------------------------------- + + case PowpvOp: + CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) < num_par ); + forward_powpv_op(p, q, i_var, arg, parameter, J, taylor); + break; + // ------------------------------------------------- + + case PowvvOp: + forward_powvv_op(p, q, i_var, arg, parameter, J, taylor); + break; + // ------------------------------------------------- + + case PriOp: + if( (p == 0) & print ) forward_pri_0(s_out, + arg, num_text, text, num_par, parameter, J, taylor + ); + break; + // ------------------------------------------------- + + case SignOp: + // sign(x) + CPPAD_ASSERT_UNKNOWN( i_var < numvar ); + forward_sign_op(p, q, i_var, size_t(arg[0]), J, taylor); + break; + // ------------------------------------------------- + + case SinOp: + // cos(x), sin(x) + CPPAD_ASSERT_UNKNOWN( i_var < numvar ); + forward_sin_op(p, q, i_var, size_t(arg[0]), J, taylor); + break; + // ------------------------------------------------- + + case SinhOp: + // cosh(x), sinh(x) + CPPAD_ASSERT_UNKNOWN( i_var < numvar ); + forward_sinh_op(p, q, i_var, size_t(arg[0]), J, taylor); + break; + // ------------------------------------------------- + + case SqrtOp: + forward_sqrt_op(p, q, i_var, size_t(arg[0]), J, taylor); + break; + // ------------------------------------------------- + + case StppOp: + if( p == 0 ) + { forward_store_pp_op_0( + i_var, + arg, + num_par, + parameter, + J, + taylor, + vec_ad2isvar.data(), + vec_ad2index.data() + ); + } + break; + // ------------------------------------------------- + + case StpvOp: + if( p == 0 ) + { forward_store_pv_op_0( + i_var, + arg, + num_par, + parameter, + J, + taylor, + vec_ad2isvar.data(), + vec_ad2index.data() + ); + } + break; + // ------------------------------------------------- + + case StvpOp: + if( p == 0 ) + { forward_store_vp_op_0( + i_var, + arg, + num_par, + J, + taylor, + vec_ad2isvar.data(), + vec_ad2index.data() + ); + } + break; + // ------------------------------------------------- + + case StvvOp: + if( p == 0 ) + { forward_store_vv_op_0( + i_var, + arg, + num_par, + J, + taylor, + vec_ad2isvar.data(), + vec_ad2index.data() + ); + } + break; + // ------------------------------------------------- + + case SubvvOp: + forward_subvv_op(p, q, i_var, arg, parameter, J, taylor); + break; + // ------------------------------------------------- + + case SubpvOp: + CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) < num_par ); + forward_subpv_op(p, q, i_var, arg, parameter, J, taylor); + break; + // ------------------------------------------------- + + case SubvpOp: + CPPAD_ASSERT_UNKNOWN( size_t(arg[1]) < num_par ); + forward_subvp_op(p, q, i_var, arg, parameter, J, taylor); + break; + // ------------------------------------------------- + + case TanOp: + // tan(x)^2, tan(x) + CPPAD_ASSERT_UNKNOWN( i_var < numvar ); + forward_tan_op(p, q, i_var, size_t(arg[0]), J, taylor); + break; + // ------------------------------------------------- + + case TanhOp: + // tanh(x)^2, tanh(x) + CPPAD_ASSERT_UNKNOWN( i_var < numvar ); + forward_tanh_op(p, q, i_var, size_t(arg[0]), J, taylor); + break; + // ------------------------------------------------- + + case AFunOp: + // start or end an atomic function call + flag = atom_state == start_atom; + play::atom_op_info( + op, arg, atom_index, atom_old, atom_m, atom_n + ); + if( flag ) + { atom_state = arg_atom; + atom_i = 0; + atom_j = 0; + // + atom_par_x.resize(atom_n); + atom_type_x.resize(atom_n); + atom_tx.resize(atom_n * atom_q1); + atom_ty.resize(atom_m * atom_q1); + atom_iy.resize(atom_m); + } + else + { CPPAD_ASSERT_UNKNOWN( atom_i == atom_m ); + CPPAD_ASSERT_UNKNOWN( atom_j == atom_n ); + atom_state = start_atom; + // + // call atomic function for this operation + call_atomic_forward( + atom_par_x, atom_type_x, need_y, + order_low, order_up, atom_index, atom_old, atom_tx, atom_ty + ); + for(i = 0; i < atom_m; i++) + if( atom_iy[i] > 0 ) + for(k = p; k <= q; k++) + taylor[ atom_iy[i] * J + k ] = + atom_ty[ i * atom_q1 + k ]; +# if CPPAD_FORWARD1_TRACE + atom_trace = true; +# endif + } + break; + + case FunapOp: + // parameter argument for a atomic function + CPPAD_ASSERT_UNKNOWN( NumArg(op) == 1 ); + CPPAD_ASSERT_UNKNOWN( atom_state == arg_atom ); + CPPAD_ASSERT_UNKNOWN( atom_i == 0 ); + CPPAD_ASSERT_UNKNOWN( atom_j < atom_n ); + CPPAD_ASSERT_UNKNOWN( size_t( arg[0] ) < num_par ); + // + if( dyn_par_is[ arg[0] ] ) + atom_type_x[atom_j] = dynamic_enum; + else + atom_type_x[atom_j] = constant_enum; + atom_par_x[atom_j] = parameter[ arg[0] ]; + atom_tx[atom_j * atom_q1 + 0] = parameter[ arg[0]]; + for(k = 1; k < atom_q1; k++) + atom_tx[atom_j * atom_q1 + k] = Base(0.0); + // + ++atom_j; + if( atom_j == atom_n ) + atom_state = ret_atom; + break; + + case FunavOp: + // variable argument for a atomic function + CPPAD_ASSERT_UNKNOWN( NumArg(op) == 1 ); + CPPAD_ASSERT_UNKNOWN( atom_state == arg_atom ); + CPPAD_ASSERT_UNKNOWN( atom_i == 0 ); + CPPAD_ASSERT_UNKNOWN( atom_j < atom_n ); + // + atom_type_x[atom_j] = variable_enum; + atom_par_x[atom_j] = CppAD::numeric_limits::quiet_NaN(); + for(k = 0; k < atom_q1; k++) + atom_tx[atom_j * atom_q1 + k] = taylor[ size_t(arg[0]) * J + k]; + // + ++atom_j; + if( atom_j == atom_n ) + atom_state = ret_atom; + break; + + case FunrpOp: + // parameter result for a atomic function + CPPAD_ASSERT_NARG_NRES(op, 1, 0); + CPPAD_ASSERT_UNKNOWN( atom_state == ret_atom ); + CPPAD_ASSERT_UNKNOWN( atom_i < atom_m ); + CPPAD_ASSERT_UNKNOWN( atom_j == atom_n ); + CPPAD_ASSERT_UNKNOWN( size_t( arg[0] ) < num_par ); + // + atom_iy[atom_i] = 0; + atom_ty[atom_i * atom_q1 + 0] = parameter[ arg[0]]; + for(k = 1; k < p; k++) + atom_ty[atom_i * atom_q1 + k] = Base(0.0); + // + ++atom_i; + if( atom_i == atom_m ) + atom_state = end_atom; + break; + + case FunrvOp: + // variable result for a atomic function + CPPAD_ASSERT_NARG_NRES(op, 0, 1); + CPPAD_ASSERT_UNKNOWN( atom_state == ret_atom ); + CPPAD_ASSERT_UNKNOWN( atom_i < atom_m ); + CPPAD_ASSERT_UNKNOWN( atom_j == atom_n ); + // + atom_iy[atom_i] = i_var; + for(k = 0; k < p; k++) + atom_ty[atom_i * atom_q1 + k] = taylor[ i_var * J + k]; + // + ++atom_i; + if( atom_i == atom_m ) + atom_state = end_atom; + break; + // ------------------------------------------------- + + case ZmulpvOp: + CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) < num_par ); + forward_zmulpv_op(p, q, i_var, arg, parameter, J, taylor); + break; + // ------------------------------------------------- + + case ZmulvpOp: + CPPAD_ASSERT_UNKNOWN( size_t(arg[1]) < num_par ); + forward_zmulvp_op(p, q, i_var, arg, parameter, J, taylor); + break; + // ------------------------------------------------- + + case ZmulvvOp: + forward_zmulvv_op(p, q, i_var, arg, parameter, J, taylor); + break; + // ------------------------------------------------- + + default: + CPPAD_ASSERT_UNKNOWN(0); + } +# if CPPAD_FORWARD1_TRACE + if( atom_trace ) + { atom_trace = false; + + CPPAD_ASSERT_UNKNOWN( op == AFunOp ); + CPPAD_ASSERT_UNKNOWN( NumArg(FunrvOp) == 0 ); + for(i = 0; i < atom_m; i++) if( atom_iy[i] > 0 ) + { size_t i_tmp = (itr.op_index() + i) - atom_m; + printOp( + std::cout, + play, + i_tmp, + atom_iy[i], + FunrvOp, + nullptr + ); + Base* Z_tmp = taylor + atom_iy[i] * J; + printOpResult( + std::cout, + q + 1, + Z_tmp, + 0, + (Base *) nullptr + ); + std::cout << std::endl; + } + } + Base* Z_tmp = taylor + J * i_var; + if( op != FunrvOp ) + { + printOp( + std::cout, + play, + itr.op_index(), + i_var, + op, + arg + ); + if( NumRes(op) > 0 ) printOpResult( + std::cout, + q + 1, + Z_tmp, + 0, + (Base *) nullptr + ); + std::cout << std::endl; + } + } + std::cout << std::endl; +# else + } +# endif + CPPAD_ASSERT_UNKNOWN( atom_state == start_atom ); + + if( (p == 0) & (compare_change_count == 0) ) + compare_change_number = 0; + return; +} + +// preprocessor symbols that are local to this file +# undef CPPAD_FORWARD1_TRACE + +} } } // END_CPPAD_LOCAL_SWEEP_NAMESPACE +# endif diff --git a/build-config/cppad/include/cppad/local/sweep/forward2.hpp b/build-config/cppad/include/cppad/local/sweep/forward2.hpp new file mode 100644 index 00000000..39d32a94 --- /dev/null +++ b/build-config/cppad/include/cppad/local/sweep/forward2.hpp @@ -0,0 +1,786 @@ +# ifndef CPPAD_LOCAL_SWEEP_FORWARD2_HPP +# define CPPAD_LOCAL_SWEEP_FORWARD2_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +# include +# include + +// BEGIN_CPPAD_LOCAL_SWEEP_NAMESPACE +namespace CppAD { namespace local { namespace sweep { +/*! +\file sweep/forward2.hpp +Compute one Taylor coefficient for each direction requested. +*/ + +/*! +\def CPPAD_FORWARD2_TRACE +This value is either zero or one. +Zero is the normal operational value. +If it is one, a trace of every forward2sweep computation is printed. +*/ +# define CPPAD_FORWARD2_TRACE 0 + +/*! +Compute multiple directions forward mode Taylor coefficients. + +\tparam Base +The type used during the forward mode computations; i.e., the corresponding +recording of operations used the type AD. + +\param q +is the order of the Taylor coefficients +that are computed during this call; +q > 0. + +\param r +is the number of Taylor coefficients +that are computed during this call. + +\param n +is the number of independent variables on the tape. + +\param numvar +is the total number of variables on the tape. +This is also equal to the number of rows in the matrix taylor; i.e., +play->num_var_rec(). + +\param play +The information stored in play +is a recording of the operations corresponding to the function +\f[ + F : {\bf R}^n \rightarrow {\bf R}^m +\f] +where \f$ n \f$ is the number of independent variables and +\f$ m \f$ is the number of dependent variables. + +\param J +Is the number of columns in the coefficient matrix taylor. +This must be greater than or equal one. + +\param taylor +\n +\b Input: +For i = 1 , ... , numvar-1, +taylor[ (J-1)*r*i + i + 0 ] +is the zero order Taylor coefficient corresponding to +the i-th variable and all directions. +For i = 1 , ... , numvar-1, +For k = 1 , ... , q-1, +ell = 0 , ... , r-1, +taylor[ (J-1)*r*i + i + (k-1)*r + ell + 1 ] +is the k-th order Taylor coefficient corresponding to +the i-th variabel and ell-th direction. +\n +\n +\b Input: +For i = 1 , ... , n, +ell = 0 , ... , r-1, +taylor[ (J-1)*r*i + i + (q-1)*r + ell + 1 ] +is the q-th order Taylor coefficient corresponding to +the i-th variable and ell-th direction +(these are the independent varaibles). +\n +\n +\b Output: +For i = n+1 , ... , numvar-1, +ell = 0 , ... , r-1, +taylor[ (J-1)*r*i + i + (q-1)*r + ell + 1 ] +is the q-th order Taylor coefficient corresponding to +the i-th variable and ell-th direction. + +\param cskip_op +Is a vector with size play->num_op_rec(). +If cskip_op[i] is true, the operator with index i +does not affect any of the dependent variable (given the value +of the independent variables). + +\param load_op2var +is a vector with size play->num_var_load_rec(). +It is the variable index corresponding to each the +load instruction. +In the case where the index is zero, +the instruction corresponds to a parameter (not variable). + +\param not_used_rec_base +Specifies RecBase for this call. + +*/ + +template +void forward2( + const local::player* play, + const size_t q, + const size_t r, + const size_t n, + const size_t numvar, + const size_t J, + Base* taylor, + const bool* cskip_op, + const pod_vector& load_op2var, + const RecBase& not_used_rec_base +) +{ + CPPAD_ASSERT_UNKNOWN( q > 0 ); + CPPAD_ASSERT_UNKNOWN( J >= q + 1 ); + CPPAD_ASSERT_UNKNOWN( play->num_var_rec() == numvar ); + + // only compute one order at a time when using multi-direction forward + size_t p = q; + + // information used by atomic function operators + const pod_vector& dyn_par_is( play->dyn_par_is() ); + const size_t need_y = size_t( variable_enum ); + const size_t order_low = p; + const size_t order_up = q; + + // vectors used by atomic function operators + vector atom_par_x; // argument parameter values + vector atom_type_x; // argument type + vector atom_tx_one; // argument vector Taylor coefficients + vector atom_tx_all; + vector atom_ty_one; // result vector Taylor coefficients + vector atom_ty_all; + // + // information defined by atomic function operators + size_t atom_index=0, atom_old=0, atom_m=0, atom_n=0, atom_i=0, atom_j=0; + enum_atom_state atom_state = start_atom; // proper initialization + // + // length of the parameter vector (used by CppAD assert macros) + const size_t num_par = play->num_par_rec(); + + // pointer to the beginning of the parameter vector + CPPAD_ASSERT_UNKNOWN( num_par > 0 ) + const Base* parameter = play->GetPar(); + + // temporary indices + size_t i, j, k, ell; + + // number of orders for this atomic calculation + // (not needed for order zero) + const size_t atom_q1 = q+1; + + // variable indices for results vector + // (done differently for order zero). + vector atom_iy; + + // skip the BeginOp at the beginning of the recording + play::const_sequential_iterator itr = play->begin(); + // op_info + OpCode op; + size_t i_var; + const Addr* arg; + itr.op_info(op, arg, i_var); + CPPAD_ASSERT_UNKNOWN( op == BeginOp ); +# if CPPAD_FORWARD2_TRACE + bool atom_trace = false; + std::cout << std::endl; + CppAD::vector Z_vec(q+1); +# endif + bool flag; // a temporary flag to use in switch cases + bool more_operators = true; + while(more_operators) + { + // next op + (++itr).op_info(op, arg, i_var); + CPPAD_ASSERT_UNKNOWN( itr.op_index() < play->num_op_rec() ); + + // check if we are skipping this operation + while( cskip_op[itr.op_index()] ) + { switch(op) + { + case AFunOp: + { // get information for this atomic function call + CPPAD_ASSERT_UNKNOWN( atom_state == start_atom ); + play::atom_op_info( + op, arg, atom_index, atom_old, atom_m, atom_n + ); + // + // skip to the second AFunOp + for(i = 0; i < atom_m + atom_n + 1; ++i) + ++itr; +# ifndef NDEBUG + itr.op_info(op, arg, i_var); + CPPAD_ASSERT_UNKNOWN( op == AFunOp ); +# endif + } + break; + + case CSkipOp: + case CSumOp: + itr.correct_before_increment(); + break; + + default: + break; + } + (++itr).op_info(op, arg, i_var); + } + + // action depends on the operator + switch( op ) + { + case AbsOp: + forward_abs_op_dir(q, r, i_var, size_t(arg[0]), J, taylor); + break; + // ------------------------------------------------- + + case AddvvOp: + forward_addvv_op_dir(q, r, i_var, arg, parameter, J, taylor); + break; + // ------------------------------------------------- + + case AddpvOp: + CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) < num_par ); + forward_addpv_op_dir(q, r, i_var, arg, parameter, J, taylor); + break; + // ------------------------------------------------- + + case AcosOp: + // sqrt(1 - x * x), acos(x) + CPPAD_ASSERT_UNKNOWN( i_var < numvar ); + forward_acos_op_dir(q, r, i_var, size_t(arg[0]), J, taylor); + break; + // ------------------------------------------------- + + case AcoshOp: + // sqrt(x * x - 1), acosh(x) + CPPAD_ASSERT_UNKNOWN( i_var < numvar ); + forward_acosh_op_dir(q, r, i_var, size_t(arg[0]), J, taylor); + break; + // ------------------------------------------------- + + case AsinOp: + // sqrt(1 - x * x), asin(x) + CPPAD_ASSERT_UNKNOWN( i_var < numvar ); + forward_asin_op_dir(q, r, i_var, size_t(arg[0]), J, taylor); + break; + // ------------------------------------------------- + + case AsinhOp: + // sqrt(1 + x * x), asinh(x) + CPPAD_ASSERT_UNKNOWN( i_var < numvar ); + forward_asinh_op_dir(q, r, i_var, size_t(arg[0]), J, taylor); + break; + // ------------------------------------------------- + + case AtanOp: + // 1 + x * x, atan(x) + CPPAD_ASSERT_UNKNOWN( i_var < numvar ); + forward_atan_op_dir(q, r, i_var, size_t(arg[0]), J, taylor); + break; + // ------------------------------------------------- + + case AtanhOp: + // 1 - x * x, atanh(x) + CPPAD_ASSERT_UNKNOWN( i_var < numvar ); + forward_atanh_op_dir(q, r, i_var, size_t(arg[0]), J, taylor); + break; + // ------------------------------------------------- + + case CExpOp: + forward_cond_op_dir( + q, r, i_var, arg, num_par, parameter, J, taylor + ); + break; + // --------------------------------------------------- + + case CosOp: + // sin(x), cos(x) + CPPAD_ASSERT_UNKNOWN( i_var < numvar ); + forward_cos_op_dir(q, r, i_var, size_t(arg[0]), J, taylor); + break; + // --------------------------------------------------- + + case CoshOp: + // sinh(x), cosh(x) + CPPAD_ASSERT_UNKNOWN( i_var < numvar ); + forward_cosh_op_dir(q, r, i_var, size_t(arg[0]), J, taylor); + break; + // ------------------------------------------------- + + case CSkipOp: + // CSkipOp only does somthing on order zero. + CPPAD_ASSERT_UNKNOWN( p > 0 ); + itr.correct_before_increment(); + break; + // ------------------------------------------------- + + case CSumOp: + forward_csum_op_dir( + q, r, i_var, arg, num_par, parameter, J, taylor + ); + itr.correct_before_increment(); + break; + // ------------------------------------------------- + + case DisOp: + forward_dis_op(p, q, r, i_var, arg, J, taylor); + break; + // ------------------------------------------------- + + case DivvvOp: + forward_divvv_op_dir(q, r, i_var, arg, parameter, J, taylor); + break; + // ------------------------------------------------- + + case DivpvOp: + CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) < num_par ); + forward_divpv_op_dir(q, r, i_var, arg, parameter, J, taylor); + break; + // ------------------------------------------------- + + case DivvpOp: + CPPAD_ASSERT_UNKNOWN( size_t(arg[1]) < num_par ); + forward_divvp_op_dir(q, r, i_var, arg, parameter, J, taylor); + break; + // ------------------------------------------------- + + case EndOp: + // needed for sparse_jacobian test + CPPAD_ASSERT_NARG_NRES(op, 0, 0); + more_operators = false; + break; + // ------------------------------------------------- + + case ErfOp: + case ErfcOp: + forward_erf_op_dir(op, q, r, i_var, arg, parameter, J, taylor); + break; + // ------------------------------------------------- + + case ExpOp: + forward_exp_op_dir(q, r, i_var, size_t(arg[0]), J, taylor); + break; + // ------------------------------------------------- + + case Expm1Op: + forward_expm1_op_dir(q, r, i_var, size_t(arg[0]), J, taylor); + break; + // ------------------------------------------------- + + case InvOp: + CPPAD_ASSERT_NARG_NRES(op, 0, 1); + break; + // ------------------------------------------------- + + case LdpOp: + case LdvOp: + forward_load_op( + play, + op, + p, + q, + r, + J, + i_var, + arg, + load_op2var.data(), + taylor + ); + break; + // --------------------------------------------------- + + case EqppOp: + case EqpvOp: + case EqvvOp: + case LtppOp: + case LtpvOp: + case LtvpOp: + case LtvvOp: + case LeppOp: + case LepvOp: + case LevpOp: + case LevvOp: + case NeppOp: + case NepvOp: + case NevvOp: + CPPAD_ASSERT_UNKNOWN(q > 0 ); + break; + // ------------------------------------------------- + + case LogOp: + forward_log_op_dir(q, r, i_var, size_t(arg[0]), J, taylor); + break; + // --------------------------------------------------- + + case Log1pOp: + forward_log1p_op_dir(q, r, i_var, size_t(arg[0]), J, taylor); + break; + // --------------------------------------------------- + + case MulpvOp: + CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) < num_par ); + forward_mulpv_op_dir(q, r, i_var, arg, parameter, J, taylor); + break; + // ------------------------------------------------- + + case MulvvOp: + forward_mulvv_op_dir(q, r, i_var, arg, parameter, J, taylor); + break; + // ------------------------------------------------- + + case ParOp: + k = i_var*(J-1)*r + i_var + (q-1)*r + 1; + for(ell = 0; ell < r; ell++) + taylor[k + ell] = Base(0.0); + break; + // ------------------------------------------------- + + case PowpvOp: + CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) < num_par ); + forward_powpv_op_dir(q, r, i_var, arg, parameter, J, taylor); + break; + // ------------------------------------------------- + + case PowvpOp: + CPPAD_ASSERT_UNKNOWN( size_t(arg[1]) < num_par ); + forward_powvp_op_dir(q, r, i_var, arg, parameter, J, taylor); + break; + // ------------------------------------------------- + + case PowvvOp: + forward_powvv_op_dir(q, r, i_var, arg, parameter, J, taylor); + break; + // ------------------------------------------------- + + case PriOp: + CPPAD_ASSERT_UNKNOWN(q > 0); + break; + // ------------------------------------------------- + + case SignOp: + // sign(x) + CPPAD_ASSERT_UNKNOWN( i_var < numvar ); + forward_sign_op_dir(q, r, i_var, size_t(arg[0]), J, taylor); + break; + // ------------------------------------------------- + + case SinOp: + // cos(x), sin(x) + CPPAD_ASSERT_UNKNOWN( i_var < numvar ); + forward_sin_op_dir(q, r, i_var, size_t(arg[0]), J, taylor); + break; + // ------------------------------------------------- + + case SinhOp: + // cosh(x), sinh(x) + CPPAD_ASSERT_UNKNOWN( i_var < numvar ); + forward_sinh_op_dir(q, r, i_var, size_t(arg[0]), J, taylor); + break; + // ------------------------------------------------- + + case SqrtOp: + forward_sqrt_op_dir(q, r, i_var, size_t(arg[0]), J, taylor); + break; + // ------------------------------------------------- + + case StppOp: + case StpvOp: + case StvpOp: + case StvvOp: + CPPAD_ASSERT_UNKNOWN(q > 0 ); + break; + // ------------------------------------------------- + + case SubvvOp: + forward_subvv_op_dir(q, r, i_var, arg, parameter, J, taylor); + break; + // ------------------------------------------------- + + case SubpvOp: + CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) < num_par ); + forward_subpv_op_dir(q, r, i_var, arg, parameter, J, taylor); + break; + // ------------------------------------------------- + + case SubvpOp: + CPPAD_ASSERT_UNKNOWN( size_t(arg[1]) < num_par ); + forward_subvp_op_dir(q, r, i_var, arg, parameter, J, taylor); + break; + // ------------------------------------------------- + + case TanOp: + // tan(x)^2, tan(x) + CPPAD_ASSERT_UNKNOWN( i_var < numvar ); + forward_tan_op_dir(q, r, i_var, size_t(arg[0]), J, taylor); + break; + // ------------------------------------------------- + + case TanhOp: + // tanh(x)^2, tanh(x) + CPPAD_ASSERT_UNKNOWN( i_var < numvar ); + forward_tanh_op_dir(q, r, i_var, size_t(arg[0]), J, taylor); + break; + // ------------------------------------------------- + + case AFunOp: + // start or end an atomic function call + flag = atom_state == start_atom; + play::atom_op_info( + op, arg, atom_index, atom_old, atom_m, atom_n + ); + if( flag ) + { atom_state = arg_atom; + atom_i = 0; + atom_j = 0; + // + atom_par_x.resize(atom_n); + atom_type_x.resize(atom_n); + // + atom_tx_one.resize(atom_n * atom_q1); + atom_tx_all.resize(atom_n * (q * r + 1)); + // + atom_ty_one.resize(atom_m * atom_q1); + atom_ty_all.resize(atom_m * (q * r + 1)); + // + atom_iy.resize(atom_m); + } + else + { CPPAD_ASSERT_UNKNOWN( atom_i == atom_m ); + CPPAD_ASSERT_UNKNOWN( atom_j == atom_n ); + atom_state = start_atom; + // + // call atomic function for this operation + for(ell = 0; ell < r; ell++) + { // set atom_tx + for(j = 0; j < atom_n; j++) + { size_t j_all = j * (q * r + 1); + size_t j_one = j * atom_q1; + atom_tx_one[j_one+0] = atom_tx_all[j_all+0]; + for(k = 1; k < atom_q1; k++) + { size_t k_all = j_all + (k-1)*r+1+ell; + size_t k_one = j_one + k; + atom_tx_one[k_one] = atom_tx_all[k_all]; + } + } + // set atom_ty + for(i = 0; i < atom_m; i++) + { size_t i_all = i * (q * r + 1); + size_t i_one = i * atom_q1; + atom_ty_one[i_one+0] = atom_ty_all[i_all+0]; + for(k = 1; k < q; k++) + { size_t k_all = i_all + (k-1)*r+1+ell; + size_t k_one = i_one + k; + atom_ty_one[k_one] = atom_ty_all[k_all]; + } + } + call_atomic_forward( + atom_par_x, + atom_type_x, + need_y, + order_low, + order_up, + atom_index, + atom_old, + atom_tx_one, + atom_ty_one + ); + for(i = 0; i < atom_m; i++) + { if( atom_iy[i] > 0 ) + { size_t i_taylor = atom_iy[i]*((J-1)*r+1); + size_t q_taylor = i_taylor + (q-1)*r+1+ell; + size_t q_one = i * atom_q1 + q; + taylor[q_taylor] = atom_ty_one[q_one]; + } + } + } +# if CPPAD_FORWARD2_TRACE + atom_trace = true; +# endif + } + break; + + case FunapOp: + // parameter argument for a atomic function + CPPAD_ASSERT_UNKNOWN( NumArg(op) == 1 ); + CPPAD_ASSERT_UNKNOWN( atom_state == arg_atom ); + CPPAD_ASSERT_UNKNOWN( atom_i == 0 ); + CPPAD_ASSERT_UNKNOWN( atom_j < atom_n ); + CPPAD_ASSERT_UNKNOWN( size_t( arg[0] ) < num_par ); + // + if( dyn_par_is[ arg[0] ] ) + atom_type_x[atom_j] = dynamic_enum; + else + atom_type_x[atom_j] = constant_enum; + atom_par_x[atom_j] = parameter[ arg[0] ]; + atom_tx_all[atom_j*(q*r+1) + 0] = parameter[ arg[0]]; + for(ell = 0; ell < r; ell++) + for(k = 1; k < atom_q1; k++) + atom_tx_all[atom_j*(q*r+1) + (k-1)*r+1+ell] = Base(0.0); + // + ++atom_j; + if( atom_j == atom_n ) + atom_state = ret_atom; + break; + + case FunavOp: + // variable argument for a atomic function + CPPAD_ASSERT_UNKNOWN( NumArg(op) == 1 ); + CPPAD_ASSERT_UNKNOWN( atom_state == arg_atom ); + CPPAD_ASSERT_UNKNOWN( atom_i == 0 ); + CPPAD_ASSERT_UNKNOWN( atom_j < atom_n ); + // + atom_type_x[atom_j] = variable_enum; + atom_par_x[atom_j] = CppAD::numeric_limits::quiet_NaN(); + atom_tx_all[atom_j*(q*r+1)+0] = + taylor[size_t(arg[0])*((J-1)*r+1)+0]; + for(ell = 0; ell < r; ell++) + { for(k = 1; k < atom_q1; k++) + { atom_tx_all[atom_j*(q*r+1) + (k-1)*r+1+ell] = + taylor[size_t(arg[0])*((J-1)*r+1) + (k-1)*r+1+ell]; + } + } + // + ++atom_j; + if( atom_j == atom_n ) + atom_state = ret_atom; + break; + + case FunrpOp: + // parameter result for a atomic function + CPPAD_ASSERT_NARG_NRES(op, 1, 0); + CPPAD_ASSERT_UNKNOWN( atom_state == ret_atom ); + CPPAD_ASSERT_UNKNOWN( atom_i < atom_m ); + CPPAD_ASSERT_UNKNOWN( atom_j == atom_n ); + // + atom_iy[atom_i] = 0; + atom_ty_all[atom_i*(q*r+1) + 0] = parameter[ arg[0]]; + for(ell = 0; ell < r; ell++) + for(k = 1; k < atom_q1; k++) + atom_ty_all[atom_i*(q*r+1) + (k-1)*r+1+ell] = Base(0.0); + // + ++atom_i; + if( atom_i == atom_m ) + atom_state = end_atom; + break; + + case FunrvOp: + // variable result for a atomic function + CPPAD_ASSERT_NARG_NRES(op, 0, 1); + CPPAD_ASSERT_UNKNOWN( atom_state == ret_atom ); + CPPAD_ASSERT_UNKNOWN( atom_i < atom_m ); + CPPAD_ASSERT_UNKNOWN( atom_j == atom_n ); + // + atom_iy[atom_i] = i_var; + atom_ty_all[atom_i*(q*r+1)+0] = taylor[i_var*((J-1)*r+1)+0]; + for(ell = 0; ell < r; ell++) + { for(k = 1; k < atom_q1; k++) + { atom_ty_all[atom_i*(q*r+1) + (k-1)*r+1+ell] = + taylor[i_var*((J-1)*r+1) + (k-1)*r+1+ell]; + } + } + ++atom_i; + if( atom_i == atom_m ) + atom_state = end_atom; + break; + // ------------------------------------------------- + + case ZmulpvOp: + CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) < num_par ); + forward_zmulpv_op_dir(q, r, i_var, arg, parameter, J, taylor); + break; + // ------------------------------------------------- + + case ZmulvpOp: + CPPAD_ASSERT_UNKNOWN( size_t(arg[1]) < num_par ); + forward_zmulvp_op_dir(q, r, i_var, arg, parameter, J, taylor); + break; + // ------------------------------------------------- + + case ZmulvvOp: + forward_zmulvv_op_dir(q, r, i_var, arg, parameter, J, taylor); + break; + // ------------------------------------------------- + + default: + CPPAD_ASSERT_UNKNOWN(0); + } +# if CPPAD_FORWARD2_TRACE + if( atom_trace ) + { atom_trace = false; + CPPAD_ASSERT_UNKNOWN( op == AFunOp ); + CPPAD_ASSERT_UNKNOWN( NumArg(FunrvOp) == 0 ); + for(i = 0; i < atom_m; i++) if( atom_iy[i] > 0 ) + { size_t i_tmp = (itr.op_index() + i) - atom_m; + printOp( + std::cout, + play, + i_tmp, + atom_iy[i], + FunrvOp, + nullptr + ); + Base* Z_tmp = taylor + atom_iy[i]*((J-1) * r + 1); + { Z_vec[0] = Z_tmp[0]; + for(ell = 0; ell < r; ell++) + { std::cout << std::endl << " "; + for(size_t p_tmp = 1; p_tmp <= q; p_tmp++) + Z_vec[p_tmp] = Z_tmp[(p_tmp-1)*r+ell+1]; + printOpResult( + std::cout, + q + 1, + Z_vec.data(), + 0, + (Base *) nullptr + ); + } + } + std::cout << std::endl; + } + } + if( op != FunrvOp ) + { printOp( + std::cout, + play, + itr.op_index(), + i_var, + op, + arg + ); + Base* Z_tmp = nullptr; + if( op == FunavOp ) + Z_tmp = taylor + size_t(arg[0])*((J-1) * r + 1); + else if( NumRes(op) > 0 ) + Z_tmp = taylor + i_var*((J-1)*r + 1); + if( Z_tmp != nullptr ) + { Z_vec[0] = Z_tmp[0]; + for(ell = 0; ell < r; ell++) + { std::cout << std::endl << " "; + for(size_t p_tmp = 1; p_tmp <= q; p_tmp++) + Z_vec[p_tmp] = Z_tmp[ (p_tmp-1)*r + ell + 1]; + printOpResult( + std::cout, + q + 1, + Z_vec.data(), + 0, + (Base *) nullptr + ); + } + } + std::cout << std::endl; + } + } + std::cout << std::endl; +# else + } +# endif + CPPAD_ASSERT_UNKNOWN( atom_state == start_atom ); + + return; +} + +// preprocessor symbols that are local to this file +# undef CPPAD_FORWARD2_TRACE + +} } } // END_CPPAD_LOCAL_SWEEP_NAMESPACE +# endif diff --git a/build-config/cppad/include/cppad/local/sweep/rev_hes.hpp b/build-config/cppad/include/cppad/local/sweep/rev_hes.hpp new file mode 100644 index 00000000..2ce3e443 --- /dev/null +++ b/build-config/cppad/include/cppad/local/sweep/rev_hes.hpp @@ -0,0 +1,802 @@ +# ifndef CPPAD_LOCAL_SWEEP_REV_HES_HPP +# define CPPAD_LOCAL_SWEEP_REV_HES_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +# include +# include + +// BEGIN_CPPAD_LOCAL_SWEEP_NAMESPACE +namespace CppAD { namespace local { namespace sweep { +/*! +\file sweep/rev_hes.hpp +Compute Reverse mode Hessian sparsity patterns. +*/ + +/*! +\def CPPAD_REV_HES_TRACE +This value is either zero or one. +Zero is the normal operational value. +If it is one, a trace of every rev_hes_sweep computation is printed. +*/ +# define CPPAD_REV_HES_TRACE 0 + +/*! +Given the forward Jacobian sparsity pattern for all the variables, +and the reverse Jacobian sparsity pattern for the dependent variables, +RevHesSweep computes the Hessian sparsity pattern for all the independent +variables. + +\tparam Base +this operation sequence was recorded using AD. + +\tparam Vector_set +is the type used for vectors of sets. It can be either +sparse::pack_setvec or sparse::list_setvec. + +\param n +is the number of independent variables on the tape. + +\param numvar +is the total number of variables on the tape; i.e., + play->num_var_rec(). +This is also the number of rows in the entire sparsity pattern + rev_hes_sparse. + +\param play +The information stored in play +is a recording of the operations corresponding to a function +\f[ + F : {\bf R}^n \rightarrow {\bf R}^m +\f] +where \f$ n \f$ is the number of independent variables +and \f$ m \f$ is the number of dependent variables. + +\param for_jac_sparse +For i = 0 , ... , numvar - 1, +(for all the variables on the tape), +the forward Jacobian sparsity pattern for the variable with index i +corresponds to the set with index i in for_jac_sparse. + +\param RevJac +\b Input: +For i = 0, ... , numvar - 1 +the if the variable with index i on the tape is an dependent variable and +included in the Hessian, RevJac[ i ] is equal to true, +otherwise it is equal to false. +\n +\n +\b Output: The values in RevJac upon return are not specified; i.e., +it is used for temporary work space. + +\param rev_hes_sparse +The reverse Hessian sparsity pattern for the variable with index i +corresponds to the set with index i in rev_hes_sparse. +\n +\n +\b Input: For i = 0 , ... , numvar - 1 +the reverse Hessian sparsity pattern for the variable with index i is empty. +\n +\n +\b Output: For j = 1 , ... , n, +the reverse Hessian sparsity pattern for the independent dependent variable +with index (j-1) is given by the set with index j +in rev_hes_sparse. +The values in the rest of rev_hes_sparse are not specified; i.e., +they are used for temporary work space. + +\param not_used_rec_base +Specifies RecBase for this call. +*/ + +template +void rev_hes( + const local::player* play, + size_t n, + size_t numvar, + const Vector_set& for_jac_sparse, + bool* RevJac, + Vector_set& rev_hes_sparse, + const RecBase& not_used_rec_base +) +{ + // length of the parameter vector (used by CppAD assert macros) + const size_t num_par = play->num_par_rec(); + + size_t i, j, k; + + // check numvar argument + CPPAD_ASSERT_UNKNOWN( play->num_var_rec() == numvar ); + CPPAD_ASSERT_UNKNOWN( for_jac_sparse.n_set() == numvar ); + CPPAD_ASSERT_UNKNOWN( rev_hes_sparse.n_set() == numvar ); + CPPAD_ASSERT_UNKNOWN( numvar > 0 ); + + // upper limit exclusive for set elements + size_t limit = rev_hes_sparse.end(); + CPPAD_ASSERT_UNKNOWN( for_jac_sparse.end() == limit ); + + // check number of sets match + CPPAD_ASSERT_UNKNOWN( + for_jac_sparse.n_set() == rev_hes_sparse.n_set() + ); + + // vecad_sparsity contains a sparsity pattern for each VecAD object. + // vecad_ind maps a VecAD index (beginning of the VecAD object) + // to the index for the corresponding set in vecad_sparsity. + size_t num_vecad_ind = play->num_var_vecad_ind_rec(); + size_t num_vecad_vec = play->num_var_vecad_rec(); + Vector_set vecad_sparse; + pod_vector vecad_ind; + pod_vector vecad_jac; + if( num_vecad_vec > 0 ) + { size_t length; + vecad_sparse.resize(num_vecad_vec, limit); + vecad_ind.extend(num_vecad_ind); + vecad_jac.extend(num_vecad_vec); + j = 0; + for(i = 0; i < num_vecad_vec; i++) + { // length of this VecAD + length = play->GetVecInd(j); + // set vecad_ind to proper index for this VecAD + vecad_ind[j] = i; + // make all other values for this vector invalid + for(k = 1; k <= length; k++) + vecad_ind[j+k] = num_vecad_vec; + // start of next VecAD + j += length + 1; + // initialize this vector's reverse jacobian value + vecad_jac[i] = false; + } + CPPAD_ASSERT_UNKNOWN( j == play->num_var_vecad_ind_rec() ); + } + + // ---------------------------------------------------------------------- + // work space used by AFunOp. + vector atom_x; // value of parameter arguments to function + vector type_x; // argument types + pod_vector atom_ix; // variable indices for argument vector + pod_vector atom_iy; // variable indices for result vector + // + // information set by atomic forward (initialization to avoid warnings) + size_t atom_index=0, atom_old=0, atom_m=0, atom_n=0, atom_i=0, atom_j=0; + // information set by atomic forward (necessary initialization) + enum_atom_state atom_state = end_atom; // proper initialization + // ---------------------------------------------------------------------- + // + // pointer to the beginning of the parameter vector + // (used by atomic functions + CPPAD_ASSERT_UNKNOWN( num_par > 0 ) + const Base* parameter = play->GetPar(); + // + // which parametes are dynamic + const pod_vector& dyn_par_is( play->dyn_par_is() ); + // + // skip the EndOp at the end of the recording + play::const_sequential_iterator itr = play->end(); + // op_info + OpCode op; + size_t i_var; + const Addr* arg; + itr.op_info(op, arg, i_var); + CPPAD_ASSERT_UNKNOWN( op == EndOp ); +# if CPPAD_REV_HES_TRACE + std::cout << std::endl; + CppAD::vectorBool zf_value(limit); + CppAD::vectorBool zh_value(limit); +# endif + bool more_operators = true; + while(more_operators) + { bool flag; // temporary for use in switch cases + // + // next op + (--itr).op_info(op, arg, i_var); + + // rest of information depends on the case + switch( op ) + { + case AbsOp: + CPPAD_ASSERT_NARG_NRES(op, 1, 1) + sparse::rev_hes_lin_unary_op( + i_var, size_t(arg[0]), RevJac, for_jac_sparse, rev_hes_sparse + ); + break; + // ------------------------------------------------- + + case AddvvOp: + CPPAD_ASSERT_NARG_NRES(op, 2, 1) + sparse::rev_hes_addsub_op( + i_var, arg, RevJac, for_jac_sparse, rev_hes_sparse + ); + break; + // ------------------------------------------------- + + case AddpvOp: + CPPAD_ASSERT_NARG_NRES(op, 2, 1) + sparse::rev_hes_lin_unary_op( + i_var, size_t(arg[1]), RevJac, for_jac_sparse, rev_hes_sparse + ); + break; + // ------------------------------------------------- + + case AcosOp: + // sqrt(1 - x * x), acos(x) + CPPAD_ASSERT_NARG_NRES(op, 1, 2) + sparse::rev_hes_nl_unary_op( + i_var, size_t(arg[0]), RevJac, for_jac_sparse, rev_hes_sparse + ); + break; + // ------------------------------------------------- + + case AcoshOp: + // sqrt(x * x - 1), acosh(x) + CPPAD_ASSERT_NARG_NRES(op, 1, 2) + sparse::rev_hes_nl_unary_op( + i_var, size_t(arg[0]), RevJac, for_jac_sparse, rev_hes_sparse + ); + break; + // ------------------------------------------------- + + case AsinOp: + // sqrt(1 - x * x), asin(x) + CPPAD_ASSERT_NARG_NRES(op, 1, 2) + sparse::rev_hes_nl_unary_op( + i_var, size_t(arg[0]), RevJac, for_jac_sparse, rev_hes_sparse + ); + break; + // ------------------------------------------------- + + case AsinhOp: + // sqrt(1 + x * x), asinh(x) + CPPAD_ASSERT_NARG_NRES(op, 1, 2) + sparse::rev_hes_nl_unary_op( + i_var, size_t(arg[0]), RevJac, for_jac_sparse, rev_hes_sparse + ); + break; + // ------------------------------------------------- + + case AtanOp: + // 1 + x * x, atan(x) + CPPAD_ASSERT_NARG_NRES(op, 1, 2) + sparse::rev_hes_nl_unary_op( + i_var, size_t(arg[0]), RevJac, for_jac_sparse, rev_hes_sparse + ); + break; + // ------------------------------------------------- + + case AtanhOp: + // 1 - x * x, atanh(x) + CPPAD_ASSERT_NARG_NRES(op, 1, 2) + sparse::rev_hes_nl_unary_op( + i_var, size_t(arg[0]), RevJac, for_jac_sparse, rev_hes_sparse + ); + break; + // ------------------------------------------------- + + case BeginOp: + CPPAD_ASSERT_NARG_NRES(op, 1, 1) + more_operators = false; + break; + // ------------------------------------------------- + + case CSkipOp: + itr.correct_after_decrement(arg); + break; + // ------------------------------------------------- + + case CSumOp: + itr.correct_after_decrement(arg); + reverse_sparse_hessian_csum_op( + i_var, arg, RevJac, rev_hes_sparse + ); + break; + // ------------------------------------------------- + + case CExpOp: + reverse_sparse_hessian_cond_op( + i_var, arg, num_par, RevJac, rev_hes_sparse + ); + break; + // --------------------------------------------------- + + case CosOp: + // sin(x), cos(x) + CPPAD_ASSERT_NARG_NRES(op, 1, 2) + sparse::rev_hes_nl_unary_op( + i_var, size_t(arg[0]), RevJac, for_jac_sparse, rev_hes_sparse + ); + break; + // --------------------------------------------------- + + case CoshOp: + // sinh(x), cosh(x) + CPPAD_ASSERT_NARG_NRES(op, 1, 2) + sparse::rev_hes_nl_unary_op( + i_var, size_t(arg[0]), RevJac, for_jac_sparse, rev_hes_sparse + ); + break; + // ------------------------------------------------- + + case DisOp: + CPPAD_ASSERT_NARG_NRES(op, 2, 1) + // derivativve is identically zero + break; + // ------------------------------------------------- + + case DivvvOp: + CPPAD_ASSERT_NARG_NRES(op, 2, 1) + sparse::rev_hes_div_op( + i_var, arg, RevJac, for_jac_sparse, rev_hes_sparse + ); + break; + // ------------------------------------------------- + + case DivpvOp: + CPPAD_ASSERT_NARG_NRES(op, 2, 1) + sparse::rev_hes_nl_unary_op( + i_var, size_t(arg[1]), RevJac, for_jac_sparse, rev_hes_sparse + ); + break; + // ------------------------------------------------- + + case DivvpOp: + CPPAD_ASSERT_NARG_NRES(op, 2, 1) + sparse::rev_hes_lin_unary_op( + i_var, size_t(arg[0]), RevJac, for_jac_sparse, rev_hes_sparse + ); + break; + // ------------------------------------------------- + + case ErfOp: + case ErfcOp: + // arg[1] is always the parameter 0 + // arg[2] is always the parameter 2 / sqrt(pi) + CPPAD_ASSERT_NARG_NRES(op, 3, 5); + sparse::rev_hes_nl_unary_op( + i_var, size_t(arg[0]), RevJac, for_jac_sparse, rev_hes_sparse + ); + break; + // ------------------------------------------------- + + case ExpOp: + CPPAD_ASSERT_NARG_NRES(op, 1, 1) + sparse::rev_hes_nl_unary_op( + i_var, size_t(arg[0]), RevJac, for_jac_sparse, rev_hes_sparse + ); + break; + // ------------------------------------------------- + + case Expm1Op: + CPPAD_ASSERT_NARG_NRES(op, 1, 1) + sparse::rev_hes_nl_unary_op( + i_var, size_t(arg[0]), RevJac, for_jac_sparse, rev_hes_sparse + ); + break; + // ------------------------------------------------- + + case InvOp: + CPPAD_ASSERT_NARG_NRES(op, 0, 1) + // Z is already defined + break; + // ------------------------------------------------- + + case LdpOp: + reverse_sparse_hessian_load_op( + op, + i_var, + arg, + num_vecad_ind, + vecad_ind.data(), + rev_hes_sparse, + vecad_sparse, + RevJac, + vecad_jac.data() + ); + break; + // ------------------------------------------------- + + case LdvOp: + reverse_sparse_hessian_load_op( + op, + i_var, + arg, + num_vecad_ind, + vecad_ind.data(), + rev_hes_sparse, + vecad_sparse, + RevJac, + vecad_jac.data() + ); + break; + // ------------------------------------------------- + + case EqppOp: + case EqpvOp: + case EqvvOp: + case LtppOp: + case LtpvOp: + case LtvpOp: + case LtvvOp: + case LeppOp: + case LepvOp: + case LevpOp: + case LevvOp: + case NeppOp: + case NepvOp: + case NevvOp: + CPPAD_ASSERT_NARG_NRES(op, 2, 0); + break; + // ------------------------------------------------- + + case LogOp: + CPPAD_ASSERT_NARG_NRES(op, 1, 1) + sparse::rev_hes_nl_unary_op( + i_var, size_t(arg[0]), RevJac, for_jac_sparse, rev_hes_sparse + ); + break; + // ------------------------------------------------- + + case Log1pOp: + CPPAD_ASSERT_NARG_NRES(op, 1, 1) + sparse::rev_hes_nl_unary_op( + i_var, size_t(arg[0]), RevJac, for_jac_sparse, rev_hes_sparse + ); + break; + // ------------------------------------------------- + + case MulpvOp: + CPPAD_ASSERT_NARG_NRES(op, 2, 1) + sparse::rev_hes_lin_unary_op( + i_var, size_t(arg[1]), RevJac, for_jac_sparse, rev_hes_sparse + ); + break; + // ------------------------------------------------- + + case MulvvOp: + CPPAD_ASSERT_NARG_NRES(op, 2, 1) + sparse::rev_hes_mul_op( + i_var, arg, RevJac, for_jac_sparse, rev_hes_sparse + ); + break; + // ------------------------------------------------- + + case ParOp: + CPPAD_ASSERT_NARG_NRES(op, 1, 1) + + break; + // ------------------------------------------------- + + case PowpvOp: + CPPAD_ASSERT_NARG_NRES(op, 2, 3) + sparse::rev_hes_nl_unary_op( + i_var, size_t(arg[1]), RevJac, for_jac_sparse, rev_hes_sparse + ); + break; + // ------------------------------------------------- + + case PowvpOp: + CPPAD_ASSERT_NARG_NRES(op, 2, 3) + sparse::rev_hes_nl_unary_op( + i_var, size_t(arg[0]), RevJac, for_jac_sparse, rev_hes_sparse + ); + break; + // ------------------------------------------------- + + case PowvvOp: + CPPAD_ASSERT_NARG_NRES(op, 2, 3) + sparse::rev_hes_pow_op( + i_var, arg, RevJac, for_jac_sparse, rev_hes_sparse + ); + break; + // ------------------------------------------------- + + case PriOp: + CPPAD_ASSERT_NARG_NRES(op, 5, 0); + break; + // ------------------------------------------------- + + case SignOp: + CPPAD_ASSERT_NARG_NRES(op, 1, 1); + // Derivative is identiaclly zero + break; + // ------------------------------------------------- + + case SinOp: + // cos(x), sin(x) + CPPAD_ASSERT_NARG_NRES(op, 1, 2) + sparse::rev_hes_nl_unary_op( + i_var, size_t(arg[0]), RevJac, for_jac_sparse, rev_hes_sparse + ); + break; + // ------------------------------------------------- + + case SinhOp: + // cosh(x), sinh(x) + CPPAD_ASSERT_NARG_NRES(op, 1, 2) + sparse::rev_hes_nl_unary_op( + i_var, size_t(arg[0]), RevJac, for_jac_sparse, rev_hes_sparse + ); + break; + // ------------------------------------------------- + + case SqrtOp: + CPPAD_ASSERT_NARG_NRES(op, 1, 1) + sparse::rev_hes_nl_unary_op( + i_var, size_t(arg[0]), RevJac, for_jac_sparse, rev_hes_sparse + ); + break; + // ------------------------------------------------- + + case StppOp: + // sparsity cannot propagate through a parameter + CPPAD_ASSERT_NARG_NRES(op, 3, 0) + break; + // ------------------------------------------------- + + case StpvOp: + reverse_sparse_hessian_store_op( + op, + arg, + num_vecad_ind, + vecad_ind.data(), + rev_hes_sparse, + vecad_sparse, + RevJac, + vecad_jac.data() + ); + break; + // ------------------------------------------------- + + case StvpOp: + // sparsity cannot propagate through a parameter + CPPAD_ASSERT_NARG_NRES(op, 3, 0) + break; + // ------------------------------------------------- + + case StvvOp: + reverse_sparse_hessian_store_op( + op, + arg, + num_vecad_ind, + vecad_ind.data(), + rev_hes_sparse, + vecad_sparse, + RevJac, + vecad_jac.data() + ); + break; + // ------------------------------------------------- + + case SubvvOp: + CPPAD_ASSERT_NARG_NRES(op, 2, 1) + sparse::rev_hes_addsub_op( + i_var, arg, RevJac, for_jac_sparse, rev_hes_sparse + ); + break; + // ------------------------------------------------- + + case SubpvOp: + CPPAD_ASSERT_NARG_NRES(op, 2, 1) + sparse::rev_hes_lin_unary_op( + i_var, size_t(arg[1]), RevJac, for_jac_sparse, rev_hes_sparse + ); + break; + // ------------------------------------------------- + + case SubvpOp: + CPPAD_ASSERT_NARG_NRES(op, 2, 1) + sparse::rev_hes_lin_unary_op( + i_var, size_t(arg[0]), RevJac, for_jac_sparse, rev_hes_sparse + ); + break; + // ------------------------------------------------- + + case TanOp: + // tan(x)^2, tan(x) + CPPAD_ASSERT_NARG_NRES(op, 1, 2) + sparse::rev_hes_nl_unary_op( + i_var, size_t(arg[0]), RevJac, for_jac_sparse, rev_hes_sparse + ); + break; + // ------------------------------------------------- + + case TanhOp: + // tanh(x)^2, tanh(x) + CPPAD_ASSERT_NARG_NRES(op, 1, 2) + sparse::rev_hes_nl_unary_op( + i_var, size_t(arg[0]), RevJac, for_jac_sparse, rev_hes_sparse + ); + break; + // ------------------------------------------------- + + case AFunOp: + // start or end an atomic function call + CPPAD_ASSERT_UNKNOWN( + atom_state == start_atom || atom_state == end_atom + ); + flag = atom_state == end_atom; + play::atom_op_info( + op, arg, atom_index, atom_old, atom_m, atom_n + ); + if( flag ) + { atom_state = ret_atom; + atom_i = atom_m; + atom_j = atom_n; + // + atom_x.resize(atom_n); + type_x.resize(atom_n); + atom_ix.resize(atom_n); + atom_iy.resize(atom_m); + } + else + { CPPAD_ASSERT_UNKNOWN( atom_i == 0 ); + CPPAD_ASSERT_UNKNOWN( atom_j == 0 ); + atom_state = end_atom; + // + // call atomic function for this operation + call_atomic_rev_hes_sparsity( + atom_index, atom_old, atom_x, type_x, atom_ix, atom_iy, + for_jac_sparse, RevJac, rev_hes_sparse + ); + } + break; + + case FunapOp: + // parameter argument in an atomic operation sequence + CPPAD_ASSERT_UNKNOWN( NumArg(op) == 1 ); + CPPAD_ASSERT_UNKNOWN( atom_state == arg_atom ); + CPPAD_ASSERT_UNKNOWN( atom_i == 0 ); + CPPAD_ASSERT_UNKNOWN( atom_j <= atom_n ); + CPPAD_ASSERT_UNKNOWN( size_t( arg[0] ) < num_par ); + // + --atom_j; + // argument parameter value + atom_x[atom_j] = parameter[arg[0]]; + // argument type + if( dyn_par_is[arg[0]] ) + type_x[atom_j] = dynamic_enum; + else + type_x[atom_j] = constant_enum; + // special variable index used for parameters + atom_ix[atom_j] = 0; + // + if( atom_j == 0 ) + atom_state = start_atom; + break; + + case FunavOp: + // variable argument in an atomic operation sequence + CPPAD_ASSERT_UNKNOWN( NumArg(op) == 1 ); + CPPAD_ASSERT_UNKNOWN( atom_state == arg_atom ); + CPPAD_ASSERT_UNKNOWN( atom_i == 0 ); + CPPAD_ASSERT_UNKNOWN( atom_j <= atom_n ); + // + --atom_j; + // argument variables not available during sparsity calculations + atom_x[atom_j] = CppAD::numeric_limits::quiet_NaN(); + type_x[atom_j] = variable_enum; + // variable index for this argument + atom_ix[atom_j] = size_t(arg[0]); + // + if( atom_j == 0 ) + atom_state = start_atom; + break; + + case FunrpOp: + // parameter result for a atomic function + CPPAD_ASSERT_NARG_NRES(op, 1, 0); + CPPAD_ASSERT_UNKNOWN( atom_state == ret_atom ); + CPPAD_ASSERT_UNKNOWN( atom_i <= atom_m ); + CPPAD_ASSERT_UNKNOWN( atom_j == atom_n ); + CPPAD_ASSERT_UNKNOWN( size_t( arg[0] ) < num_par ); + // + --atom_i; + atom_iy[atom_i] = 0; // special variable used for parameters + // + if( atom_i == 0 ) + atom_state = arg_atom; + break; + + case FunrvOp: + // variable result for a atomic function + CPPAD_ASSERT_NARG_NRES(op, 0, 1); + CPPAD_ASSERT_UNKNOWN( atom_state == ret_atom ); + CPPAD_ASSERT_UNKNOWN( atom_i <= atom_m ); + CPPAD_ASSERT_UNKNOWN( atom_j == atom_n ); + // + --atom_i; + atom_iy[atom_i] = i_var; // variable for this result + // + if( atom_i == 0 ) + atom_state = arg_atom; + break; + // ------------------------------------------------- + + case ZmulpvOp: + CPPAD_ASSERT_NARG_NRES(op, 2, 1) + sparse::rev_hes_lin_unary_op( + i_var, size_t(arg[1]), RevJac, for_jac_sparse, rev_hes_sparse + ); + break; + // ------------------------------------------------- + + case ZmulvpOp: + CPPAD_ASSERT_NARG_NRES(op, 2, 1) + sparse::rev_hes_lin_unary_op( + i_var, size_t(arg[0]), RevJac, for_jac_sparse, rev_hes_sparse + ); + break; + // ------------------------------------------------- + + case ZmulvvOp: + CPPAD_ASSERT_NARG_NRES(op, 2, 1) + sparse::rev_hes_mul_op( + i_var, arg, RevJac, for_jac_sparse, rev_hes_sparse + ); + break; + + // ------------------------------------------------- + + default: + CPPAD_ASSERT_UNKNOWN(0); + } +# if CPPAD_REV_HES_TRACE + for(j = 0; j < limit; j++) + { zf_value[j] = false; + zh_value[j] = false; + } + typename Vector_set::const_iterator itr_jac(for_jac_sparse, i_var); + j = *itr_jac; + while( j < limit ) + { zf_value[j] = true; + j = *(++itr_jac); + } + typename Vector_set::const_iterator itr_hes(rev_hes_sparse, i_var); + j = *itr_hes; + while( j < limit ) + { zh_value[j] = true; + j = *(++itr_hes); + } + printOp( + std::cout, + play, + itr.op_index(), + i_var, + op, + arg + ); + // should also print RevJac[i_var], but printOpResult does not + // yet allow for this + if( NumRes(op) > 0 && op != BeginOp ) printOpResult( + std::cout, + 1, + &zf_value, + 1, + &zh_value + ); + std::cout << std::endl; + } + std::cout << std::endl; +# else + } +# endif + // values corresponding to BeginOp + CPPAD_ASSERT_UNKNOWN( itr.op_index() == 0 ); + CPPAD_ASSERT_UNKNOWN( i_var == 0 ); + + return; +} +} } } // END_CPPAD_LOCAL_SWEEP_NAMESPACE + +// preprocessor symbols that are local to this file +# undef CPPAD_REV_HES_TRACE + +# endif diff --git a/build-config/cppad/include/cppad/local/sweep/rev_jac.hpp b/build-config/cppad/include/cppad/local/sweep/rev_jac.hpp new file mode 100644 index 00000000..5b344dc5 --- /dev/null +++ b/build-config/cppad/include/cppad/local/sweep/rev_jac.hpp @@ -0,0 +1,815 @@ +# ifndef CPPAD_LOCAL_SWEEP_REV_JAC_HPP +# define CPPAD_LOCAL_SWEEP_REV_JAC_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +# include +# include + +// This value is either zero or one. Zero is the normal operational value. +// If it is one, a trace of every rev_jac_sweep computation is printed. +# define CPPAD_REV_JAC_TRACE 0 + +/* +$begin local_sweep_rev_jac$$ +$spell + Jacobian + jac + Jacobian + numvar + var + Addr + CondExpRel + optimizer + num + setvec +$$ + +$section Reverse Mode Jacobian Sparsity Patterns$$ + +$head Syntax$$ +$codei%local::sweep::rev_jac( + %play% , + %dependency% , + %n% , + %numvar% , + %var_sparsity% , + %not_used_rec_base +)%$$ + +$head Prototype$$ +$srcthisfile% + 0%// BEGIN_PROTOTYPE%// END_PROTOTYPE%1 +%$$ + +$head Addr$$ +Is the type used to record address on this tape +This is allows for smaller tapes when address are smaller. + +$head Base$$ +this operation sequence was recorded using $codei%AD<%Base%>%$$. + +$head Vector_set$$ +is the type used for vectors of sets. It can be either +$code sparse::pack_setvec$$ or $code sparse::list_setvec$$. +$comment 2DO: in previous line change code to cref$$ + +$head RecBase$$ +Is the base type when this function was recorded. +This is different from $icode Base$$ if +this function object was created by $cref base2ad$$. + +$head play$$ +The information stored in play +is a recording of the operations corresponding to a function +$latex F : \B{R}^n \rightarrow \B{R}^m$$ +where $icode m$$ is the number of dependent variables. + +$head dependency$$ +Are we computing dependency relations, or only concerned with +possibly non-zero derivatives. For example, +are the derivatives with respect to +$icode left$$ and $icode right$$ of the expression below +considered to be non-zero: +$codei% + CondExpRel(%left%, %right%, %if_true%, %if_false%) +%$$ +This is used by the optimizer to obtain the correct dependency relations. + +$head n$$ +is the number of independent variables in the tape. + +$head numvar$$ +is the total number of variables in the tape; i.e., +$icode%play%->num_var_rec()%$$. +This is also the number of rows in all the sparsity patterns. + +$head var_sparsity$$ + +$subhead On Input$$ +For $icode%i% = 0 , ... , %numvar%-1%$$, +if $icode i$$ corresponds to a dependent variables, +the set with index $icode i$$ is an input. +Otherwise the set with index $icode i$$ is empty. + +$subhead On Output$$ +For $icode%i% = 0 , ... , %numvar%-1%$$, +the sparsity pattern for the variable with index $icode%j%-1%$$ +is given by the set with index $icode j$$ in $icode var_sparsity$$. +Note that one dependent variable may depend on the value of another, +in which case its output sparsity pattern may be different than its +input pattern. + +$head not_used_rec_base$$ +Specifies $icode RecBase$$ for this call. + +$end +*/ + +// BEGIN_CPPAD_LOCAL_SWEEP_NAMESPACE +namespace CppAD { namespace local { namespace sweep { + +// BEGIN_PROTOTYPE +template +void rev_jac( + const local::player* play , + bool dependency , + size_t n , + size_t numvar , + Vector_set& var_sparsity , + const RecBase& not_used_rec_base ) +// END_PROTOTYPE +{ + size_t i, j, k; + + // length of the parameter vector (used by CppAD assert macros) + const size_t num_par = play->num_par_rec(); + + // check numvar argument + CPPAD_ASSERT_UNKNOWN( numvar > 0 ); + CPPAD_ASSERT_UNKNOWN( play->num_var_rec() == numvar ); + CPPAD_ASSERT_UNKNOWN( var_sparsity.n_set() == numvar ); + + // upper limit (exclusive) for elements in the set + size_t limit = var_sparsity.end(); + + // vecad_sparsity contains a sparsity pattern for each VecAD object. + // vecad_ind maps a VecAD index (beginning of the VecAD object) + // to the index of the corresponding set in vecad_sparsity. + size_t num_vecad_ind = play->num_var_vecad_ind_rec(); + size_t num_vecad_vec = play->num_var_vecad_rec(); + Vector_set vecad_sparsity; + pod_vector vecad_ind; + if( num_vecad_vec > 0 ) + { size_t length; + vecad_sparsity.resize(num_vecad_vec, limit); + vecad_ind.extend(num_vecad_ind); + j = 0; + for(i = 0; i < num_vecad_vec; i++) + { // length of this VecAD + length = play->GetVecInd(j); + // set to proper index for this VecAD + vecad_ind[j] = i; + for(k = 1; k <= length; k++) + vecad_ind[j+k] = num_vecad_vec; // invalid index + // start of next VecAD + j += length + 1; + } + CPPAD_ASSERT_UNKNOWN( j == play->num_var_vecad_ind_rec() ); + } + + // ---------------------------------------------------------------------- + // work space used by AFunOp. + vector atom_x; // value of parameter arguments to function + vector type_x; // argument types + pod_vector atom_ix; // variable indices for argument vector + pod_vector atom_iy; // variable indices for result vector + // + // information set by atomic forward (initialization to avoid warnings) + size_t atom_index=0, atom_old=0, atom_m=0, atom_n=0, atom_i=0, atom_j=0; + // information set by atomic forward (necessary initialization) + enum_atom_state atom_state = end_atom; // proper initialization + // ---------------------------------------------------------------------- + // + // pointer to the beginning of the parameter vector + // (used by atomic functions + CPPAD_ASSERT_UNKNOWN( num_par > 0 ) + const Base* parameter = play->GetPar(); + // + // which parametes are dynamic + const pod_vector& dyn_par_is( play->dyn_par_is() ); + // + // skip the EndOp at the end of the recording + play::const_sequential_iterator itr = play->end(); + // op_info + OpCode op; + size_t i_var; + const Addr* arg; + itr.op_info(op, arg, i_var); + CPPAD_ASSERT_UNKNOWN( op == EndOp ); +# if CPPAD_REV_JAC_TRACE + std::cout << std::endl; + CppAD::vectorBool z_value(limit); +# endif + bool more_operators = true; + while(more_operators) + { bool flag; // temporary for use in switch cases + // + // next op + (--itr).op_info(op, arg, i_var); + + // rest of information depends on the case + switch( op ) + { + case AbsOp: + CPPAD_ASSERT_NARG_NRES(op, 1, 1); + sparse::rev_jac_unary_op( + i_var, size_t(arg[0]), var_sparsity + ); + break; + // ------------------------------------------------- + + case AddvvOp: + CPPAD_ASSERT_NARG_NRES(op, 2, 1); + sparse::rev_jac_binary_op( + i_var, arg, var_sparsity + ); + break; + // ------------------------------------------------- + + case AddpvOp: + CPPAD_ASSERT_NARG_NRES(op, 2, 1); + sparse::rev_jac_unary_op( + i_var, size_t(arg[1]), var_sparsity + ); + break; + // ------------------------------------------------- + + case AcosOp: + // sqrt(1 - x * x), acos(x) + CPPAD_ASSERT_NARG_NRES(op, 1, 2); + sparse::rev_jac_unary_op( + i_var, size_t(arg[0]), var_sparsity + ); + break; + // ------------------------------------------------- + + case AcoshOp: + // sqrt(x * x - 1), acosh(x) + CPPAD_ASSERT_NARG_NRES(op, 1, 2); + sparse::rev_jac_unary_op( + i_var, size_t(arg[0]), var_sparsity + ); + break; + // ------------------------------------------------- + + case AsinOp: + // sqrt(1 - x * x), asin(x) + CPPAD_ASSERT_NARG_NRES(op, 1, 2); + sparse::rev_jac_unary_op( + i_var, size_t(arg[0]), var_sparsity + ); + break; + // ------------------------------------------------- + + case AsinhOp: + // sqrt(1 + x * x), asinh(x) + CPPAD_ASSERT_NARG_NRES(op, 1, 2); + sparse::rev_jac_unary_op( + i_var, size_t(arg[0]), var_sparsity + ); + break; + // ------------------------------------------------- + + case AtanOp: + // 1 + x * x, atan(x) + CPPAD_ASSERT_NARG_NRES(op, 1, 2); + sparse::rev_jac_unary_op( + i_var, size_t(arg[0]), var_sparsity + ); + break; + // ------------------------------------------------- + + case AtanhOp: + // 1 - x * x, atanh(x) + CPPAD_ASSERT_NARG_NRES(op, 1, 2); + sparse::rev_jac_unary_op( + i_var, size_t(arg[0]), var_sparsity + ); + break; + // ------------------------------------------------- + + case BeginOp: + CPPAD_ASSERT_NARG_NRES(op, 1, 1); + more_operators = false; + break; + // ------------------------------------------------- + + case CSkipOp: + itr.correct_after_decrement(arg); + break; + // ------------------------------------------------- + + case CSumOp: + itr.correct_after_decrement(arg); + reverse_sparse_jacobian_csum_op( + i_var, arg, var_sparsity + ); + break; + // ------------------------------------------------- + + case CExpOp: + reverse_sparse_jacobian_cond_op( + dependency, i_var, arg, num_par, var_sparsity + ); + break; + // --------------------------------------------------- + + case CosOp: + // sin(x), cos(x) + CPPAD_ASSERT_NARG_NRES(op, 1, 2); + sparse::rev_jac_unary_op( + i_var, size_t(arg[0]), var_sparsity + ); + break; + // --------------------------------------------------- + + case CoshOp: + // sinh(x), cosh(x) + CPPAD_ASSERT_NARG_NRES(op, 1, 2); + sparse::rev_jac_unary_op( + i_var, size_t(arg[0]), var_sparsity + ); + break; + // ------------------------------------------------- + + case DisOp: + CPPAD_ASSERT_NARG_NRES(op, 2, 1); + // derivative is identically zero but dependency is not + if( dependency ) sparse::rev_jac_unary_op( + i_var, size_t(arg[1]), var_sparsity + ); + break; + // ------------------------------------------------- + + case DivvvOp: + CPPAD_ASSERT_NARG_NRES(op, 2, 1); + sparse::rev_jac_binary_op( + i_var, arg, var_sparsity + ); + break; + // ------------------------------------------------- + + case DivpvOp: + CPPAD_ASSERT_NARG_NRES(op, 2, 1); + sparse::rev_jac_unary_op( + i_var, size_t(arg[1]), var_sparsity + ); + break; + // ------------------------------------------------- + + case DivvpOp: + CPPAD_ASSERT_NARG_NRES(op, 2, 1); + sparse::rev_jac_unary_op( + i_var, size_t(arg[0]), var_sparsity + ); + break; + // ------------------------------------------------- + + case ErfOp: + case ErfcOp: + // arg[1] is always the parameter 0 + // arg[0] is always the parameter 2 / sqrt(pi) + CPPAD_ASSERT_NARG_NRES(op, 3, 5); + sparse::rev_jac_unary_op( + i_var, size_t(arg[0]), var_sparsity + ); + break; + // ------------------------------------------------- + + case ExpOp: + CPPAD_ASSERT_NARG_NRES(op, 1, 1); + sparse::rev_jac_unary_op( + i_var, size_t(arg[0]), var_sparsity + ); + break; + // ------------------------------------------------- + + case Expm1Op: + CPPAD_ASSERT_NARG_NRES(op, 1, 1); + sparse::rev_jac_unary_op( + i_var, size_t(arg[0]), var_sparsity + ); + break; + // ------------------------------------------------- + + case InvOp: + CPPAD_ASSERT_NARG_NRES(op, 0, 1); + break; + // ------------------------------------------------- + + case LdpOp: + reverse_sparse_jacobian_load_op( + dependency, + op, + i_var, + arg, + num_vecad_ind, + vecad_ind.data(), + var_sparsity, + vecad_sparsity + ); + break; + // ------------------------------------------------- + + case LdvOp: + reverse_sparse_jacobian_load_op( + dependency, + op, + i_var, + arg, + num_vecad_ind, + vecad_ind.data(), + var_sparsity, + vecad_sparsity + ); + break; + // ------------------------------------------------- + + case EqppOp: + case EqpvOp: + case EqvvOp: + case LtppOp: + case LtpvOp: + case LtvpOp: + case LtvvOp: + case LeppOp: + case LepvOp: + case LevpOp: + case LevvOp: + case NeppOp: + case NepvOp: + case NevvOp: + CPPAD_ASSERT_NARG_NRES(op, 2, 0); + break; + // ------------------------------------------------- + + case LogOp: + CPPAD_ASSERT_NARG_NRES(op, 1, 1); + sparse::rev_jac_unary_op( + i_var, size_t(arg[0]), var_sparsity + ); + break; + // ------------------------------------------------- + + case Log1pOp: + CPPAD_ASSERT_NARG_NRES(op, 1, 1); + sparse::rev_jac_unary_op( + i_var, size_t(arg[0]), var_sparsity + ); + break; + // ------------------------------------------------- + + case MulpvOp: + CPPAD_ASSERT_NARG_NRES(op, 2, 1); + sparse::rev_jac_unary_op( + i_var, size_t(arg[1]), var_sparsity + ); + break; + // ------------------------------------------------- + + case MulvvOp: + CPPAD_ASSERT_NARG_NRES(op, 2, 1); + sparse::rev_jac_binary_op( + i_var, arg, var_sparsity + ); + break; + // ------------------------------------------------- + + case ParOp: + CPPAD_ASSERT_NARG_NRES(op, 1, 1); + + break; + // ------------------------------------------------- + + case PowvpOp: + sparse::rev_jac_unary_op( + i_var, size_t(arg[0]), var_sparsity + ); + break; + // ------------------------------------------------- + + case PowpvOp: + CPPAD_ASSERT_NARG_NRES(op, 2, 3); + sparse::rev_jac_unary_op( + i_var, size_t(arg[1]), var_sparsity + ); + break; + // ------------------------------------------------- + + case PowvvOp: + CPPAD_ASSERT_NARG_NRES(op, 2, 3); + sparse::rev_jac_binary_op( + i_var, arg, var_sparsity + ); + break; + // ------------------------------------------------- + + case PriOp: + CPPAD_ASSERT_NARG_NRES(op, 5, 0); + break; + // ------------------------------------------------- + + case SignOp: + CPPAD_ASSERT_NARG_NRES(op, 1, 1); + // derivative is identically zero but dependency is not + if( dependency ) sparse::rev_jac_unary_op( + i_var, size_t(arg[0]), var_sparsity + ); + break; + // ------------------------------------------------- + + case SinOp: + // cos(x), sin(x) + CPPAD_ASSERT_NARG_NRES(op, 1, 2); + sparse::rev_jac_unary_op( + i_var, size_t(arg[0]), var_sparsity + ); + break; + // ------------------------------------------------- + + case SinhOp: + // cosh(x), sinh(x) + CPPAD_ASSERT_NARG_NRES(op, 1, 2); + sparse::rev_jac_unary_op( + i_var, size_t(arg[0]), var_sparsity + ); + break; + // ------------------------------------------------- + + case SqrtOp: + CPPAD_ASSERT_NARG_NRES(op, 1, 1); + sparse::rev_jac_unary_op( + i_var, size_t(arg[0]), var_sparsity + ); + break; + // ------------------------------------------------- + + case StppOp: + // does not affect sparsity or dependency when both are parameters + CPPAD_ASSERT_NARG_NRES(op, 3, 0); + break; + // ------------------------------------------------- + + case StpvOp: + reverse_sparse_jacobian_store_op( + dependency, + op, + arg, + num_vecad_ind, + vecad_ind.data(), + var_sparsity, + vecad_sparsity + ); + break; + // ------------------------------------------------- + + case StvpOp: + CPPAD_ASSERT_NARG_NRES(op, 3, 0); + // storing a parameter only affects dependency + reverse_sparse_jacobian_store_op( + dependency, + op, + arg, + num_vecad_ind, + vecad_ind.data(), + var_sparsity, + vecad_sparsity + ); + break; + // ------------------------------------------------- + + case StvvOp: + reverse_sparse_jacobian_store_op( + dependency, + op, + arg, + num_vecad_ind, + vecad_ind.data(), + var_sparsity, + vecad_sparsity + ); + break; + // ------------------------------------------------- + + case SubvvOp: + CPPAD_ASSERT_NARG_NRES(op, 2, 1); + sparse::rev_jac_binary_op( + i_var, arg, var_sparsity + ); + break; + // ------------------------------------------------- + + case SubpvOp: + CPPAD_ASSERT_NARG_NRES(op, 2, 1); + sparse::rev_jac_unary_op( + i_var, size_t(arg[1]), var_sparsity + ); + break; + // ------------------------------------------------- + + case SubvpOp: + CPPAD_ASSERT_NARG_NRES(op, 2, 1); + sparse::rev_jac_unary_op( + i_var, size_t(arg[0]), var_sparsity + ); + break; + // ------------------------------------------------- + + case TanOp: + // tan(x)^2, tan(x) + CPPAD_ASSERT_NARG_NRES(op, 1, 2); + sparse::rev_jac_unary_op( + i_var, size_t(arg[0]), var_sparsity + ); + break; + // ------------------------------------------------- + + case TanhOp: + // tanh(x)^2, tanh(x) + CPPAD_ASSERT_NARG_NRES(op, 1, 2); + sparse::rev_jac_unary_op( + i_var, size_t(arg[0]), var_sparsity + ); + break; + // ------------------------------------------------- + + case AFunOp: + // start or end an atomic function call + CPPAD_ASSERT_UNKNOWN( + atom_state == start_atom || atom_state == end_atom + ); + flag = atom_state == end_atom; + play::atom_op_info( + op, arg, atom_index, atom_old, atom_m, atom_n + ); + if( flag ) + { atom_state = ret_atom; + atom_i = atom_m; + atom_j = atom_n; + // + atom_x.resize( atom_n ); + type_x.resize( atom_n ); + atom_ix.resize( atom_n ); + atom_iy.resize( atom_m ); + } + else + { CPPAD_ASSERT_UNKNOWN( atom_i == 0 ); + CPPAD_ASSERT_UNKNOWN( atom_j == 0 ); + atom_state = end_atom; + // + call_atomic_rev_jac_sparsity( + atom_index, + atom_old, + dependency, + atom_x, + type_x, + atom_ix, + atom_iy, + var_sparsity + ); + } + break; + + case FunapOp: + // parameter argument in an atomic operation sequence + CPPAD_ASSERT_UNKNOWN( NumArg(op) == 1 ); + CPPAD_ASSERT_UNKNOWN( atom_state == arg_atom ); + CPPAD_ASSERT_UNKNOWN( atom_i == 0 ); + CPPAD_ASSERT_UNKNOWN( atom_j <= atom_n ); + CPPAD_ASSERT_UNKNOWN( size_t( arg[0] ) < num_par ); + // + --atom_j; + // argument parameter value + atom_x[atom_j] = parameter[arg[0]]; + // argument type + if( dyn_par_is[arg[0]] ) + type_x[atom_j] = dynamic_enum; + else + type_x[atom_j] = constant_enum; + // special variable index used for parameters + atom_ix[atom_j] = 0; + // + if( atom_j == 0 ) + atom_state = start_atom; + break; + + case FunavOp: + // variable argument in an atomic operation sequence + CPPAD_ASSERT_UNKNOWN( NumArg(op) == 1 ); + CPPAD_ASSERT_UNKNOWN( atom_state == arg_atom ); + CPPAD_ASSERT_UNKNOWN( atom_i == 0 ); + CPPAD_ASSERT_UNKNOWN( atom_j <= atom_n ); + // + --atom_j; + // argument variables not available during sparsity calculations + atom_x[atom_j] = CppAD::numeric_limits::quiet_NaN(); + type_x[atom_j] = variable_enum; + // variable index for this argument + atom_ix[atom_j] = size_t(arg[0]); + // + if( atom_j == 0 ) + atom_state = start_atom; + break; + + case FunrpOp: + // parameter result for a atomic function + CPPAD_ASSERT_NARG_NRES(op, 1, 0); + CPPAD_ASSERT_UNKNOWN( atom_state == ret_atom ); + CPPAD_ASSERT_UNKNOWN( atom_i <= atom_m ); + CPPAD_ASSERT_UNKNOWN( atom_j == atom_n ); + CPPAD_ASSERT_UNKNOWN( size_t( arg[0] ) < num_par ); + // + --atom_i; + atom_iy[atom_i] = 0; // special variable used for parameters + // + if( atom_i == 0 ) + atom_state = arg_atom; + break; + + case FunrvOp: + // variable result for a atomic function + CPPAD_ASSERT_NARG_NRES(op, 0, 1); + CPPAD_ASSERT_UNKNOWN( atom_state == ret_atom ); + CPPAD_ASSERT_UNKNOWN( atom_i <= atom_m ); + CPPAD_ASSERT_UNKNOWN( atom_j == atom_n ); + // + --atom_i; + atom_iy[atom_i] = i_var; // variable for this result + // + if( atom_i == 0 ) + atom_state = arg_atom; + break; + // ------------------------------------------------- + + case ZmulpvOp: + CPPAD_ASSERT_NARG_NRES(op, 2, 1); + sparse::rev_jac_unary_op( + i_var, size_t(arg[1]), var_sparsity + ); + break; + // ------------------------------------------------- + + case ZmulvpOp: + CPPAD_ASSERT_NARG_NRES(op, 2, 1); + sparse::rev_jac_unary_op( + i_var, size_t(arg[0]), var_sparsity + ); + break; + // ------------------------------------------------- + + case ZmulvvOp: + CPPAD_ASSERT_NARG_NRES(op, 2, 1); + sparse::rev_jac_binary_op( + i_var, arg, var_sparsity + ); + break; + // ------------------------------------------------- + + default: + CPPAD_ASSERT_UNKNOWN(0); + } +# if CPPAD_REV_JAC_TRACE + for(j = 0; j < limit; j++) + z_value[j] = false; + typename Vector_set::const_iterator itr(var_sparsity, i_var); + j = *itr; + while( j < limit ) + { z_value[j] = true; + j = *(++itr); + } + printOp( + std::cout, + play, + itr.op_index(), + i_var, + op, + arg + ); + // Note that sparsity for FunrvOp are computed before call to + // atomic function so no need to delay printing (as in forward mode) + if( NumRes(op) > 0 && op != BeginOp ) printOpResult( + std::cout, + 0, + (CppAD::vectorBool *) nullptr, + 1, + &z_value + ); + std::cout << std::endl; + } + std::cout << std::endl; +# else + } +# endif + // values corresponding to BeginOp + CPPAD_ASSERT_UNKNOWN( itr.op_index() == 0 ); + CPPAD_ASSERT_UNKNOWN( i_var == 0 ); + + return; +} + +// preprocessor symbols that are local to this file +# undef CPPAD_REV_JAC_TRACE + +} } } // END_CPPAD_LOCAL_SWEEP_NAMESPACE + +# endif diff --git a/build-config/cppad/include/cppad/local/sweep/reverse.hpp b/build-config/cppad/include/cppad/local/sweep/reverse.hpp new file mode 100644 index 00000000..84957d0a --- /dev/null +++ b/build-config/cppad/include/cppad/local/sweep/reverse.hpp @@ -0,0 +1,809 @@ +# ifndef CPPAD_LOCAL_SWEEP_REVERSE_HPP +# define CPPAD_LOCAL_SWEEP_REVERSE_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + + +# include + +// BEGIN_CPPAD_LOCAL_SWEEP_NAMESPACE +namespace CppAD { namespace local { namespace sweep { +/*! +\file sweep/reverse.hpp +Compute derivatives of arbitrary order Taylor coefficients. +*/ + +/*! +\def CPPAD_REVERSE_TRACE +This value is either zero or one. +Zero is the normal operational value. +If it is one, a trace of every reverse_sweep computation is printed. +*/ +# define CPPAD_REVERSE_TRACE 0 + +/*! +Compute derivative of arbitrary order forward mode Taylor coefficients. + +\tparam Base +this operation sequence was recorded using AD +and computations by this routine are done using type Base. + +\param d +is the highest order Taylor coefficients that +we are computing the derivative of. + +\param n +is the number of independent variables on the tape. + +\param numvar +is the total number of variables on the tape. +This is also equal to the number of rows in the matrix Taylor; i.e., +play->num_var_rec(). + +\param play +The information stored in play +is a recording of the operations corresponding to the function +\f[ + F : {\bf R}^n \rightarrow {\bf R}^m +\f] +where \f$ n \f$ is the number of independent variables and +\f$ m \f$ is the number of dependent variables. +We define \f$ u^{(k)} \f$ as the value of x_k in the previous call +of the form + + f.Forward(k, x_k) + +We define +\f$ X : {\bf R}^{n \times d} \rightarrow {\bf R}^n \f$ by +\f[ + X(t, u) = u^{(0)} + u^{(1)} t + \cdots + u^{(d)} t^d +\f] +We define +\f$ Y : {\bf R}^{n \times d} \rightarrow {\bf R}^m \f$ by +\f[ + Y(t, u) = F[ X(t, u) ] +\f] +We define the function +\f$ W : {\bf R}^{n \times d} \rightarrow {\bf R} \f$ by +\f[ +W(u) += +\sum_{k=0}^{d} ( w^{(k)} )^{\rm T} + \frac{1}{k !} \frac{\partial^k}{\partial t^k} Y(0, u) +\f] +(The matrix \f$ w \in {\bf R}^m \f$, +is defined below under the heading Partial.) +Note that the scale factor 1 / k converts +the k-th partial derivative to the k-th order Taylor coefficient. +This routine computes the derivative of \f$ W(u) \f$ +with respect to all the Taylor coefficients +\f$ u^{(k)} \f$ for \f$ k = 0 , ... , d \f$. + +\param J +Is the number of columns in the coefficient matrix Taylor. +This must be greater than or equal d + 1. + +\param Taylor +For i = 1 , ... , numvar, and for k = 0 , ... , d, + Taylor [ i * J + k ] +is the k-th order Taylor coefficient corresponding to +variable with index i on the tape. +The value \f$ u \in {\bf R}^{n \times d} \f$, +at which the derivative is computed, +is defined by +\f$ u_j^{(k)} \f$ = Taylor [ j * J + k ] +for j = 1 , ... , n, and for k = 0 , ... , d. + +\param K +Is the number of columns in the partial derivative matrix Partial. +It must be greater than or equal d + 1. + +\param Partial +\b Input: +The last \f$ m \f$ rows of Partial are inputs. +The matrix \f$ w \f$, used to define \f$ W(u) \f$, +is specified by these rows. +For i = 0 , ... , m - 1, +for k = 0 , ... , d, +Partial [ (numvar - m + i ) * K + k ] = w[i,k]. +\n +\n +\b Temporary: +For i = n+1 , ... , numvar - 1 and for k = 0 , ... , d, +the value of Partial [ i * K + k ] is used for temporary work space +and its output value is not defined. +\n +\n +\b Output: +For j = 1 , ... , n and for k = 0 , ... , d, + Partial [ j * K + k ] +is the partial derivative of \f$ W( u ) \f$ with +respect to \f$ u_j^{(k)} \f$. + +\param cskip_op +Is a vector with size play->num_op_rec(). +If cskip_op[i] is true, the operator index i in the recording +does not affect any of the dependent variable (given the value +of the independent variables). +Note that all the operators in an atomic function call are skipped as a block, +so only the last AFunOp fore each call needs to have cskip_op[i] true. + +\param load_op2var +is a vector with size play->num_var_load_rec(). +It contains the variable index corresponding to each load instruction. +In the case where the index is zero, +the instruction corresponds to a parameter (not variable). + +\tparam Iterator +This is either player::const_iteratoror player::const_subgraph_iterator. + +\param play_itr +On input this is either play->end(), for the entire graph, +or play->end(subgraph), for a subgraph. +This routine mode will use --play_itr to iterate over the graph or subgraph. +It is assumes that the iterator starts just past the EndOp and it will +continue until it reaches the BeginOp. +If i_var is a variable index, and the corresponding operator +is not in the subgraph, +then the partials with respect to i_var are not modified and need to be +initialized as zero. Note that this means the partial for the independent +varaibles, that are not in the subgraph are not calculated. +If part of an atomic function call is in the subgraph, +the entire atomic function call must be in the subgraph. + +\param not_used_rec_base +Specifies RecBase for this call. + +\par Assumptions +The first operator on the tape is a BeginOp, +and the next n operators are InvOp operations for the +corresponding independent variables; see play->check_inv_op(n_ind). +*/ +template +void reverse( + size_t d, + size_t n, + size_t numvar, + const local::player* play, + size_t J, + const Base* Taylor, + size_t K, + Base* Partial, + bool* cskip_op, + const pod_vector& load_op2var, + Iterator& play_itr, + const RecBase& not_used_rec_base +) +{ + // check numvar argument + CPPAD_ASSERT_UNKNOWN( play->num_var_rec() == numvar ); + CPPAD_ASSERT_UNKNOWN( numvar > 0 ); + + // length of the parameter vector (used by CppAD assert macros) + const size_t num_par = play->num_par_rec(); + + // pointer to the beginning of the parameter vector + CPPAD_ASSERT_UNKNOWN( num_par > 0 ) + const Base* parameter = play->GetPar(); + + // work space used by AFunOp. + const size_t atom_k = d; // highest order we are differentiating + const size_t atom_k1 = d+1; // number orders for this calculation + vector atom_par_x; // argument parameter values + vector atom_type_x; // argument type + vector atom_ix; // variable indices for argument vector + vector atom_tx; // argument vector Taylor coefficients + vector atom_ty; // result vector Taylor coefficients + vector atom_px; // partials w.r.t argument vector + vector atom_py; // partials w.r.t. result vector + // + // information defined by atomic forward + size_t atom_index=0, atom_old=0, atom_m=0, atom_n=0, atom_i=0, atom_j=0; + enum_atom_state atom_state = end_atom; // proper initialization + + // temporary indices + size_t j, ell; + + // Initialize +# if CPPAD_REVERSE_TRACE + std::cout << std::endl; +# endif + OpCode op; + const Addr* arg; + size_t i_var; + play_itr.op_info(op, arg, i_var); + CPPAD_ASSERT_UNKNOWN( op == EndOp ); + while(op != BeginOp ) + { bool flag; // temporary for use in switch cases + // + // next op + (--play_itr).op_info(op, arg, i_var); + + // check if we are skipping this operation + size_t i_op = play_itr.op_index(); + while( cskip_op[i_op] ) + { switch(op) + { + case AFunOp: + { // get information for this atomic function call + CPPAD_ASSERT_UNKNOWN( atom_state == end_atom ); + play::atom_op_info( + op, arg, atom_index, atom_old, atom_m, atom_n + ); + // + // skip to the first AFunOp + for(size_t i = 0; i < atom_m + atom_n + 1; ++i) + --play_itr; + play_itr.op_info(op, arg, i_var); + CPPAD_ASSERT_UNKNOWN( op == AFunOp ); + } + break; + + default: + break; + } + (--play_itr).op_info(op, arg, i_var); + i_op = play_itr.op_index(); + } +# if CPPAD_REVERSE_TRACE + size_t i_tmp = i_var; + const Base* Z_tmp = Taylor + i_var * J; + const Base* pZ_tmp = Partial + i_var * K; + printOp( + std::cout, + play, + i_op, + i_tmp, + op, + arg + ); + if( NumRes(op) > 0 && op != BeginOp ) printOpResult( + std::cout, + d + 1, + Z_tmp, + d + 1, + pZ_tmp + ); + std::cout << std::endl; +# endif + switch( op ) + { + case AbsOp: + reverse_abs_op( + d, i_var, size_t(arg[0]), J, Taylor, K, Partial + ); + break; + // -------------------------------------------------- + + case AcosOp: + // sqrt(1 - x * x), acos(x) + CPPAD_ASSERT_UNKNOWN( i_var < numvar ); + reverse_acos_op( + d, i_var, size_t(arg[0]), J, Taylor, K, Partial + ); + break; + // -------------------------------------------------- + + case AcoshOp: + // sqrt(x * x - 1), acosh(x) + CPPAD_ASSERT_UNKNOWN( i_var < numvar ); + reverse_acosh_op( + d, i_var, size_t(arg[0]), J, Taylor, K, Partial + ); + break; + // -------------------------------------------------- + + case AddvvOp: + reverse_addvv_op( + d, i_var, arg, parameter, J, Taylor, K, Partial + ); + break; + // -------------------------------------------------- + + case AddpvOp: + CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) < num_par ); + reverse_addpv_op( + d, i_var, arg, parameter, J, Taylor, K, Partial + ); + break; + // -------------------------------------------------- + + case AsinOp: + // sqrt(1 - x * x), asin(x) + CPPAD_ASSERT_UNKNOWN( i_var < numvar ); + reverse_asin_op( + d, i_var, size_t(arg[0]), J, Taylor, K, Partial + ); + break; + // -------------------------------------------------- + + case AsinhOp: + // sqrt(1 + x * x), asinh(x) + CPPAD_ASSERT_UNKNOWN( i_var < numvar ); + reverse_asinh_op( + d, i_var, size_t(arg[0]), J, Taylor, K, Partial + ); + break; + // -------------------------------------------------- + + case AtanOp: + // 1 + x * x, atan(x) + CPPAD_ASSERT_UNKNOWN( i_var < numvar ); + reverse_atan_op( + d, i_var, size_t(arg[0]), J, Taylor, K, Partial + ); + break; + // ------------------------------------------------- + + case AtanhOp: + // 1 - x * x, atanh(x) + CPPAD_ASSERT_UNKNOWN( i_var < numvar ); + reverse_atanh_op( + d, i_var, size_t(arg[0]), J, Taylor, K, Partial + ); + break; + // ------------------------------------------------- + + case BeginOp: + CPPAD_ASSERT_NARG_NRES(op, 1, 1); + CPPAD_ASSERT_UNKNOWN( i_op == 0 ); + break; + // -------------------------------------------------- + + case CSkipOp: + // CSkipOp has a zero order forward action. + play_itr.correct_after_decrement(arg); + break; + // ------------------------------------------------- + + case CSumOp: + play_itr.correct_after_decrement(arg); + reverse_csum_op( + d, i_var, arg, K, Partial + ); + // end of a cumulative summation + break; + // ------------------------------------------------- + + case CExpOp: + reverse_cond_op( + d, + i_var, + arg, + num_par, + parameter, + J, + Taylor, + K, + Partial + ); + break; + // -------------------------------------------------- + + case CosOp: + CPPAD_ASSERT_UNKNOWN( i_var < numvar ); + reverse_cos_op( + d, i_var, size_t(arg[0]), J, Taylor, K, Partial + ); + break; + // -------------------------------------------------- + + case CoshOp: + CPPAD_ASSERT_UNKNOWN( i_var < numvar ); + reverse_cosh_op( + d, i_var, size_t(arg[0]), J, Taylor, K, Partial + ); + break; + // -------------------------------------------------- + + case DisOp: + // Derivative of discrete operation is zero so no + // contribution passes through this operation. + break; + // -------------------------------------------------- + + case DivvvOp: + reverse_divvv_op( + d, i_var, arg, parameter, J, Taylor, K, Partial + ); + break; + // -------------------------------------------------- + + case DivpvOp: + CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) < num_par ); + reverse_divpv_op( + d, i_var, arg, parameter, J, Taylor, K, Partial + ); + break; + // -------------------------------------------------- + + case DivvpOp: + CPPAD_ASSERT_UNKNOWN( size_t(arg[1]) < num_par ); + reverse_divvp_op( + d, i_var, arg, parameter, J, Taylor, K, Partial + ); + break; + // -------------------------------------------------- + case EndOp: + CPPAD_ASSERT_UNKNOWN( + i_op == play->num_op_rec() - 1 + ); + break; + + // -------------------------------------------------- + + case ErfOp: + case ErfcOp: + reverse_erf_op( + op, d, i_var, arg, parameter, J, Taylor, K, Partial + ); + break; + // -------------------------------------------------- + + case ExpOp: + reverse_exp_op( + d, i_var, size_t(arg[0]), J, Taylor, K, Partial + ); + break; + // -------------------------------------------------- + + case Expm1Op: + reverse_expm1_op( + d, i_var, size_t(arg[0]), J, Taylor, K, Partial + ); + break; + // -------------------------------------------------- + + case InvOp: + break; + // -------------------------------------------------- + + case LdpOp: + reverse_load_op( + op, d, i_var, arg, J, Taylor, K, Partial, load_op2var.data() + ); + break; + // ------------------------------------------------- + + case LdvOp: + reverse_load_op( + op, d, i_var, arg, J, Taylor, K, Partial, load_op2var.data() + ); + break; + // -------------------------------------------------- + + case EqppOp: + case EqpvOp: + case EqvvOp: + case LtppOp: + case LtpvOp: + case LtvpOp: + case LtvvOp: + case LeppOp: + case LepvOp: + case LevpOp: + case LevvOp: + case NeppOp: + case NepvOp: + case NevvOp: + break; + // ------------------------------------------------- + + case LogOp: + reverse_log_op( + d, i_var, size_t(arg[0]), J, Taylor, K, Partial + ); + break; + // -------------------------------------------------- + + case Log1pOp: + reverse_log1p_op( + d, i_var, size_t(arg[0]), J, Taylor, K, Partial + ); + break; + // -------------------------------------------------- + + case MulpvOp: + CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) < num_par ); + reverse_mulpv_op( + d, i_var, arg, parameter, J, Taylor, K, Partial + ); + break; + // -------------------------------------------------- + + case MulvvOp: + reverse_mulvv_op( + d, i_var, arg, parameter, J, Taylor, K, Partial + ); + break; + // -------------------------------------------------- + + case ParOp: + break; + // -------------------------------------------------- + + case PowvpOp: + CPPAD_ASSERT_UNKNOWN( size_t(arg[1]) < num_par ); + reverse_powvp_op( + d, i_var, arg, parameter, J, Taylor, K, Partial + ); + break; + // ------------------------------------------------- + + case PowpvOp: + CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) < num_par ); + reverse_powpv_op( + d, i_var, arg, parameter, J, Taylor, K, Partial + ); + break; + // ------------------------------------------------- + + case PowvvOp: + reverse_powvv_op( + d, i_var, arg, parameter, J, Taylor, K, Partial + ); + break; + // -------------------------------------------------- + + case PriOp: + // no result so nothing to do + break; + // -------------------------------------------------- + + case SignOp: + CPPAD_ASSERT_UNKNOWN( i_var < numvar ); + reverse_sign_op( + d, i_var, size_t(arg[0]), J, Taylor, K, Partial + ); + break; + // ------------------------------------------------- + + case SinOp: + CPPAD_ASSERT_UNKNOWN( i_var < numvar ); + reverse_sin_op( + d, i_var, size_t(arg[0]), J, Taylor, K, Partial + ); + break; + // ------------------------------------------------- + + case SinhOp: + CPPAD_ASSERT_UNKNOWN( i_var < numvar ); + reverse_sinh_op( + d, i_var, size_t(arg[0]), J, Taylor, K, Partial + ); + break; + // -------------------------------------------------- + + case SqrtOp: + reverse_sqrt_op( + d, i_var, size_t(arg[0]), J, Taylor, K, Partial + ); + break; + // -------------------------------------------------- + + case StppOp: + break; + // -------------------------------------------------- + + case StpvOp: + break; + // ------------------------------------------------- + + case StvpOp: + break; + // ------------------------------------------------- + + case StvvOp: + break; + // -------------------------------------------------- + + case SubvvOp: + reverse_subvv_op( + d, i_var, arg, parameter, J, Taylor, K, Partial + ); + break; + // -------------------------------------------------- + + case SubpvOp: + CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) < num_par ); + reverse_subpv_op( + d, i_var, arg, parameter, J, Taylor, K, Partial + ); + break; + // -------------------------------------------------- + + case SubvpOp: + CPPAD_ASSERT_UNKNOWN( size_t(arg[1]) < num_par ); + reverse_subvp_op( + d, i_var, arg, parameter, J, Taylor, K, Partial + ); + break; + // ------------------------------------------------- + + case TanOp: + CPPAD_ASSERT_UNKNOWN( i_var < numvar ); + reverse_tan_op( + d, i_var, size_t(arg[0]), J, Taylor, K, Partial + ); + break; + // ------------------------------------------------- + + case TanhOp: + CPPAD_ASSERT_UNKNOWN( i_var < numvar ); + reverse_tanh_op( + d, i_var, size_t(arg[0]), J, Taylor, K, Partial + ); + break; + // -------------------------------------------------- + + case AFunOp: + // start or end an atomic function call + flag = atom_state == end_atom; + play::atom_op_info( + op, arg, atom_index, atom_old, atom_m, atom_n + ); + if( flag ) + { atom_state = ret_atom; + atom_i = atom_m; + atom_j = atom_n; + // + atom_ix.resize(atom_n); + atom_par_x.resize(atom_n); + atom_type_x.resize(atom_n); + atom_tx.resize(atom_n * atom_k1); + atom_px.resize(atom_n * atom_k1); + atom_ty.resize(atom_m * atom_k1); + atom_py.resize(atom_m * atom_k1); + } + else + { CPPAD_ASSERT_UNKNOWN( atom_i == 0 ); + CPPAD_ASSERT_UNKNOWN( atom_j == 0 ); + atom_state = end_atom; + // + // call atomic function for this operation + call_atomic_reverse( + atom_par_x, + atom_type_x, + atom_k, + atom_index, + atom_old, + atom_tx, + atom_ty, + atom_px, + atom_py + ); + for(j = 0; j < atom_n; j++) if( atom_ix[j] > 0 ) + { for(ell = 0; ell < atom_k1; ell++) + Partial[atom_ix[j] * K + ell] += + atom_px[j * atom_k1 + ell]; + } + } + break; + + case FunapOp: + // parameter argument in an atomic operation sequence + CPPAD_ASSERT_UNKNOWN( NumArg(op) == 1 ); + CPPAD_ASSERT_UNKNOWN( atom_state == arg_atom ); + CPPAD_ASSERT_UNKNOWN( atom_i == 0 ); + CPPAD_ASSERT_UNKNOWN( atom_j <= atom_n ); + CPPAD_ASSERT_UNKNOWN( size_t( arg[0] ) < num_par ); + // + --atom_j; + atom_ix[atom_j] = 0; + if( play->dyn_par_is()[ arg[0] ] ) + atom_type_x[atom_j] = dynamic_enum; + else + atom_type_x[atom_j] = constant_enum; + atom_par_x[atom_j] = parameter[ arg[0] ]; + atom_tx[atom_j * atom_k1 + 0] = parameter[ arg[0] ]; + for(ell = 1; ell < atom_k1; ell++) + atom_tx[atom_j * atom_k1 + ell] = Base(0.); + // + if( atom_j == 0 ) + atom_state = start_atom; + break; + + case FunavOp: + // variable argument in an atomic operation sequence + CPPAD_ASSERT_UNKNOWN( NumArg(op) == 1 ); + CPPAD_ASSERT_UNKNOWN( atom_state == arg_atom ); + CPPAD_ASSERT_UNKNOWN( atom_i == 0 ); + CPPAD_ASSERT_UNKNOWN( atom_j <= atom_n ); + // + --atom_j; + atom_ix[atom_j] = size_t( arg[0] ); + atom_type_x[atom_j] = variable_enum; + atom_par_x[atom_j] = CppAD::numeric_limits::quiet_NaN(); + for(ell = 0; ell < atom_k1; ell++) + atom_tx[atom_j*atom_k1 + ell] = + Taylor[ size_t(arg[0]) * J + ell]; + // + if( atom_j == 0 ) + atom_state = start_atom; + break; + + case FunrpOp: + // parameter result for a atomic function + CPPAD_ASSERT_NARG_NRES(op, 1, 0); + CPPAD_ASSERT_UNKNOWN( atom_state == ret_atom ); + CPPAD_ASSERT_UNKNOWN( atom_i <= atom_m ); + CPPAD_ASSERT_UNKNOWN( atom_j == atom_n ); + CPPAD_ASSERT_UNKNOWN( size_t( arg[0] ) < num_par ); + // + --atom_i; + for(ell = 0; ell < atom_k1; ell++) + { atom_py[atom_i * atom_k1 + ell] = Base(0.); + atom_ty[atom_i * atom_k1 + ell] = Base(0.); + } + atom_ty[atom_i * atom_k1 + 0] = parameter[ arg[0] ]; + // + if( atom_i == 0 ) + atom_state = arg_atom; + break; + + case FunrvOp: + // variable result for a atomic function + CPPAD_ASSERT_NARG_NRES(op, 0, 1); + CPPAD_ASSERT_UNKNOWN( atom_state == ret_atom ); + CPPAD_ASSERT_UNKNOWN( atom_i <= atom_m ); + CPPAD_ASSERT_UNKNOWN( atom_j == atom_n ); + // + --atom_i; + for(ell = 0; ell < atom_k1; ell++) + { atom_py[atom_i * atom_k1 + ell] = + Partial[i_var * K + ell]; + atom_ty[atom_i * atom_k1 + ell] = + Taylor[i_var * J + ell]; + } + if( atom_i == 0 ) + atom_state = arg_atom; + break; + // ------------------------------------------------------------ + + case ZmulpvOp: + CPPAD_ASSERT_UNKNOWN( size_t(arg[0]) < num_par ); + reverse_zmulpv_op( + d, i_var, arg, parameter, J, Taylor, K, Partial + ); + break; + // -------------------------------------------------- + + case ZmulvpOp: + CPPAD_ASSERT_UNKNOWN( size_t(arg[1]) < num_par ); + reverse_zmulvp_op( + d, i_var, arg, parameter, J, Taylor, K, Partial + ); + break; + // -------------------------------------------------- + + case ZmulvvOp: + reverse_zmulvv_op( + d, i_var, arg, parameter, J, Taylor, K, Partial + ); + break; + // -------------------------------------------------- + + default: + CPPAD_ASSERT_UNKNOWN(false); + } + } +# if CPPAD_REVERSE_TRACE + std::cout << std::endl; +# endif +} + +} } } // END_CPPAD_LOCAL_SWEEP_NAMESPACE + +// preprocessor symbols that are local to this file +# undef CPPAD_REVERSE_TRACE + +# endif diff --git a/build-config/cppad/include/cppad/local/tan_op.hpp b/build-config/cppad/include/cppad/local/tan_op.hpp new file mode 100644 index 00000000..fba7dc83 --- /dev/null +++ b/build-config/cppad/include/cppad/local/tan_op.hpp @@ -0,0 +1,231 @@ +# ifndef CPPAD_LOCAL_TAN_OP_HPP +# define CPPAD_LOCAL_TAN_OP_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-17 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + + +namespace CppAD { namespace local { // BEGIN_CPPAD_LOCAL_NAMESPACE +/*! +\file tan_op.hpp +Forward and reverse mode calculations for z = tan(x). +*/ + + +/*! +Compute forward mode Taylor coefficient for result of op = TanOp. + +The C++ source code corresponding to this operation is +\verbatim + z = tan(x) +\endverbatim +The auxillary result is +\verbatim + y = tan(x)^2 +\endverbatim +The value of y, and its derivatives, are computed along with the value +and derivatives of z. + +\copydetails CppAD::local::forward_unary2_op +*/ +template +void forward_tan_op( + size_t p , + size_t q , + size_t i_z , + size_t i_x , + size_t cap_order , + Base* taylor ) +{ + // check assumptions + CPPAD_ASSERT_UNKNOWN( NumArg(TanOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( NumRes(TanOp) == 2 ); + CPPAD_ASSERT_UNKNOWN( q < cap_order ); + CPPAD_ASSERT_UNKNOWN( p <= q ); + + // Taylor coefficients corresponding to argument and result + Base* x = taylor + i_x * cap_order; + Base* z = taylor + i_z * cap_order; + Base* y = z - cap_order; + + size_t k; + if( p == 0 ) + { z[0] = tan( x[0] ); + y[0] = z[0] * z[0]; + p++; + } + for(size_t j = p; j <= q; j++) + { Base base_j = static_cast(double(j)); + + z[j] = x[j]; + for(k = 1; k <= j; k++) + z[j] += Base(double(k)) * x[k] * y[j-k] / base_j; + + y[j] = z[0] * z[j]; + for(k = 1; k <= j; k++) + y[j] += z[k] * z[j-k]; + } +} + +/*! +Multiple directions forward mode Taylor coefficient for op = TanOp. + +The C++ source code corresponding to this operation is +\verbatim + z = tan(x) +\endverbatim +The auxillary result is +\verbatim + y = tan(x)^2 +\endverbatim +The value of y, and its derivatives, are computed along with the value +and derivatives of z. + +\copydetails CppAD::local::forward_unary2_op_dir +*/ +template +void forward_tan_op_dir( + size_t q , + size_t r , + size_t i_z , + size_t i_x , + size_t cap_order , + Base* taylor ) +{ + // check assumptions + CPPAD_ASSERT_UNKNOWN( NumArg(TanOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( NumRes(TanOp) == 2 ); + CPPAD_ASSERT_UNKNOWN( 0 < q ); + CPPAD_ASSERT_UNKNOWN( q < cap_order ); + + // Taylor coefficients corresponding to argument and result + size_t num_taylor_per_var = (cap_order-1) * r + 1; + Base* x = taylor + i_x * num_taylor_per_var; + Base* z = taylor + i_z * num_taylor_per_var; + Base* y = z - num_taylor_per_var; + + size_t k; + size_t m = (q-1) * r + 1; + for(size_t ell = 0; ell < r; ell++) + { z[m+ell] = Base(double(q)) * ( x[m+ell] + x[m+ell] * y[0]); + for(k = 1; k < q; k++) + z[m+ell] += Base(double(k)) * x[(k-1)*r+1+ell] * y[(q-k-1)*r+1+ell]; + z[m+ell] /= Base(double(q)); + // + y[m+ell] = Base(2.0) * z[m+ell] * z[0]; + for(k = 1; k < q; k++) + y[m+ell] += z[(k-1)*r+1+ell] * z[(q-k-1)*r+1+ell]; + } +} + + +/*! +Compute zero order forward mode Taylor coefficient for result of op = TanOp. + +The C++ source code corresponding to this operation is +\verbatim + z = tan(x) +\endverbatim +The auxillary result is +\verbatim + y = cos(x) +\endverbatim +The value of y is computed along with the value of z. + +\copydetails CppAD::local::forward_unary2_op_0 +*/ +template +void forward_tan_op_0( + size_t i_z , + size_t i_x , + size_t cap_order , + Base* taylor ) +{ + // check assumptions + CPPAD_ASSERT_UNKNOWN( NumArg(TanOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( NumRes(TanOp) == 2 ); + CPPAD_ASSERT_UNKNOWN( 0 < cap_order ); + + // Taylor coefficients corresponding to argument and result + Base* x = taylor + i_x * cap_order; + Base* z = taylor + i_z * cap_order; // called z in documentation + Base* y = z - cap_order; // called y in documentation + + z[0] = tan( x[0] ); + y[0] = z[0] * z[0]; +} + +/*! +Compute reverse mode partial derivatives for result of op = TanOp. + +The C++ source code corresponding to this operation is +\verbatim + z = tan(x) +\endverbatim +The auxillary result is +\verbatim + y = cos(x) +\endverbatim +The value of y is computed along with the value of z. + +\copydetails CppAD::local::reverse_unary2_op +*/ + +template +void reverse_tan_op( + size_t d , + size_t i_z , + size_t i_x , + size_t cap_order , + const Base* taylor , + size_t nc_partial , + Base* partial ) +{ + // check assumptions + CPPAD_ASSERT_UNKNOWN( NumArg(TanOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( NumRes(TanOp) == 2 ); + CPPAD_ASSERT_UNKNOWN( d < cap_order ); + CPPAD_ASSERT_UNKNOWN( d < nc_partial ); + + // Taylor coefficients and partials corresponding to argument + const Base* x = taylor + i_x * cap_order; + Base* px = partial + i_x * nc_partial; + + // Taylor coefficients and partials corresponding to first result + const Base* z = taylor + i_z * cap_order; // called z in doc + Base* pz = partial + i_z * nc_partial; + + // Taylor coefficients and partials corresponding to auxillary result + const Base* y = z - cap_order; // called y in documentation + Base* py = pz - nc_partial; + + + size_t j = d; + size_t k; + Base base_two(2); + while(j) + { + px[j] += pz[j]; + pz[j] /= Base(double(j)); + for(k = 1; k <= j; k++) + { px[k] += azmul(pz[j], y[j-k]) * Base(double(k)); + py[j-k] += azmul(pz[j], x[k]) * Base(double(k)); + } + for(k = 0; k < j; k++) + pz[k] += azmul(py[j-1], z[j-k-1]) * base_two; + + --j; + } + px[0] += azmul(pz[0], Base(1.0) + y[0]); +} + +} } // END_CPPAD_LOCAL_NAMESPACE +# endif diff --git a/build-config/cppad/include/cppad/local/tanh_op.hpp b/build-config/cppad/include/cppad/local/tanh_op.hpp new file mode 100644 index 00000000..a2ade1fa --- /dev/null +++ b/build-config/cppad/include/cppad/local/tanh_op.hpp @@ -0,0 +1,230 @@ +# ifndef CPPAD_LOCAL_TANH_OP_HPP +# define CPPAD_LOCAL_TANH_OP_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-17 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + + +namespace CppAD { namespace local { // BEGIN_CPPAD_LOCAL_NAMESPACE +/*! +\file tanh_op.hpp +Forward and reverse mode calculations for z = tanh(x). +*/ + + +/*! +Compute forward mode Taylor coefficient for result of op = TanOp. + +The C++ source code corresponding to this operation is +\verbatim + z = tanh(x) +\endverbatim +The auxillary result is +\verbatim + y = tanh(x)^2 +\endverbatim +The value of y, and its derivatives, are computed along with the value +and derivatives of z. + +\copydetails CppAD::local::forward_unary2_op +*/ +template +void forward_tanh_op( + size_t p , + size_t q , + size_t i_z , + size_t i_x , + size_t cap_order , + Base* taylor ) +{ + // check assumptions + CPPAD_ASSERT_UNKNOWN( NumArg(TanOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( NumRes(TanOp) == 2 ); + CPPAD_ASSERT_UNKNOWN( q < cap_order ); + CPPAD_ASSERT_UNKNOWN( p <= q ); + + // Taylor coefficients corresponding to argument and result + Base* x = taylor + i_x * cap_order; + Base* z = taylor + i_z * cap_order; + Base* y = z - cap_order; + + size_t k; + if( p == 0 ) + { z[0] = tanh( x[0] ); + y[0] = z[0] * z[0]; + p++; + } + for(size_t j = p; j <= q; j++) + { Base base_j = static_cast(double(j)); + + z[j] = x[j]; + for(k = 1; k <= j; k++) + z[j] -= Base(double(k)) * x[k] * y[j-k] / base_j; + + y[j] = z[0] * z[j]; + for(k = 1; k <= j; k++) + y[j] += z[k] * z[j-k]; + } +} + +/*! +Multiple directions forward mode Taylor coefficient for op = TanOp. + +The C++ source code corresponding to this operation is +\verbatim + z = tanh(x) +\endverbatim +The auxillary result is +\verbatim + y = tanh(x)^2 +\endverbatim +The value of y, and its derivatives, are computed along with the value +and derivatives of z. + +\copydetails CppAD::local::forward_unary2_op_dir +*/ +template +void forward_tanh_op_dir( + size_t q , + size_t r , + size_t i_z , + size_t i_x , + size_t cap_order , + Base* taylor ) +{ + // check assumptions + CPPAD_ASSERT_UNKNOWN( NumArg(TanOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( NumRes(TanOp) == 2 ); + CPPAD_ASSERT_UNKNOWN( 0 < q ); + CPPAD_ASSERT_UNKNOWN( q < cap_order ); + + // Taylor coefficients corresponding to argument and result + size_t num_taylor_per_var = (cap_order-1) * r + 1; + Base* x = taylor + i_x * num_taylor_per_var; + Base* z = taylor + i_z * num_taylor_per_var; + Base* y = z - num_taylor_per_var; + + size_t k; + size_t m = (q-1) * r + 1; + for(size_t ell = 0; ell < r; ell++) + { z[m+ell] = Base(double(q)) * ( x[m+ell] - x[m+ell] * y[0] ); + for(k = 1; k < q; k++) + z[m+ell] -= Base(double(k)) * x[(k-1)*r+1+ell] * y[(q-k-1)*r+1+ell]; + z[m+ell] /= Base(double(q)); + // + y[m+ell] = Base(2.0) * z[m+ell] * z[0]; + for(k = 1; k < q; k++) + y[m+ell] += z[(k-1)*r+1+ell] * z[(q-k-1)*r+1+ell]; + } +} + +/*! +Compute zero order forward mode Taylor coefficient for result of op = TanOp. + +The C++ source code corresponding to this operation is +\verbatim + z = tanh(x) +\endverbatim +The auxillary result is +\verbatim + y = cos(x) +\endverbatim +The value of y is computed along with the value of z. + +\copydetails CppAD::local::forward_unary2_op_0 +*/ +template +void forward_tanh_op_0( + size_t i_z , + size_t i_x , + size_t cap_order , + Base* taylor ) +{ + // check assumptions + CPPAD_ASSERT_UNKNOWN( NumArg(TanOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( NumRes(TanOp) == 2 ); + CPPAD_ASSERT_UNKNOWN( 0 < cap_order ); + + // Taylor coefficients corresponding to argument and result + Base* x = taylor + i_x * cap_order; + Base* z = taylor + i_z * cap_order; // called z in documentation + Base* y = z - cap_order; // called y in documentation + + z[0] = tanh( x[0] ); + y[0] = z[0] * z[0]; +} + +/*! +Compute reverse mode partial derivatives for result of op = TanOp. + +The C++ source code corresponding to this operation is +\verbatim + z = tanh(x) +\endverbatim +The auxillary result is +\verbatim + y = cos(x) +\endverbatim +The value of y is computed along with the value of z. + +\copydetails CppAD::local::reverse_unary2_op +*/ + +template +void reverse_tanh_op( + size_t d , + size_t i_z , + size_t i_x , + size_t cap_order , + const Base* taylor , + size_t nc_partial , + Base* partial ) +{ + // check assumptions + CPPAD_ASSERT_UNKNOWN( NumArg(TanOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( NumRes(TanOp) == 2 ); + CPPAD_ASSERT_UNKNOWN( d < cap_order ); + CPPAD_ASSERT_UNKNOWN( d < nc_partial ); + + // Taylor coefficients and partials corresponding to argument + const Base* x = taylor + i_x * cap_order; + Base* px = partial + i_x * nc_partial; + + // Taylor coefficients and partials corresponding to first result + const Base* z = taylor + i_z * cap_order; // called z in doc + Base* pz = partial + i_z * nc_partial; + + // Taylor coefficients and partials corresponding to auxillary result + const Base* y = z - cap_order; // called y in documentation + Base* py = pz - nc_partial; + + + size_t j = d; + size_t k; + Base base_two(2); + while(j) + { + px[j] += pz[j]; + pz[j] /= Base(double(j)); + for(k = 1; k <= j; k++) + { px[k] -= azmul(pz[j], y[j-k]) * Base(double(k)); + py[j-k] -= azmul(pz[j], x[k]) * Base(double(k)); + } + for(k = 0; k < j; k++) + pz[k] += azmul(py[j-1], z[j-k-1]) * base_two; + + --j; + } + px[0] += azmul(pz[0], Base(1.0) - y[0]); +} + +} } // END_CPPAD_LOCAL_NAMESPACE +# endif diff --git a/build-config/cppad/include/cppad/local/utility/cppad_vector_itr.hpp b/build-config/cppad/include/cppad/local/utility/cppad_vector_itr.hpp new file mode 100644 index 00000000..b4415d9c --- /dev/null +++ b/build-config/cppad/include/cppad/local/utility/cppad_vector_itr.hpp @@ -0,0 +1,444 @@ +# ifndef CPPAD_LOCAL_UTILITY_CPPAD_VECTOR_ITR_HPP +# define CPPAD_LOCAL_UTILITY_CPPAD_VECTOR_ITR_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +# include +# include +/* +------------------------------------------------------------------------------ +$begin cppad_vector_itr_define$$ +$spell + Iterator + cppad + itr + undef + const + endif + hpp +$$ + +$section Vector Class Iterator Preprocessor Definitions$$ + +$head Syntax$$ +$codep +# define CPPAD_CONST 0 +# include +# undef CPPAD_LOCAL_UTILITY_CPPAD_VECTOR_ITR_HPP +# define CPPAD_CONST 1 +# include +%$$ + +$head Beginning of cppad_vector_itr.hpp$$ +The following preprocessor definition appears at the beginning of +$code cppad_vector_itr.hpp$$ and is used for the class definition in this file: +$codep +# if CPPAD_CONST +# define CPPAD_VECTOR_ITR const_cppad_vector_itr +# else +# define CPPAD_VECTOR_ITR cppad_vector_itr +# endif +$$ + +$head End of cppad_vector_itr.hpp$$ +The following preprocessor definition appears at the end of +$code cppad_vector_itr.hpp$$ so that it can be included with a different +value for $code CPPAD_CONST$$: +$codep +# undef CPPAD_CONST +# undef CPPAD_VECTOR_ITR +$$ + +$end +*/ +# if CPPAD_CONST +# define CPPAD_VECTOR_ITR const_cppad_vector_itr +# else +# define CPPAD_VECTOR_ITR cppad_vector_itr +# endif + + +// BEGIN_CPPAD_LOCAL_UTILITY_NAMESPACE +namespace CppAD { namespace local { namespace utility { + +// so can be declared friend in cppad_vector_itr +template class const_cppad_vector_itr; + +// ========================================================================== +template class CPPAD_VECTOR_ITR { +// ========================================================================== +/* +----------------------------------------------------------------------------- +$begin cppad_vector_itr_traits$$ +$spell + Iterator +$$ + +$section Vector Class Iterator Traits and Friends$$ + +$srccode%hpp% */ +# if ! CPPAD_CONST + friend class const_cppad_vector_itr; +# endif +public: + typedef std::random_access_iterator_tag iterator_category; + typedef Type value_type; + typedef std::ptrdiff_t difference_type; + typedef Type* pointer; + typedef Type& reference; +/* %$$ +$end +------------------------------------------------------------------------------- +$begin cppad_vector_itr_ctor$$ +$spell + Iterator + ptr + cppad + Namespace + CppAD + const + iterators + itr +$$ + +$section Vector Class Iterator Member Data and Constructors$$ + +$head Constructors$$ + +$subhead Constant$$ +$codei%const_cppad_vector_itr %itr%() +%$$ +$codei%const_cppad_vector_itr %itr%(%data%, %length%, %index%) +%$$ +$codei%const_cppad_vector_itr %itr%(%other%) +%$$ +$codei%const_cppad_vector_itr %itr%(%non_const_other%) +%$$ + +$subhead Not Constant$$ +$codei%cppad_vector_itr %itr%() +%$$ +$codei%cppad_vector_itr %itr%(%data%, %length%, %index%) +%$$ +$codei%cppad_vector_itr %itr%(%other%) +%$$ + +$head Namespace$$ +These definitions are in the $code CppAD::local::utility$$ namespace. + +$head Indirection$$ +We use an extra level of indirection in this routine so that +the iterator has the same values as the vector even if the vector changes. + +$head data_$$ +is a pointer to a constant pointer to data for this vector +(used by operations that are not supported by constant iterators). + +$head length_$$ +is a pointer to the length of the corresponding vector. + +$head index_$$ +is the current vector index corresponding to this iterator. + +$head check_element$$ +generates an assert with a known cause when the $code index_$$ +does not correspond go a valid element and +$code NDEBUG$$ is not defined. + +$head check_cop$$ +Generates an assert with a known cause when the $code data_$$ +for this vector is different from the other vector and +$code NDEBUG$$ is not defined. +This should be used by operators that compare iterators. + + +$head Source$$ +$srccode%hpp% */ +private: +# if CPPAD_CONST + const Type* const* data_; +# else + Type* const* data_; +# endif + const size_t* length_; + difference_type index_; + void check_element(void) const CPPAD_NDEBUG_NOEXCEPT + { CPPAD_ASSERT_KNOWN( 0 <= index_ && size_t(index_) < *length_, + "CppAD vector iterator: accessing element out of range" + ); + } + void check_cop(const CPPAD_VECTOR_ITR& other) const CPPAD_NDEBUG_NOEXCEPT + { CPPAD_ASSERT_KNOWN( data_ == other.data_, + "CppAD vector iterator: comparing indices from different vectors" + ); + } +public: + CPPAD_VECTOR_ITR(void) noexcept + : data_(nullptr), length_(nullptr), index_(0) + { } +# if CPPAD_CONST + const_cppad_vector_itr( + const Type* const* data, const size_t* length, difference_type index + ) noexcept + : data_(data), length_(length), index_( difference_type(index) ) + { } + // ctor a const_iterator from an iterator + const_cppad_vector_itr( + const cppad_vector_itr& non_const_other + ) noexcept + { data_ = non_const_other.data_; + length_ = non_const_other.length_; + index_ = non_const_other.index_; + } +# else + cppad_vector_itr( + Type* const* data, const size_t* length, difference_type index + ) noexcept + : data_(data), length_(length), index_( difference_type(index) ) + { } +# endif + void operator=(const CPPAD_VECTOR_ITR& other) noexcept + { data_ = other.data_; + length_ = other.length_; + index_ = other.index_; + } + CPPAD_VECTOR_ITR(const CPPAD_VECTOR_ITR& other) noexcept + { *this = other; } +/* %$$ +$end +------------------------------------------------------------------------------- +$begin cppad_vector_itr_inc$$ +$spell + Iterator + itr +$$ + +$section Vector Class Iterator Increment Operators$$ + +$head Syntax$$ +$codei%++%itr% +%$$ +$codei%--%itr% +%$$ +$icode%itr%++ +%$$ +$icode%itr%-- +%$$ + +$head Source$$ +$srccode%hpp% */ +public: + CPPAD_VECTOR_ITR& operator++(void) noexcept + { ++index_; + return *this; + } + CPPAD_VECTOR_ITR& operator--(void) noexcept + { --index_; + return *this; + } + CPPAD_VECTOR_ITR operator++(int) noexcept + { CPPAD_VECTOR_ITR ret(*this); + ++index_; + return ret; + } + CPPAD_VECTOR_ITR operator--(int) noexcept + { CPPAD_VECTOR_ITR ret(*this); + --index_; + return ret; + } +/* %$$ +$end +------------------------------------------------------------------------------- +$begin cppad_vector_itr_equal$$ +$spell + itr + Iterator +$$ + +$section Vector Class Iterator Equality Operators$$ +$spell + iterators +$$ + +$head Syntax$$ +$icode%itr% == %other% +%$$ +$icode%itr% != %other% +%$$ + +$head Restrictions$$ +It is an error to compare iterators corresponding to different +$code data_$$ vectors + +$head Source$$ +$srccode%hpp% */ +public: + bool operator==(const CPPAD_VECTOR_ITR& other) const CPPAD_NDEBUG_NOEXCEPT + { check_cop(other); + return index_ == other.index_; + } + bool operator!=(const CPPAD_VECTOR_ITR& other) const CPPAD_NDEBUG_NOEXCEPT + { check_cop(other); + return index_ != other.index_; + } +/* %$$ +$end +------------------------------------------------------------------------------- +$begin cppad_vector_itr_element$$ +$spell + itr + Iterator +$$ + +$section Vector Class Iterator Access Elements$$ + +$head Syntax$$ +$icode%element% = *%itr% +%$$ +$codei%*%itr% = %element% +%$$ + +$head Source$$ +$srccode%hpp% */ +public: + const Type& operator*(void) const + { check_element(); + return (*data_)[index_]; + } +# if ! CPPAD_CONST + Type& operator*(void) + { check_element(); + return (*data_)[index_]; + } +# endif +/* %$$ +$end +------------------------------------------------------------------------------- +$begin cppad_vector_itr_random$$ +$spell + itr + Iterator + bool + iterators +$$ + +$section Vector Class Iterator Random Access$$ + +$head Syntax$$ +$icode%element% = %itr%[%n%] +%$$ +$icode%itr%[%n%] = %element% +%$$ +$icode%itr% %+-% = %n% +%$$ +$icode%itr% = %other% %+-% %n% +%$$ +$icode%itr% = %n% %+-% %other% +%$$ +$icode%n% = %itr% - %other% +%$$ +$code%b% = %itr% %cop% %other% +%$$ + +$subhead +-$$ +The notation $icode +-$$ above is either $code +$$ or $code -$$. + +$subhead cop$$ +is one of the following: +$code <$$, $code <=$$, +$code >$$, $code >=$$. + +$head itr, other$$ +are iterators of the same type. + +$head n$$ +is a $code difference_type$$ object. + +$head b$$ +is a $code bool$$. + +$head Restrictions$$ +It is an error to use a $icode cop$$ with iterators corresponding to different +$code data_$$ vectors + +$head Source$$ +$srccode%hpp% */ +public: + CPPAD_VECTOR_ITR operator[](difference_type n) + { return *(*this + n); + } + // sum and difference operators + CPPAD_VECTOR_ITR& operator+=(difference_type n) noexcept + { index_ += n; + return *this; + } + CPPAD_VECTOR_ITR& operator-=(difference_type n) noexcept + { index_ -= n; + return *this; + } + CPPAD_VECTOR_ITR operator+(difference_type n) const noexcept + { return CPPAD_VECTOR_ITR(data_, length_, index_ + n); + } + CPPAD_VECTOR_ITR operator-(difference_type n) const noexcept + { return CPPAD_VECTOR_ITR(data_, length_, index_ - n); + } + difference_type operator-(const CPPAD_VECTOR_ITR& other) const + noexcept + { return index_ - other.index_; + } + // comparison operators + bool operator<(const CPPAD_VECTOR_ITR& other) const CPPAD_NDEBUG_NOEXCEPT + { check_cop(other); + return index_ < other.index_; + } + bool operator<=(const CPPAD_VECTOR_ITR& other) const CPPAD_NDEBUG_NOEXCEPT + { check_cop(other); + return index_ <= other.index_; + } + bool operator>(const CPPAD_VECTOR_ITR& other) const CPPAD_NDEBUG_NOEXCEPT + { check_cop(other); + return index_ > other.index_; + } + bool operator>=(const CPPAD_VECTOR_ITR& other) const CPPAD_NDEBUG_NOEXCEPT + { check_cop(other); + return index_ >= other.index_; + } +/* %$$ +$srcthisfile% + 0%// BEGIN_BINARY_OP%// END_BINARY_OP%1 +%$$ +$end +*/ +// ========================================================================== +}; // END_TEMPLATE_CLASS_CPPAD_VECTOR_ITR +// ========================================================================== + +// BEGIN_BINARY_OP +template CPPAD_VECTOR_ITR operator+( + typename CPPAD_VECTOR_ITR::difference_type n , + const CPPAD_VECTOR_ITR& other ) noexcept +{ return + CPPAD_VECTOR_ITR(other.data_, other.length_, n + other.index_ ); +} +template CPPAD_VECTOR_ITR operator-( + typename CPPAD_VECTOR_ITR::difference_type n , + const CPPAD_VECTOR_ITR& other ) noexcept +{ return + CPPAD_VECTOR_ITR(other.data_, other.length_, n - other.index_ ); +} +// END_BINARY_OP + +} } } // END_CPPAD_LOCAL_UTILITY_NAMESPACE + +# undef CPPAD_CONST +# undef CPPAD_VECTOR_ITR +# endif diff --git a/build-config/cppad/include/cppad/local/utility/vector_bool.hpp b/build-config/cppad/include/cppad/local/utility/vector_bool.hpp new file mode 100644 index 00000000..48d5d147 --- /dev/null +++ b/build-config/cppad/include/cppad/local/utility/vector_bool.hpp @@ -0,0 +1,84 @@ +# ifndef CPPAD_LOCAL_UTILITY_VECTOR_BOOL_HPP +# define CPPAD_LOCAL_UTILITY_VECTOR_BOOL_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +# include + +// BEGIN_CPPAD_LOCAL_UTILITY_NAMESPACE +namespace CppAD { namespace local { namespace utility { +/* +$begin vector_bool_element$$ +$spell + Bool +$$ + +$section vectorBoolElement Class$$ + +$head Syntax$$ +$codei%local::utility::vectorBoolElement %element%(%unit%, %mask%) +%$$ +$codei%local::utility::vectorBoolElement %element%(%other%) +%$$ +$icode%value% = %element% +%$$ +$icode%element% = %value% +%$$ +$icode%element% = %element% +%$$ + +$head unit_t$$ +Type used to pack multiple boolean (bit) values into one unit. +Logical operations are preformed one unit at a time. + +$head unit_$$ +pointer to the unit that holds the value for this element. + +$head mask_$$ +mask for the bit corresponding to this element; i.e., all the bits +are zero except for bit that corresponds to this element which is one. + +$head value$$ +is a $code bool$$. + +$head Source$$ +$srccode%hpp% */ +class vectorBoolElement { +private: + typedef size_t unit_t; + unit_t* unit_; + unit_t mask_; +public: + vectorBoolElement(unit_t* unit, unit_t mask ) + : unit_(unit) , mask_(mask) + { } + vectorBoolElement(const vectorBoolElement& other) + : unit_(other.unit_) , mask_(other.mask_) + { } + operator bool() const + { return (*unit_ & mask_) != 0; } + vectorBoolElement& operator=(bool value) + { if(value) *unit_ |= mask_; + else *unit_ &= ~mask_; + return *this; + } + vectorBoolElement& operator=(const vectorBoolElement& element) + { if( *(element.unit_) & element.mask_ ) *unit_ |= mask_; + else *unit_ &= ~mask_; + return *this; + } +}; +/* %$$ +$end +*/ +} } } // END_CPPAD_LOCAL_UTILITY_NAMESPACE +# endif diff --git a/build-config/cppad/include/cppad/local/zmul_op.hpp b/build-config/cppad/include/cppad/local/zmul_op.hpp new file mode 100644 index 00000000..13f9049e --- /dev/null +++ b/build-config/cppad/include/cppad/local/zmul_op.hpp @@ -0,0 +1,517 @@ +# ifndef CPPAD_LOCAL_ZMUL_OP_HPP +# define CPPAD_LOCAL_ZMUL_OP_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-18 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +namespace CppAD { namespace local { // BEGIN_CPPAD_LOCAL_NAMESPACE +/*! +\file mul_op.hpp +Forward and reverse mode calculations for z = azmul(x, y). +*/ + +// --------------------------- Zmulvv ----------------------------------------- +/*! +Compute forward mode Taylor coefficients for result of op = ZmulvvOp. + +The C++ source code corresponding to this operation is +\verbatim + z = azmul(x, y) +\endverbatim +In the documentation below, +this operations is for the case where both x and y are variables +and the argument parameter is not used. + +\copydetails CppAD::local::forward_binary_op +*/ + +template +void forward_zmulvv_op( + size_t p , + size_t q , + size_t i_z , + const addr_t* arg , + const Base* parameter , + size_t cap_order , + Base* taylor ) +{ + // check assumptions + CPPAD_ASSERT_UNKNOWN( NumArg(ZmulvvOp) == 2 ); + CPPAD_ASSERT_UNKNOWN( NumRes(ZmulvvOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( q < cap_order ); + CPPAD_ASSERT_UNKNOWN( p <= q ); + + // Taylor coefficients corresponding to arguments and result + Base* x = taylor + size_t(arg[0]) * cap_order; + Base* y = taylor + size_t(arg[1]) * cap_order; + Base* z = taylor + i_z * cap_order; + + size_t k; + for(size_t d = p; d <= q; d++) + { z[d] = Base(0.0); + for(k = 0; k <= d; k++) + z[d] += azmul(x[d-k], y[k]); + } +} +/*! +Multiple directions forward mode Taylor coefficients for op = ZmulvvOp. + +The C++ source code corresponding to this operation is +\verbatim + z = azmul(x, y) +\endverbatim +In the documentation below, +this operations is for the case where both x and y are variables +and the argument parameter is not used. + +\copydetails CppAD::local::forward_binary_op_dir +*/ + +template +void forward_zmulvv_op_dir( + size_t q , + size_t r , + size_t i_z , + const addr_t* arg , + const Base* parameter , + size_t cap_order , + Base* taylor ) +{ + // check assumptions + CPPAD_ASSERT_UNKNOWN( NumArg(ZmulvvOp) == 2 ); + CPPAD_ASSERT_UNKNOWN( NumRes(ZmulvvOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( 0 < q ); + CPPAD_ASSERT_UNKNOWN( q < cap_order ); + + // Taylor coefficients corresponding to arguments and result + size_t num_taylor_per_var = (cap_order-1) * r + 1; + Base* x = taylor + size_t(arg[0]) * num_taylor_per_var; + Base* y = taylor + size_t(arg[1]) * num_taylor_per_var; + Base* z = taylor + i_z * num_taylor_per_var; + + size_t k, ell, m; + for(ell = 0; ell < r; ell++) + { m = (q-1)*r + ell + 1; + z[m] = azmul(x[0], y[m]) + azmul(x[m], y[0]); + for(k = 1; k < q; k++) + z[m] += azmul(x[(q-k-1)*r + ell + 1], y[(k-1)*r + ell + 1]); + } +} + +/*! +Compute zero order forward mode Taylor coefficients for result of op = ZmulvvOp. + +The C++ source code corresponding to this operation is +\verbatim + z = azmul(x, y) +\endverbatim +In the documentation below, +this operations is for the case where both x and y are variables +and the argument parameter is not used. + +\copydetails CppAD::local::forward_binary_op_0 +*/ + +template +void forward_zmulvv_op_0( + size_t i_z , + const addr_t* arg , + const Base* parameter , + size_t cap_order , + Base* taylor ) +{ + // check assumptions + CPPAD_ASSERT_UNKNOWN( NumArg(ZmulvvOp) == 2 ); + CPPAD_ASSERT_UNKNOWN( NumRes(ZmulvvOp) == 1 ); + + // Taylor coefficients corresponding to arguments and result + Base* x = taylor + size_t(arg[0]) * cap_order; + Base* y = taylor + size_t(arg[1]) * cap_order; + Base* z = taylor + i_z * cap_order; + + z[0] = azmul(x[0], y[0]); +} + +/*! +Compute reverse mode partial derivatives for result of op = ZmulvvOp. + +The C++ source code corresponding to this operation is +\verbatim + z = azmul(x, y) +\endverbatim +In the documentation below, +this operations is for the case where both x and y are variables +and the argument parameter is not used. + +\copydetails CppAD::local::reverse_binary_op +*/ + +template +void reverse_zmulvv_op( + size_t d , + size_t i_z , + const addr_t* arg , + const Base* parameter , + size_t cap_order , + const Base* taylor , + size_t nc_partial , + Base* partial ) +{ + // check assumptions + CPPAD_ASSERT_UNKNOWN( NumArg(ZmulvvOp) == 2 ); + CPPAD_ASSERT_UNKNOWN( NumRes(ZmulvvOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( d < cap_order ); + CPPAD_ASSERT_UNKNOWN( d < nc_partial ); + + // Arguments + const Base* x = taylor + size_t(arg[0]) * cap_order; + const Base* y = taylor + size_t(arg[1]) * cap_order; + + // Partial derivatives corresponding to arguments and result + Base* px = partial + size_t(arg[0]) * nc_partial; + Base* py = partial + size_t(arg[1]) * nc_partial; + Base* pz = partial + i_z * nc_partial; + + // number of indices to access + size_t j = d + 1; + size_t k; + while(j) + { --j; + for(k = 0; k <= j; k++) + { + px[j-k] += azmul(pz[j], y[k]); + py[k] += azmul(pz[j], x[j-k]); + } + } +} +// --------------------------- Zmulpv ----------------------------------------- +/*! +Compute forward mode Taylor coefficients for result of op = ZmulpvOp. + +The C++ source code corresponding to this operation is +\verbatim + z = azmul(x, y) +\endverbatim +In the documentation below, +this operations is for the case where x is a parameter and y is a variable. + +\copydetails CppAD::local::forward_binary_op +*/ + +template +void forward_zmulpv_op( + size_t p , + size_t q , + size_t i_z , + const addr_t* arg , + const Base* parameter , + size_t cap_order , + Base* taylor ) +{ + // check assumptions + CPPAD_ASSERT_UNKNOWN( NumArg(ZmulpvOp) == 2 ); + CPPAD_ASSERT_UNKNOWN( NumRes(ZmulpvOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( q < cap_order ); + CPPAD_ASSERT_UNKNOWN( p <= q ); + + // Taylor coefficients corresponding to arguments and result + Base* y = taylor + size_t(arg[1]) * cap_order; + Base* z = taylor + i_z * cap_order; + + // Paraemter value + Base x = parameter[ arg[0] ]; + + for(size_t d = p; d <= q; d++) + z[d] = azmul(x, y[d]); +} +/*! +Multiple directions forward mode Taylor coefficients for op = ZmulpvOp. + +The C++ source code corresponding to this operation is +\verbatim + z = azmul(x, y) +\endverbatim +In the documentation below, +this operations is for the case where x is a parameter and y is a variable. + +\copydetails CppAD::local::forward_binary_op_dir +*/ + +template +void forward_zmulpv_op_dir( + size_t q , + size_t r , + size_t i_z , + const addr_t* arg , + const Base* parameter , + size_t cap_order , + Base* taylor ) +{ + // check assumptions + CPPAD_ASSERT_UNKNOWN( NumArg(ZmulpvOp) == 2 ); + CPPAD_ASSERT_UNKNOWN( NumRes(ZmulpvOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( 0 < q ); + CPPAD_ASSERT_UNKNOWN( q < cap_order ); + + // Taylor coefficients corresponding to arguments and result + size_t num_taylor_per_var = (cap_order-1) * r + 1; + size_t m = (q-1) * r + 1; + Base* y = taylor + size_t(arg[1]) * num_taylor_per_var + m; + Base* z = taylor + i_z * num_taylor_per_var + m; + + // Paraemter value + Base x = parameter[ arg[0] ]; + + for(size_t ell = 0; ell < r; ell++) + z[ell] = azmul(x, y[ell]); +} +/*! +Compute zero order forward mode Taylor coefficient for result of op = ZmulpvOp. + +The C++ source code corresponding to this operation is +\verbatim + z = azmul(x, y) +\endverbatim +In the documentation below, +this operations is for the case where x is a parameter and y is a variable. + +\copydetails CppAD::local::forward_binary_op_0 +*/ + +template +void forward_zmulpv_op_0( + size_t i_z , + const addr_t* arg , + const Base* parameter , + size_t cap_order , + Base* taylor ) +{ + // check assumptions + CPPAD_ASSERT_UNKNOWN( NumArg(ZmulpvOp) == 2 ); + CPPAD_ASSERT_UNKNOWN( NumRes(ZmulpvOp) == 1 ); + + // Paraemter value + Base x = parameter[ arg[0] ]; + + // Taylor coefficients corresponding to arguments and result + Base* y = taylor + size_t(arg[1]) * cap_order; + Base* z = taylor + i_z * cap_order; + + z[0] = azmul(x, y[0]); +} + +/*! +Compute reverse mode partial derivative for result of op = ZmulpvOp. + +The C++ source code corresponding to this operation is +\verbatim + z = azmul(x, y) +\endverbatim +In the documentation below, +this operations is for the case where x is a parameter and y is a variable. + +\copydetails CppAD::local::reverse_binary_op +*/ + +template +void reverse_zmulpv_op( + size_t d , + size_t i_z , + const addr_t* arg , + const Base* parameter , + size_t cap_order , + const Base* taylor , + size_t nc_partial , + Base* partial ) +{ + // check assumptions + CPPAD_ASSERT_UNKNOWN( NumArg(ZmulpvOp) == 2 ); + CPPAD_ASSERT_UNKNOWN( NumRes(ZmulpvOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( d < cap_order ); + CPPAD_ASSERT_UNKNOWN( d < nc_partial ); + + // Arguments + Base x = parameter[ arg[0] ]; + + // Partial derivatives corresponding to arguments and result + Base* py = partial + size_t(arg[1]) * nc_partial; + Base* pz = partial + i_z * nc_partial; + + // number of indices to access + size_t j = d + 1; + while(j) + { --j; + py[j] += azmul(pz[j], x); + } +} +// --------------------------- Zmulvp ----------------------------------------- +/*! +Compute forward mode Taylor coefficients for result of op = ZmulvpOp. + +The C++ source code corresponding to this operation is +\verbatim + z = azmul(x, y) +\endverbatim +In the documentation below, +this operations is for the case where x is a parameter and y is a variable. + +\copydetails CppAD::local::forward_binary_op +*/ + +template +void forward_zmulvp_op( + size_t p , + size_t q , + size_t i_z , + const addr_t* arg , + const Base* parameter , + size_t cap_order , + Base* taylor ) +{ + // check assumptions + CPPAD_ASSERT_UNKNOWN( NumArg(ZmulvpOp) == 2 ); + CPPAD_ASSERT_UNKNOWN( NumRes(ZmulvpOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( q < cap_order ); + CPPAD_ASSERT_UNKNOWN( p <= q ); + + // Taylor coefficients corresponding to arguments and result + Base* x = taylor + size_t(arg[0]) * cap_order; + Base* z = taylor + i_z * cap_order; + + // Paraemter value + Base y = parameter[ arg[1] ]; + + for(size_t d = p; d <= q; d++) + z[d] = azmul(x[d], y); +} +/*! +Multiple directions forward mode Taylor coefficients for op = ZmulvpOp. + +The C++ source code corresponding to this operation is +\verbatim + z = azmul(x, y) +\endverbatim +In the documentation below, +this operations is for the case where x is a parameter and y is a variable. + +\copydetails CppAD::local::forward_binary_op_dir +*/ + +template +void forward_zmulvp_op_dir( + size_t q , + size_t r , + size_t i_z , + const addr_t* arg , + const Base* parameter , + size_t cap_order , + Base* taylor ) +{ + // check assumptions + CPPAD_ASSERT_UNKNOWN( NumArg(ZmulvpOp) == 2 ); + CPPAD_ASSERT_UNKNOWN( NumRes(ZmulvpOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( 0 < q ); + CPPAD_ASSERT_UNKNOWN( q < cap_order ); + + // Taylor coefficients corresponding to arguments and result + size_t num_taylor_per_var = (cap_order-1) * r + 1; + size_t m = (q-1) * r + 1; + Base* x = taylor + size_t(arg[0]) * num_taylor_per_var + m; + Base* z = taylor + i_z * num_taylor_per_var + m; + + // Paraemter value + Base y = parameter[ arg[1] ]; + + for(size_t ell = 0; ell < r; ell++) + z[ell] = azmul(x[ell], y); +} +/*! +Compute zero order forward mode Taylor coefficient for result of op = ZmulvpOp. + +The C++ source code corresponding to this operation is +\verbatim + z = azmul(x, y) +\endverbatim +In the documentation below, +this operations is for the case where x is a parameter and y is a variable. + +\copydetails CppAD::local::forward_binary_op_0 +*/ + +template +void forward_zmulvp_op_0( + size_t i_z , + const addr_t* arg , + const Base* parameter , + size_t cap_order , + Base* taylor ) +{ + // check assumptions + CPPAD_ASSERT_UNKNOWN( NumArg(ZmulvpOp) == 2 ); + CPPAD_ASSERT_UNKNOWN( NumRes(ZmulvpOp) == 1 ); + + // Paraemter value + Base y = parameter[ arg[1] ]; + + // Taylor coefficients corresponding to arguments and result + Base* x = taylor + size_t(arg[0]) * cap_order; + Base* z = taylor + i_z * cap_order; + + z[0] = azmul(x[0], y); +} + +/*! +Compute reverse mode partial derivative for result of op = ZmulvpOp. + +The C++ source code corresponding to this operation is +\verbatim + z = azmul(x, y) +\endverbatim +In the documentation below, +this operations is for the case where x is a parameter and y is a variable. + +\copydetails CppAD::local::reverse_binary_op +*/ + +template +void reverse_zmulvp_op( + size_t d , + size_t i_z , + const addr_t* arg , + const Base* parameter , + size_t cap_order , + const Base* taylor , + size_t nc_partial , + Base* partial ) +{ + // check assumptions + CPPAD_ASSERT_UNKNOWN( NumArg(ZmulvpOp) == 2 ); + CPPAD_ASSERT_UNKNOWN( NumRes(ZmulvpOp) == 1 ); + CPPAD_ASSERT_UNKNOWN( d < cap_order ); + CPPAD_ASSERT_UNKNOWN( d < nc_partial ); + + // Arguments + Base y = parameter[ arg[1] ]; + + // Partial derivatives corresponding to arguments and result + Base* px = partial + size_t(arg[0]) * nc_partial; + Base* pz = partial + i_z * nc_partial; + + // number of indices to access + size_t j = d + 1; + while(j) + { --j; + px[j] += azmul(pz[j], y); + } +} + +} } // END_CPPAD_LOCAL_NAMESPACE +# endif diff --git a/build-config/cppad/include/cppad/speed/det_33.hpp b/build-config/cppad/include/cppad/speed/det_33.hpp new file mode 100644 index 00000000..6a59fd2a --- /dev/null +++ b/build-config/cppad/include/cppad/speed/det_33.hpp @@ -0,0 +1,113 @@ +# ifndef CPPAD_SPEED_DET_33_HPP +# define CPPAD_SPEED_DET_33_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-17 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ +/* +$begin det_33$$ +$spell + cppad + CppAD + det + namespace + const + bool + hpp +$$ + +$section Check Determinant of 3 by 3 matrix$$ + + +$head Syntax$$ +$codei%# include +%$$ +$icode%ok% = det_33(%x%, %d%)%$$ + +$head Purpose$$ +This routine can be used to check a method for computing +the determinant of a matrix. + +$head Inclusion$$ +The template function $code det_33$$ is defined in the $code CppAD$$ +namespace by including +the file $code cppad/speed/det_33.hpp$$ +(relative to the CppAD distribution directory). + +$head x$$ +The argument $icode x$$ has prototype +$codei% + const %Vector% &%x% +%$$. +It contains the elements of the matrix $latex X$$ in row major order; i.e., +$latex \[ + X_{i,j} = x [ i * 3 + j ] +\] $$ + +$head d$$ +The argument $icode d$$ has prototype +$codei% + const %Vector% &%d% +%$$. +It is tested to see if $icode%d%[0]%$$ it is equal to $latex \det ( X )$$. + +$head Vector$$ +If $icode y$$ is a $icode Vector$$ object, +it must support the syntax +$codei% + %y%[%i%] +%$$ +where $icode i$$ has type $code size_t$$ with value less than 9. +This must return a $code double$$ value corresponding to the $th i$$ +element of the vector $icode y$$. +This is the only requirement of the type $icode Vector$$. +(Note that only the first element of the vector $icode d$$ is used.) + +$head ok$$ +The return value $icode ok$$ has prototype +$codei% + bool %ok% +%$$ +It is true, if the determinant $icode%d%[0]%$$ +passes the test and false otherwise. + +$children% + omh/det_33_hpp.omh +%$$ + +$head Source Code$$ +The file +$cref det_33.hpp$$ +contains the source code for this template function. + +$end +------------------------------------------------------------------------------ +*/ +// BEGIN C++ +# include +namespace CppAD { +template + bool det_33(const Vector &x, const Vector &d) + { bool ok = true; + double eps99 = 99.0 * std::numeric_limits::epsilon(); + + // use expansion by minors to compute the determinant by hand + double check = 0.; + check += x[0] * ( x[4] * x[8] - x[5] * x[7] ); + check -= x[1] * ( x[3] * x[8] - x[5] * x[6] ); + check += x[2] * ( x[3] * x[7] - x[4] * x[6] ); + + ok &= CppAD::NearEqual(check, d[0], eps99, eps99); + + return ok; + } +} +// END C++ +# endif diff --git a/build-config/cppad/include/cppad/speed/det_by_lu.hpp b/build-config/cppad/include/cppad/speed/det_by_lu.hpp new file mode 100644 index 00000000..25ed10f5 --- /dev/null +++ b/build-config/cppad/include/cppad/speed/det_by_lu.hpp @@ -0,0 +1,182 @@ +# ifndef CPPAD_SPEED_DET_BY_LU_HPP +# define CPPAD_SPEED_DET_BY_LU_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-17 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ +/* +$begin det_by_lu$$ +$spell + CppAD + cppad + lu + hpp + typedef + const + hpp + Det + CPPAD_TESTVECTOR + namespace +$$ + +$section Determinant Using Expansion by Lu Factorization$$ + + +$head Syntax$$ +$codei%# include +%$$ +$codei%det_by_lu<%Scalar%> %det%(%n%) +%$$ +$icode%d% = %det%(%a%) +%$$ + +$head Inclusion$$ +The template class $code det_by_lu$$ is defined in the $code CppAD$$ +namespace by including +the file $code cppad/speed/det_by_lu.hpp$$ +(relative to the CppAD distribution directory). + +$head Constructor$$ +The syntax +$codei% + det_by_lu<%Scalar%> %det%(%n%) +%$$ +constructs the object $icode det$$ which can be used for +evaluating the determinant of $icode n$$ by $icode n$$ matrices +using LU factorization. + +$head Scalar$$ +The type $icode Scalar$$ can be any +$cref NumericType$$ + +$head n$$ +The argument $icode n$$ has prototype +$codei% + size_t %n% +%$$ + +$head det$$ +The syntax +$codei% + %d% = %det%(%a%) +%$$ +returns the determinant of the matrix $latex A$$ using LU factorization. + +$subhead a$$ +The argument $icode a$$ has prototype +$codei% + const %Vector% &%a% +%$$ +It must be a $icode Vector$$ with length $latex n * n$$ and with +It must be a $icode Vector$$ with length $latex n * n$$ and with +elements of type $icode Scalar$$. +The elements of the $latex n \times n$$ matrix $latex A$$ are defined, +for $latex i = 0 , \ldots , n-1$$ and $latex j = 0 , \ldots , n-1$$, by +$latex \[ + A_{i,j} = a[ i * m + j] +\] $$ + +$subhead d$$ +The return value $icode d$$ has prototype +$codei% + %Scalar% %d% +%$$ + +$head Vector$$ +If $icode y$$ is a $icode Vector$$ object, +it must support the syntax +$codei% + %y%[%i%] +%$$ +where $icode i$$ has type $code size_t$$ with value less than $latex n * n$$. +This must return a $icode Scalar$$ value corresponding to the $th i$$ +element of the vector $icode y$$. +This is the only requirement of the type $icode Vector$$. + +$children% + speed/example/det_by_lu.cpp% + omh/det_by_lu_hpp.omh +%$$ + + +$head Example$$ +The file +$cref det_by_lu.cpp$$ +contains an example and test of $code det_by_lu.hpp$$. + +$head Source Code$$ +The file +$cref det_by_lu.hpp$$ +contains the source for this template function. + + +$end +--------------------------------------------------------------------------- +*/ +// BEGIN C++ +# include +# include + +// BEGIN CppAD namespace +namespace CppAD { + +template +class det_by_lu { +private: + const size_t m_; + const size_t n_; + CppAD::vector A_; + CppAD::vector B_; + CppAD::vector X_; +public: + det_by_lu(size_t n) : m_(0), n_(n), A_(n * n) + { } + + template + Scalar operator()(const Vector &x) + { + + Scalar logdet; + Scalar det; + int signdet; + size_t i; + + // copy matrix so it is not overwritten + for(i = 0; i < n_ * n_; i++) + A_[i] = x[i]; + + // comput log determinant + signdet = CppAD::LuSolve( + n_, m_, A_, B_, X_, logdet); + +/* + // Do not do this for speed test because it makes floating + // point operation sequence very simple. + if( signdet == 0 ) + det = 0; + else + det = Scalar( signdet ) * exp( logdet ); +*/ + + // convert to determinant + det = Scalar( signdet ) * exp( logdet ); + +# ifdef FADBAD + // Fadbad requires tempories to be set to constants + for(i = 0; i < n_ * n_; i++) + A_[i] = 0; +# endif + + return det; + } +}; +} // END CppAD namespace +// END C++ +# endif diff --git a/build-config/cppad/include/cppad/speed/det_by_minor.hpp b/build-config/cppad/include/cppad/speed/det_by_minor.hpp new file mode 100644 index 00000000..88724a2a --- /dev/null +++ b/build-config/cppad/include/cppad/speed/det_by_minor.hpp @@ -0,0 +1,165 @@ +# ifndef CPPAD_SPEED_DET_BY_MINOR_HPP +# define CPPAD_SPEED_DET_BY_MINOR_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-17 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ +/* +$begin det_by_minor$$ +$spell + CppAD + cppad + typedef + const + hpp + Det + namespace +$$ + +$section Determinant Using Expansion by Minors$$ + + + +$head Syntax$$ +$codei%# include +%$$ +$codei%det_by_minor<%Scalar%> %det%(%n%) +%$$ +$icode%d% = %det%(%a%) +%$$ + +$head Inclusion$$ +The template class $code det_by_minor$$ is defined in the $code CppAD$$ +namespace by including +the file $code cppad/speed/det_by_minor.hpp$$ +(relative to the CppAD distribution directory). + +$head Constructor$$ +The syntax +$codei% + det_by_minor<%Scalar%> %det%(%n%) +%$$ +constructs the object $icode det$$ which can be used for +evaluating the determinant of $icode n$$ by $icode n$$ matrices +using expansion by minors. + +$head Scalar$$ +The type $icode Scalar$$ must satisfy the same conditions +as in the function $cref/det_of_minor/det_of_minor/Scalar/$$. + +$head n$$ +The argument $icode n$$ has prototype +$codei% + size_t %n% +%$$ + +$head det$$ +The syntax +$codei% + %d% = %det%(%a%) +%$$ +returns the determinant of the matrix $icode A$$ using expansion by minors. + +$subhead a$$ +The argument $icode a$$ has prototype +$codei% + const %Vector% &%a% +%$$ +It must be a $icode Vector$$ with length $latex n * n$$ and with +elements of type $icode Scalar$$. +The elements of the $latex n \times n$$ matrix $latex A$$ are defined, +for $latex i = 0 , \ldots , n-1$$ and $latex j = 0 , \ldots , n-1$$, by +$latex \[ + A_{i,j} = a[ i * m + j] +\] $$ + +$subhead d$$ +The return value $icode d$$ has prototype +$codei% + %Scalar% %d% +%$$ +It is equal to the determinant of $latex A$$. + +$head Vector$$ +If $icode y$$ is a $icode Vector$$ object, +it must support the syntax +$codei% + %y%[%i%] +%$$ +where $icode i$$ has type $code size_t$$ with value less than $latex n * n$$. +This must return a $icode Scalar$$ value corresponding to the $th i$$ +element of the vector $icode y$$. +This is the only requirement of the type $icode Vector$$. + +$children% + speed/example/det_by_minor.cpp% + omh/det_by_minor_hpp.omh +%$$ + + +$head Example$$ +The file +$cref det_by_minor.cpp$$ +contains an example and test of $code det_by_minor.hpp$$. + +$head Source Code$$ +The file +$cref det_by_minor.hpp$$ +contains the source for this template function. + + +$end +--------------------------------------------------------------------------- +*/ +// BEGIN C++ +# include +# include + +// BEGIN CppAD namespace +namespace CppAD { + +template +class det_by_minor { +private: + size_t m_; + + // made mutable because modified and then restored + mutable std::vector r_; + mutable std::vector c_; + + // make mutable because its value does not matter + mutable std::vector a_; +public: + det_by_minor(size_t m) : m_(m) , r_(m + 1) , c_(m + 1), a_(m * m) + { + size_t i; + + // values for r and c that correspond to entire matrix + for(i = 0; i < m; i++) + { r_[i] = i+1; + c_[i] = i+1; + } + r_[m] = 0; + c_[m] = 0; + } + + template + Scalar operator()(const Vector &x) const + { size_t i = m_ * m_; + while(i--) + a_[i] = x[i]; + return det_of_minor(a_, m_, m_, r_, c_); + } + +}; + +} // END CppAD namespace +// END C++ +# endif diff --git a/build-config/cppad/include/cppad/speed/det_grad_33.hpp b/build-config/cppad/include/cppad/speed/det_grad_33.hpp new file mode 100644 index 00000000..74dc3136 --- /dev/null +++ b/build-config/cppad/include/cppad/speed/det_grad_33.hpp @@ -0,0 +1,127 @@ +# ifndef CPPAD_SPEED_DET_GRAD_33_HPP +# define CPPAD_SPEED_DET_GRAD_33_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-17 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ +/* +$begin det_grad_33$$ +$spell + cppad + CppAD + det + namespace + const + bool + hpp +$$ + +$section Check Gradient of Determinant of 3 by 3 matrix$$ + + +$head Syntax$$ +$codei%# include +%$$ +$icode%ok% = det_grad_33(%x%, %g%)%$$ + +$head Purpose$$ +This routine can be used to check a method for computing the +gradient of the determinant of a matrix. + +$head Inclusion$$ +The template function $code det_grad_33$$ is defined in the $code CppAD$$ +namespace by including +the file $code cppad/speed/det_grad_33.hpp$$ +(relative to the CppAD distribution directory). + +$head x$$ +The argument $icode x$$ has prototype +$codei% + const %Vector% &%x% +%$$. +It contains the elements of the matrix $latex X$$ in row major order; i.e., +$latex \[ + X_{i,j} = x [ i * 3 + j ] +\] $$ + +$head g$$ +The argument $icode g$$ has prototype +$codei% + const %Vector% &%g% +%$$. +It contains the elements of the gradient of +$latex \det ( X )$$ in row major order; i.e., +$latex \[ + \D{\det (X)}{X(i,j)} = g [ i * 3 + j ] +\] $$ + +$head Vector$$ +If $icode y$$ is a $icode Vector$$ object, +it must support the syntax +$codei% + %y%[%i%] +%$$ +where $icode i$$ has type $code size_t$$ with value less than 9. +This must return a $code double$$ value corresponding to the $th i$$ +element of the vector $icode y$$. +This is the only requirement of the type $icode Vector$$. + +$head ok$$ +The return value $icode ok$$ has prototype +$codei% + bool %ok% +%$$ +It is true, if the gradient $icode g$$ +passes the test and false otherwise. + +$children% + omh/det_grad_33_hpp.omh +%$$ + +$head Source Code$$ +The file +$cref det_grad_33.hpp$$ +contains the source code for this template function. + +$end +------------------------------------------------------------------------------ +*/ +// BEGIN C++ +# include +# include +namespace CppAD { +template + bool det_grad_33(const Vector &x, const Vector &g) + { bool ok = true; + typedef typename Vector::value_type Float; + Float eps = 10. * Float( std::numeric_limits::epsilon() ); + + // use expansion by minors to compute the derivative by hand + double check[9]; + check[0] = + ( x[4] * x[8] - x[5] * x[7] ); + check[1] = - ( x[3] * x[8] - x[5] * x[6] ); + check[2] = + ( x[3] * x[7] - x[4] * x[6] ); + // + check[3] = - ( x[1] * x[8] - x[2] * x[7] ); + check[4] = + ( x[0] * x[8] - x[2] * x[6] ); + check[5] = - ( x[0] * x[7] - x[1] * x[6] ); + // + check[6] = + ( x[1] * x[5] - x[2] * x[4] ); + check[7] = - ( x[0] * x[5] - x[2] * x[3] ); + check[8] = + ( x[0] * x[4] - x[1] * x[3] ); + // + for(size_t i = 0; i < 3 * 3; i++) + ok &= CppAD::NearEqual(check[i], g[i], eps, eps); + + return ok; + } +} +// END C++ +# endif diff --git a/build-config/cppad/include/cppad/speed/det_of_minor.hpp b/build-config/cppad/include/cppad/speed/det_of_minor.hpp new file mode 100644 index 00000000..10878142 --- /dev/null +++ b/build-config/cppad/include/cppad/speed/det_of_minor.hpp @@ -0,0 +1,274 @@ +# ifndef CPPAD_SPEED_DET_OF_MINOR_HPP +# define CPPAD_SPEED_DET_OF_MINOR_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-17 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ +/* +$begin det_of_minor$$ +$spell + CppAD + hpp + std + Det + const + namespace + cppad +$$ + + +$section Determinant of a Minor$$ + +$head Syntax$$ +$codei%# include +%$$ +$icode%d% = det_of_minor(%a%, %m%, %n%, %r%, %c%)%$$ + + +$head Inclusion$$ +The template function $code det_of_minor$$ is defined in the $code CppAD$$ +namespace by including +the file $code cppad/speed/det_of_minor.hpp$$ +(relative to the CppAD distribution directory). + +$head Purpose$$ +This template function +returns the determinant of a minor of the matrix $latex A$$ +using expansion by minors. +The elements of the $latex n \times n$$ minor $latex M$$ +of the matrix $latex A$$ are defined, +for $latex i = 0 , \ldots , n-1$$ and $latex j = 0 , \ldots , n-1$$, by +$latex \[ + M_{i,j} = A_{R(i), C(j)} +\]$$ +where the functions +$latex R(i)$$ is defined by the $cref/argument r/det_of_minor/r/$$ and +$latex C(j)$$ is defined by the $cref/argument c/det_of_minor/c/$$. +$pre + +$$ +This template function +is for example and testing purposes only. +Expansion by minors is chosen as an example because it uses +a lot of floating point operations yet does not require much source code +(on the order of $icode m$$ factorial floating point operations and +about 70 lines of source code including comments). +This is not an efficient method for computing a determinant; +for example, using an LU factorization would be better. + +$head Determinant of A$$ +If the following conditions hold, the minor is the +entire matrix $latex A$$ and hence $code det_of_minor$$ +will return the determinant of $latex A$$: + +$list number$$ +$latex n = m$$. +$lnext +for $latex i = 0 , \ldots , m-1$$, $latex r[i] = i+1$$, +and $latex r[m] = 0$$. +$lnext +for $latex j = 0 , \ldots , m-1$$, $latex c[j] = j+1$$, +and $latex c[m] = 0$$. +$lend + +$head a$$ +The argument $icode a$$ has prototype +$codei% + const std::vector<%Scalar%>& %a% +%$$ +and is a vector with size $latex m * m$$ +(see description of $cref/Scalar/det_of_minor/Scalar/$$ below). +The elements of the $latex m \times m$$ matrix $latex A$$ are defined, +for $latex i = 0 , \ldots , m-1$$ and $latex j = 0 , \ldots , m-1$$, by +$latex \[ + A_{i,j} = a[ i * m + j] +\] $$ + +$head m$$ +The argument $icode m$$ has prototype +$codei% + size_t %m% +%$$ +and is the number of rows (and columns) in the square matrix $latex A$$. + +$head n$$ +The argument $icode n$$ has prototype +$codei% + size_t %n% +%$$ +and is the number of rows (and columns) in the square minor $latex M$$. + +$head r$$ +The argument $icode r$$ has prototype +$codei% + std::vector& %r% +%$$ +and is a vector with $latex m + 1$$ elements. +This vector defines the function $latex R(i)$$ +which specifies the rows of the minor $latex M$$. +To be specific, the function $latex R(i)$$ +for $latex i = 0, \ldots , n-1$$ is defined by +$latex \[ +\begin{array}{rcl} + R(0) & = & r[m] + \\ + R(i+1) & = & r[ R(i) ] +\end{array} +\] $$ +All the elements of $icode r$$ must have value +less than or equal $icode m$$. +The elements of vector $icode r$$ are modified during the computation, +and restored to their original value before the return from +$code det_of_minor$$. + +$head c$$ +The argument $icode c$$ has prototype +$codei% + std::vector& %c% +%$$ +and is a vector with $latex m + 1$$ elements +This vector defines the function $latex C(i)$$ +which specifies the rows of the minor $latex M$$. +To be specific, the function $latex C(i)$$ +for $latex j = 0, \ldots , n-1$$ is defined by +$latex \[ +\begin{array}{rcl} + C(0) & = & c[m] + \\ + C(j+1) & = & c[ C(j) ] +\end{array} +\] $$ +All the elements of $icode c$$ must have value +less than or equal $icode m$$. +The elements of vector $icode c$$ are modified during the computation, +and restored to their original value before the return from +$code det_of_minor$$. + +$head d$$ +The result $icode d$$ has prototype +$codei% + %Scalar% %d% +%$$ +and is equal to the determinant of the minor $latex M$$. + +$head Scalar$$ +If $icode x$$ and $icode y$$ are objects of type $icode Scalar$$ +and $icode i$$ is an object of type $code int$$, +the $icode Scalar$$ must support the following operations: +$table +$bold Syntax$$ + $cnext $bold Description$$ + $cnext $bold Result Type$$ +$rnext +$icode%Scalar% %x%$$ + $cnext default constructor for $icode Scalar$$ object. +$rnext +$icode%x% = %i%$$ + $cnext set value of $icode x$$ to current value of $icode i$$ +$rnext +$icode%x% = %y%$$ + $cnext set value of $icode x$$ to current value of $icode y$$ +$rnext +$icode%x% + %y%$$ + $cnext value of $icode x$$ plus $icode y$$ + $cnext $icode Scalar$$ +$rnext +$icode%x% - %y%$$ + $cnext value of $icode x$$ minus $icode y$$ + $cnext $icode Scalar$$ +$rnext +$icode%x% * %y%$$ + $cnext value of $icode x$$ times value of $icode y$$ + $cnext $icode Scalar$$ +$tend + +$children% + speed/example/det_of_minor.cpp% + omh/det_of_minor_hpp.omh +%$$ + +$head Example$$ +The file +$cref det_of_minor.cpp$$ +contains an example and test of $code det_of_minor.hpp$$. + +$head Source Code$$ +The file +$cref det_of_minor.hpp$$ +contains the source for this template function. + + +$end +--------------------------------------------------------------------------- +*/ +// BEGIN C++ +# include +# include + +namespace CppAD { // BEGIN CppAD namespace +template +Scalar det_of_minor( + const std::vector& a , + size_t m , + size_t n , + std::vector& r , + std::vector& c ) +{ + const size_t R0 = r[m]; // R(0) + size_t Cj = c[m]; // C(j) (case j = 0) + size_t Cj1 = m; // C(j-1) (case j = 0) + + // check for 1 by 1 case + if( n == 1 ) return a[ R0 * m + Cj ]; + + // initialize determinant of the minor M + Scalar detM = Scalar(0); + + // initialize sign of factor for next sub-minor + int s = 1; + + // remove row with index 0 in M from all the sub-minors of M + r[m] = r[R0]; + + // for each column of M + for(size_t j = 0; j < n; j++) + { // element with index (0,j) in the minor M + Scalar M0j = a[ R0 * m + Cj ]; + + // remove column with index j in M to form next sub-minor S of M + c[Cj1] = c[Cj]; + + // compute determinant of the current sub-minor S + Scalar detS = det_of_minor(a, m, n - 1, r, c); + + // restore column Cj to represenation of M as a minor of A + c[Cj1] = Cj; + + // include this sub-minor term in the summation + if( s > 0 ) + detM = detM + M0j * detS; + else + detM = detM - M0j * detS; + + // advance to next column of M + Cj1 = Cj; + Cj = c[Cj]; + s = - s; + } + + // restore row zero to the minor representation for M + r[m] = R0; + + // return the determinant of the minor M + return detM; +} +} // END CppAD namespace +// END C++ +# endif diff --git a/build-config/cppad/include/cppad/speed/mat_sum_sq.hpp b/build-config/cppad/include/cppad/speed/mat_sum_sq.hpp new file mode 100644 index 00000000..14a174d9 --- /dev/null +++ b/build-config/cppad/include/cppad/speed/mat_sum_sq.hpp @@ -0,0 +1,152 @@ +# ifndef CPPAD_SPEED_MAT_SUM_SQ_HPP +# define CPPAD_SPEED_MAT_SUM_SQ_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-17 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ +/* +$begin mat_sum_sq$$ +$spell + sq + namespace + const + CppAD + sq + cppad + hpp +$$ + +$section Sum Elements of a Matrix Times Itself$$ + +$head Syntax$$ +$codei%# include +%$$ +$icode%mat_sum_sq(%n%, %x%, %y%, %z%)%$$ + +$head Purpose$$ +This routine is intended for use with the matrix multiply speed tests; +to be specific, it computes +$latex \[ +\begin{array}{rcl} + y_{i,j} & = & \sum_{k=0}^{n-1} x_{i,k} x_{k,j} + \\ + z_0 & = & \sum_{i=0}^{n-1} \sum_{j=0}^{n-1} y_{i,j} +\end{array} +\] $$ +see $cref link_mat_mul$$. + +$head Inclusion$$ +The template function $code mat_sum_sq$$ is defined in the $code CppAD$$ +namespace by including +the file $code cppad/speed/mat_sum_sq.hpp$$ +(relative to the CppAD distribution directory). + +$head n$$ +This argument has prototype +$codei% + size_t %n% +%$$ +It specifies the size of the matrices. + +$head x$$ +The argument $icode x$$ has prototype +$codei% + const %Vector% &%x% +%$$ +and $icode%x%.size() == %n% * %n%$$. +It contains the elements of $latex x$$ in row major order; i.e., +$latex \[ + x_{i,j} = x [ i * n + j ] +\] $$ + +$head y$$ +The argument $icode y$$ has prototype +$codei% + %Vector%& %y% +%$$ +and $icode%y%.size() == %n% * %n%$$. +The input value of its elements does not matter. +Upon return, +$latex \[ +\begin{array}{rcl} + y_{i,j} & = & \sum_{k=0}^{n-1} x_{i,k} x_{k,j} + \\ + y[ i * n + j ] & = & y_{i,j} +\end{array} +\] $$ + + +$head z$$ +The argument $icode d$$ has prototype +$codei% + %Vector%& %z% +%$$. +The input value of its element does not matter. +Upon return +$latex \[ +\begin{array}{rcl} + z_0 & = & \sum_{i=0}^{n-1} \sum_{j=0}^n y_{i,j} + \\ + z[0] & = & z_0 +\end{array} +\] $$ + +$head Vector$$ +The type $icode Vector$$ is any +$cref SimpleVector$$, or it can be a raw pointer to the vector elements. +The element type must support +addition, multiplication, and assignment to both its own type +and to a double value. + +$children% + speed/example/mat_sum_sq.cpp% + omh/mat_sum_sq_hpp.omh +%$$ + + +$head Example$$ +The file +$cref mat_sum_sq.cpp$$ +contains an example and test of $code mat_sum_sq.hpp$$. + +$head Source Code$$ +The file +$cref mat_sum_sq.hpp$$ +contains the source for this template function. + +$end +------------------------------------------------------------------------------ +*/ +// BEGIN C++ +# include +// +namespace CppAD { + template + void mat_sum_sq(size_t n, Vector& x , Vector& y , Vector& z) + { size_t i, j, k; + // Very simple computation of y = x * x for speed comparison + for(i = 0; i < n; i++) + { for(j = 0; j < n; j++) + { y[i * n + j] = 0.; + for(k = 0; k < n; k++) + y[i * n + j] += x[i * n + k] * x[k * n + j]; + } + } + z[0] = 0.; + for(i = 0; i < n; i++) + { for(j = 0; j < n; j++) + z[0] += y[i * n + j]; + } + return; + } + +} +// END C++ +# endif diff --git a/build-config/cppad/include/cppad/speed/ode_evaluate.hpp b/build-config/cppad/include/cppad/speed/ode_evaluate.hpp new file mode 100644 index 00000000..1d670212 --- /dev/null +++ b/build-config/cppad/include/cppad/speed/ode_evaluate.hpp @@ -0,0 +1,236 @@ +# ifndef CPPAD_SPEED_ODE_EVALUATE_HPP +# define CPPAD_SPEED_ODE_EVALUATE_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-17 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +/* +$begin ode_evaluate$$ +$spell + Runge + fabs + retaped + Jacobian + const + Cpp + cppad + hpp + fp + namespace + exp +$$ + +$section Evaluate a Function Defined in Terms of an ODE$$ + + +$head Syntax$$ +$codei%# include +%$$ +$codei%ode_evaluate(%x%, %p%, %fp%)%$$ + +$head Purpose$$ +This routine evaluates a function $latex f : \B{R}^n \rightarrow \B{R}^n$$ +defined by +$latex \[ + f(x) = y(x, 1) +\] $$ +where $latex y(x, t)$$ solves the ordinary differential equation +$latex \[ +\begin{array}{rcl} + y(x, 0) & = & x + \\ + \partial_t y (x, t ) & = & g[ y(x,t) , t ] +\end{array} +\] $$ +where $latex g : \B{R}^n \times \B{R} \rightarrow \B{R}^n$$ +is an unspecified function. + +$head Inclusion$$ +The template function $code ode_evaluate$$ +is defined in the $code CppAD$$ namespace by including +the file $code cppad/speed/ode_evaluate.hpp$$ +(relative to the CppAD distribution directory). + +$head Float$$ + +$subhead Operation Sequence$$ +The type $icode Float$$ must be a $cref NumericType$$. +The $icode Float$$ +$cref/operation sequence/glossary/Operation/Sequence/$$ +for this routine does not depend on the value of the argument $icode x$$, +hence it does not need to be retaped for each value of $latex x$$. + +$subhead fabs$$ +If $icode y$$ and $icode z$$ are $icode Float$$ objects, the syntax +$codei% + %y% = fabs(%z%) +%$$ +must be supported. Note that it does not matter if the operation +sequence for $code fabs$$ depends on $icode z$$ because the +corresponding results are not actually used by $code ode_evaluate$$; +see $code fabs$$ in $cref/Runge45/Runge45/Scalar/fabs/$$. + +$head x$$ +The argument $icode x$$ has prototype +$codei% + const CppAD::vector<%Float%>& %x% +%$$ +It contains he argument value for which the function, +or its derivative, is being evaluated. +The value $latex n$$ is determined by the size of the vector $icode x$$. + +$head p$$ +The argument $icode p$$ has prototype +$codei% + size_t %p% +%$$ + +$subhead p == 0$$ +In this case a numerical method is used to solve the ode +and obtain an accurate approximation for $latex y(x, 1)$$. +This numerical method has a fixed +that does not depend on $icode x$$. + +$subhead p = 1$$ +In this case an analytic solution for the partial derivative +$latex \partial_x y(x, 1)$$ is returned. + +$head fp$$ +The argument $icode fp$$ has prototype +$codei% + CppAD::vector<%Float%>& %fp% +%$$ +The input value of the elements of $icode fp$$ does not matter. + +$subhead Function$$ +If $icode p$$ is zero, $icode fp$$ has size equal to $latex n$$ +and contains the value of $latex y(x, 1)$$. + +$subhead Gradient$$ +If $icode p$$ is one, $icode fp$$ has size equal to $icode n^2$$ +and for $latex i = 0 , \ldots 1$$, $latex j = 0 , \ldots , n-1$$ +$latex \[ + \D{y[i]}{x[j]} (x, 1) = fp [ i \cdot n + j ] +\] $$ + +$children% + speed/example/ode_evaluate.cpp% + omh/ode_evaluate.omh +%$$ + +$head Example$$ +The file +$cref ode_evaluate.cpp$$ +contains an example and test of $code ode_evaluate.hpp$$. + + +$head Source Code$$ +The file +$cref ode_evaluate.hpp$$ +contains the source code for this template function. + +$end +*/ +// BEGIN C++ +# include +# include +# include + +namespace CppAD { + + template + class ode_evaluate_fun { + public: + // Given that y_i (0) = x_i, + // the following y_i (t) satisfy the ODE below: + // y_0 (t) = x[0] + // y_1 (t) = x[1] + x[0] * t + // y_2 (t) = x[2] + x[1] * t + x[0] * t^2/2 + // y_3 (t) = x[3] + x[2] * t + x[1] * t^2/2 + x[0] * t^3 / 3! + // ... + void Ode( + const Float& t, + const CppAD::vector& y, + CppAD::vector& f) + { size_t n = y.size(); + f[0] = 0.; + for(size_t k = 1; k < n; k++) + f[k] = y[k-1]; + } + }; + // + template + void ode_evaluate( + const CppAD::vector& x , + size_t p , + CppAD::vector& fp ) + { using CppAD::vector; + typedef vector FloatVector; + + size_t n = x.size(); + CPPAD_ASSERT_KNOWN( p == 0 || p == 1, + "ode_evaluate: p is not zero or one" + ); + CPPAD_ASSERT_KNOWN( + ((p==0) & (fp.size()==n)) || ((p==1) & (fp.size()==n*n)), + "ode_evaluate: the size of fp is not correct" + ); + if( p == 0 ) + { // function that defines the ode + ode_evaluate_fun F; + + // number of Runge45 steps to use + size_t M = 10; + + // initial and final time + Float ti = 0.0; + Float tf = 1.0; + + // initial value for y(x, t); i.e. y(x, 0) + // (is a reference to x) + const FloatVector& yi = x; + + // final value for y(x, t); i.e., y(x, 1) + // (is a reference to fp) + FloatVector& yf = fp; + + // Use fourth order Runge-Kutta to solve ODE + yf = CppAD::Runge45(F, M, ti, tf, yi); + + return; + } + /* Compute derivaitve of y(x, 1) w.r.t x + y_0 (x, t) = x[0] + y_1 (x, t) = x[1] + x[0] * t + y_2 (x, t) = x[2] + x[1] * t + x[0] * t^2/2 + y_3 (x, t) = x[3] + x[2] * t + x[1] * t^2/2 + x[0] * t^3 / 3! + ... + */ + size_t i, j, k; + for(i = 0; i < n; i++) + { for(j = 0; j < n; j++) + fp[ i * n + j ] = 0.0; + } + size_t factorial = 1; + for(k = 0; k < n; k++) + { if( k > 1 ) + factorial *= k; + for(i = k; i < n; i++) + { // partial w.r.t x[i-k] of x[i-k] * t^k / k! + j = i - k; + fp[ i * n + j ] += 1.0 / Float(factorial); + } + } + } +} +// END C++ + +# endif diff --git a/build-config/cppad/include/cppad/speed/sparse_hes_fun.hpp b/build-config/cppad/include/cppad/speed/sparse_hes_fun.hpp new file mode 100644 index 00000000..bf40dbda --- /dev/null +++ b/build-config/cppad/include/cppad/speed/sparse_hes_fun.hpp @@ -0,0 +1,265 @@ +# ifndef CPPAD_SPEED_SPARSE_HES_FUN_HPP +# define CPPAD_SPEED_SPARSE_HES_FUN_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ +/* +$begin sparse_hes_fun$$ +$spell + hes + cppad + hpp + fp + CppAD + namespace + const + bool + exp + arg +$$ + +$section Evaluate a Function That Has a Sparse Hessian$$ + + +$head Syntax$$ +$codei%# include +%$$ +$codei%sparse_hes_fun(%n%, %x%, %row%, %col%, %p%, %fp%)%$$ + +$head Purpose$$ +This routine evaluates +$latex f(x)$$, $latex f^{(1)} (x)$$, or $latex f^{(2)} (x)$$ +where the Hessian $latex f^{(2)} (x)$$ is sparse. +The function $latex f : \B{R}^n \rightarrow \B{R}$$ only depends on the +size and contents of the index vectors $icode row$$ and $icode col$$. +The non-zero entries in the Hessian of this function have +one of the following forms: +$latex \[ + \DD{f}{x[row[k]]}{x[row[k]]} + \; , \; + \DD{f}{x[row[k]]}{x[col[k]]} + \; , \; + \DD{f}{x[col[k]]}{x[row[k]]} + \; , \; + \DD{f}{x[col[k]]}{x[col[k]]} +\] $$ +for some $latex k $$ between zero and $latex K-1 $$. +All the other terms of the Hessian are zero. + +$head Inclusion$$ +The template function $code sparse_hes_fun$$ +is defined in the $code CppAD$$ namespace by including +the file $code cppad/speed/sparse_hes_fun.hpp$$ +(relative to the CppAD distribution directory). + +$head Float$$ +The type $icode Float$$ must be a $cref NumericType$$. +In addition, if $icode y$$ and $icode z$$ are $icode Float$$ objects, +$codei% + %y% = exp(%z%) +%$$ +must set the $icode y$$ equal the exponential of $icode z$$, i.e., +the derivative of $icode y$$ with respect to $icode z$$ is equal to $icode y$$. + +$head FloatVector$$ +The type $icode FloatVector$$ is any +$cref SimpleVector$$, or it can be a raw pointer, +with elements of type $icode Float$$. + +$head n$$ +The argument $icode n$$ has prototype +$codei% + size_t %n% +%$$ +It specifies the dimension for the domain space for $latex f(x)$$. + +$head x$$ +The argument $icode x$$ has prototype +$codei% + const %FloatVector%& %x% +%$$ +It contains the argument value for which the function, +or its derivative, is being evaluated. +We use $latex n$$ to denote the size of the vector $icode x$$. + +$head row$$ +The argument $icode row$$ has prototype +$codei% + const CppAD::vector& %row% +%$$ +It specifies one of the first +index of $latex x$$ for each non-zero Hessian term +(see $cref/purpose/sparse_hes_fun/Purpose/$$ above). +All the elements of $icode row$$ must be between zero and $icode%n%-1%$$. +The value $latex K$$ is defined by $icode%K% = %row%.size()%$$. + +$head col$$ +The argument $icode col$$ has prototype +$codei% + const CppAD::vector& %col% +%$$ +and its size must be $latex K$$; i.e., the same as for $icode col$$. +It specifies the second +index of $latex x$$ for the non-zero Hessian terms. +All the elements of $icode col$$ must be between zero and $icode%n%-1%$$. +There are no duplicated entries requested, to be specific, +if $icode%k1% != %k2%$$ then +$codei% + ( %row%[%k1%] , %col%[%k1%] ) != ( %row%[%k2%] , %col%[%k2%] ) +%$$ + +$head p$$ +The argument $icode p$$ has prototype +$codei% + size_t %p% +%$$ +It is either zero or two and +specifies the order of the derivative of $latex f$$ +that is being evaluated, i.e., $latex f^{(p)} (x)$$ is evaluated. + +$head fp$$ +The argument $icode fp$$ has prototype +$codei% + %FloatVector%& %fp% +%$$ +The input value of the elements of $icode fp$$ does not matter. + +$subhead Function$$ +If $icode p$$ is zero, $icode fp$$ has size one and +$icode%fp%[0]%$$ is the value of $latex f(x)$$. + +$subhead Hessian$$ +If $icode p$$ is two, $icode fp$$ has size $icode K$$ and +for $latex k = 0 , \ldots , K-1$$, +$latex \[ + \DD{f}{ x[ \R{row}[k] ] }{ x[ \R{col}[k] ]} = fp [k] +\] $$ + +$children% + speed/example/sparse_hes_fun.cpp% + omh/sparse_hes_fun.omh +%$$ + +$head Example$$ +The file +$cref sparse_hes_fun.cpp$$ +contains an example and test of $code sparse_hes_fun.hpp$$. + +$head Source Code$$ +The file +$cref sparse_hes_fun.hpp$$ +contains the source code for this template function. + +$end +------------------------------------------------------------------------------ +*/ +// BEGIN C++ +# include +# include +# include + +// following needed by gcc under fedora 17 so that exp(double) is defined +# include + +namespace CppAD { + template + void sparse_hes_fun( + size_t n , + const FloatVector& x , + const CppAD::vector& row , + const CppAD::vector& col , + size_t p , + FloatVector& fp ) + { + // check numeric type specifications + CheckNumericType(); + + // check value of p + CPPAD_ASSERT_KNOWN( + p == 0 || p == 2, + "sparse_hes_fun: p != 0 and p != 2" + ); + + size_t K = row.size(); + size_t i, j, k; + if( p == 0 ) + fp[0] = Float(0); + else + { for(k = 0; k < K; k++) + fp[k] = Float(0); + } + + // determine which diagonal entries are present in row[k], col[k] + CppAD::vector diagonal(n); + for(i = 0; i < n; i++) + diagonal[i] = K; // no diagonal entry for this row + for(k = 0; k < K; k++) + { if( row[k] == col[k] ) + { CPPAD_ASSERT_UNKNOWN( diagonal[row[k]] == K ); + // index of the diagonal entry + diagonal[ row[k] ] = k; + } + } + + // determine which entries must be multiplied by a factor of two + CppAD::vector factor(K); + for(k = 0; k < K; k++) + { factor[k] = Float(1); + for(size_t k1 = 0; k1 < K; k1++) + { bool reflected = true; + reflected &= k != k1; + reflected &= row[k] != col[k]; + reflected &= row[k] == col[k1]; + reflected &= col[k] == row[k1]; + if( reflected ) + factor[k] = Float(2); + } + } + + Float t; + for(k = 0; k < K; k++) + { i = row[k]; + j = col[k]; + t = exp( x[i] * x[j] ); + switch(p) + { + case 0: + fp[0] += t; + break; + + case 2: + if( i == j ) + { // second partial of t w.r.t. x[i], x[i] + fp[k] += ( Float(2) + Float(4) * x[i] * x[i] ) * t; + } + else // (i != j) + { // + // second partial of t w.r.t x[i], x[j] + fp[k] += factor[k] * ( Float(1) + x[i] * x[j] ) * t; + if( diagonal[i] != K ) + { // second partial of t w.r.t x[i], x[i] + size_t ki = diagonal[i]; + fp[ki] += x[j] * x[j] * t; + } + if( diagonal[j] != K ) + { // second partial of t w.r.t x[j], x[j] + size_t kj = diagonal[j]; + fp[kj] += x[i] * x[i] * t; + } + } + break; + } + } + + } +} +// END C++ +# endif diff --git a/build-config/cppad/include/cppad/speed/sparse_jac_fun.hpp b/build-config/cppad/include/cppad/speed/sparse_jac_fun.hpp new file mode 100644 index 00000000..f1f6e84b --- /dev/null +++ b/build-config/cppad/include/cppad/speed/sparse_jac_fun.hpp @@ -0,0 +1,219 @@ +# ifndef CPPAD_SPEED_SPARSE_JAC_FUN_HPP +# define CPPAD_SPEED_SPARSE_JAC_FUN_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-17 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ +/* +$begin sparse_jac_fun$$ +$spell + Jacobian + jac + cppad + hpp + fp + CppAD + namespace + const + bool + exp + arg +$$ + +$section Evaluate a Function That Has a Sparse Jacobian$$ + + +$head Syntax$$ +$codei%# include +%$$ +$codei%sparse_jac_fun(%m%, %n%, %x%, %row%, %col%, %p%, %fp%)%$$ + +$head Purpose$$ +This routine evaluates +$latex f(x)$$ and $latex f^{(1)} (x)$$ +where the Jacobian $latex f^{(1)} (x)$$ is sparse. +The function $latex f : \B{R}^n \rightarrow \B{R}^m$$ only depends on the +size and contents of the index vectors $icode row$$ and $icode col$$. +The non-zero entries in the Jacobian of this function have +one of the following forms: +$latex \[ + \D{ f[row[k]]}{x[col[k]]} +\] $$ +for some $latex k $$ between zero and $latex K-1$$. +All the other terms of the Jacobian are zero. + +$head Inclusion$$ +The template function $code sparse_jac_fun$$ +is defined in the $code CppAD$$ namespace by including +the file $code cppad/speed/sparse_jac_fun.hpp$$ +(relative to the CppAD distribution directory). + +$head Float$$ +The type $icode Float$$ must be a $cref NumericType$$. +In addition, if $icode y$$ and $icode z$$ are $icode Float$$ objects, +$codei% + %y% = exp(%z%) +%$$ +must set the $icode y$$ equal the exponential of $icode z$$, i.e., +the derivative of $icode y$$ with respect to $icode z$$ is equal to $icode y$$. + +$head FloatVector$$ +The type $icode FloatVector$$ is any +$cref SimpleVector$$, or it can be a raw pointer, +with elements of type $icode Float$$. + +$head n$$ +The argument $icode n$$ has prototype +$codei% + size_t %n% +%$$ +It specifies the dimension for the domain space for $latex f(x)$$. + +$head m$$ +The argument $icode m$$ has prototype +$codei% + size_t %m% +%$$ +It specifies the dimension for the range space for $latex f(x)$$. + +$head x$$ +The argument $icode x$$ has prototype +$codei% + const %FloatVector%& %x% +%$$ +It contains the argument value for which the function, +or its derivative, is being evaluated. +We use $latex n$$ to denote the size of the vector $icode x$$. + +$head row$$ +The argument $icode row$$ has prototype +$codei% + const CppAD::vector& %row% +%$$ +It specifies indices in the range of $latex f(x)$$ for non-zero components +of the Jacobian +(see $cref/purpose/sparse_hes_fun/Purpose/$$ above). +The value $latex K$$ is defined by $icode%K% = %row%.size()%$$. +All the elements of $icode row$$ must be between zero and $icode%m%-1%$$. + +$head col$$ +The argument $icode col$$ has prototype +$codei% + const CppAD::vector& %col% +%$$ +and its size must be $latex K$$; i.e., the same as $icode row$$. +It specifies the component of $latex x$$ for +the non-zero Jacobian terms. +All the elements of $icode col$$ must be between zero and $icode%n%-1%$$. + +$head p$$ +The argument $icode p$$ has prototype +$codei% + size_t %p% +%$$ +It is either zero or one and +specifies the order of the derivative of $latex f$$ +that is being evaluated, i.e., $latex f^{(p)} (x)$$ is evaluated. + +$head fp$$ +The argument $icode fp$$ has prototype +$codei% + %FloatVector%& %fp% +%$$ +If $icode%p% = 0%$$, it size is $icode m$$ +otherwise its size is $icode K$$. +The input value of the elements of $icode fp$$ does not matter. + +$subhead Function$$ +If $icode p$$ is zero, $icode fp$$ has size $latex m$$ and +$codei%(%fp%[0]%, ... , %fp%[%m%-1])%$$ is the value of $latex f(x)$$. + +$subhead Jacobian$$ +If $icode p$$ is one, $icode fp$$ has size $icode K$$ and +for $latex k = 0 , \ldots , K-1$$, +$latex \[ + \D{f[ \R{row}[i] ]}{x[ \R{col}[j] ]} = fp [k] +\] $$ + +$children% + speed/example/sparse_jac_fun.cpp% + omh/sparse_jac_fun.omh +%$$ + +$head Example$$ +The file +$cref sparse_jac_fun.cpp$$ +contains an example and test of $code sparse_jac_fun.hpp$$. + +$head Source Code$$ +The file +$cref sparse_jac_fun.hpp$$ +contains the source code for this template function. + +$end +------------------------------------------------------------------------------ +*/ +// BEGIN C++ +# include +# include +# include + +// following needed by gcc under fedora 17 so that exp(double) is defined +# include + +namespace CppAD { + template + void sparse_jac_fun( + size_t m , + size_t n , + const FloatVector& x , + const CppAD::vector& row , + const CppAD::vector& col , + size_t p , + FloatVector& fp ) + { + // check numeric type specifications + CheckNumericType(); + // check value of p + CPPAD_ASSERT_KNOWN( + p == 0 || p == 1, + "sparse_jac_fun: p != 0 and p != 1" + ); + size_t K = row.size(); + CPPAD_ASSERT_KNOWN( + K >= m, + "sparse_jac_fun: row.size() < m" + ); + size_t i, j, k; + + if( p == 0 ) + for(i = 0; i < m; i++) + fp[i] = Float(0); + + Float t; + for(k = 0; k < K; k++) + { i = row[k]; + j = col[k]; + t = exp( x[j] * x[j] / 2.0 ); + switch(p) + { + case 0: + fp[i] += t; + break; + + case 1: + fp[k] = t * x[j]; + break; + } + } + } +} +// END C++ +# endif diff --git a/build-config/cppad/include/cppad/speed/uniform_01.hpp b/build-config/cppad/include/cppad/speed/uniform_01.hpp new file mode 100644 index 00000000..1ea4b1ce --- /dev/null +++ b/build-config/cppad/include/cppad/speed/uniform_01.hpp @@ -0,0 +1,103 @@ +# ifndef CPPAD_SPEED_UNIFORM_01_HPP +# define CPPAD_SPEED_UNIFORM_01_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-17 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ +/* +$begin uniform_01$$ +$spell + CppAD + namespace + cppad + hpp +$$ + +$section Simulate a [0,1] Uniform Random Variate$$ + + +$head Syntax$$ +$codei%# include +%$$ +$codei%uniform_01(%seed%) +%$$ +$codei%uniform_01(%n%, %x%)%$$ + +$head Purpose$$ +This routine is used to create random values for speed testing purposes. + +$head Inclusion$$ +The template function $code uniform_01$$ is defined in the $code CppAD$$ +namespace by including +the file $code cppad/speed/uniform_01.hpp$$ +(relative to the CppAD distribution directory). + +$head seed$$ +The argument $icode seed$$ has prototype +$codei% + size_t %seed% +%$$ +It specifies a seed +for the uniform random number generator. + +$head n$$ +The argument $icode n$$ has prototype +$codei% + size_t %n% +%$$ +It specifies the number of elements in the random vector $icode x$$. + +$head x$$ +The argument $icode x$$ has prototype +$codei% + %Vector% &%x% +%$$. +The input value of the elements of $icode x$$ does not matter. +Upon return, the elements of $icode x$$ are set to values +randomly sampled over the interval [0,1]. + +$head Vector$$ +If $icode y$$ is a $code double$$ value, +the object $icode x$$ must support the syntax +$codei% + %x%[%i%] = %y% +%$$ +where $icode i$$ has type $code size_t$$ with value less than +or equal $latex n-1$$. +This is the only requirement of the type $icode Vector$$. + +$children% + omh/uniform_01_hpp.omh +%$$ + +$head Source Code$$ +The file +$cref uniform_01.hpp$$ +constraints the source code for this template function. + +$end +------------------------------------------------------------------------------ +*/ +// BEGIN C++ +# include + +namespace CppAD { + inline void uniform_01(size_t seed) + { std::srand( (unsigned int) seed); } + + template + void uniform_01(size_t n, Vector &x) + { static double factor = 1. / double(RAND_MAX); + while(n--) + x[n] = std::rand() * factor; + } +} +// END C++ +# endif diff --git a/build-config/cppad/include/cppad/utility.hpp b/build-config/cppad/include/cppad/utility.hpp new file mode 100644 index 00000000..01c96a15 --- /dev/null +++ b/build-config/cppad/include/cppad/utility.hpp @@ -0,0 +1,52 @@ +# ifndef CPPAD_UTILITY_HPP +# define CPPAD_UTILITY_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ +// BEGIN_SORT_THIS_LINE_PLUS_1 +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +// END_SORT_THIS_LINE_MINUS_1 + +# if CPPAD_HAS_EIGEN +# include +# endif + +# endif diff --git a/build-config/cppad/include/cppad/utility/check_numeric_type.hpp b/build-config/cppad/include/cppad/utility/check_numeric_type.hpp new file mode 100644 index 00000000..32488771 --- /dev/null +++ b/build-config/cppad/include/cppad/utility/check_numeric_type.hpp @@ -0,0 +1,174 @@ +# ifndef CPPAD_UTILITY_CHECK_NUMERIC_TYPE_HPP +# define CPPAD_UTILITY_CHECK_NUMERIC_TYPE_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ +/* +$begin CheckNumericType$$ +$spell + alloc + cppad.hpp + CppAD +$$ + +$section Check NumericType Class Concept$$ + + +$head Syntax$$ +$codei%# include +%$$ +$codei%CheckNumericType<%NumericType%>()%$$ + + +$head Purpose$$ +The syntax +$codei% + CheckNumericType<%NumericType%>() +%$$ +preforms compile and run time checks that the type specified +by $icode NumericType$$ satisfies all the requirements for +a $cref NumericType$$ class. +If a requirement is not satisfied, +a an error message makes it clear what condition is not satisfied. + +$head Include$$ +The file $code cppad/utility/check_numeric_type.hpp$$ +is included by $code cppad/cppad.hpp$$ +but it can also be included separately with out the rest +if the CppAD include files. + +$head Parallel Mode$$ +The routine $cref/thread_alloc::parallel_setup/ta_parallel_setup/$$ +must be called before it +can be used in $cref/parallel/ta_in_parallel/$$ mode. + +$head Example$$ +$children% + example/utility/check_numeric_type.cpp +%$$ +The file $cref check_numeric_type.cpp$$ +contains an example and test of this function. +The comments in this example suggest a way to change the example +so an error message occurs. + +$end +--------------------------------------------------------------------------- +*/ + +# include +# include + +namespace CppAD { + +# ifdef NDEBUG + template + void CheckNumericType(void) + { } +# else + template + NumericType CheckNumericType(void) + { // Section 3.6.2 of ISO/IEC 14882:1998(E) states: "The storage for + // objects with static storage duration (3.7.1) shall be zero- + // initialized (8.5) before any other initialization takes place." + static size_t count[CPPAD_MAX_NUM_THREADS]; + size_t thread = thread_alloc::thread_num(); + if( count[thread] > 0 ) + return NumericType(0); + count[thread]++; + /* + contructors + */ + NumericType check_NumericType_default_constructor; + NumericType check_NumericType_constructor_from_int(1); + + const NumericType x(1); + + NumericType check_NumericType_copy_constructor(x); + + // assignment + NumericType check_NumericType_assignment; + check_NumericType_assignment = x; + + /* + unary operators + */ + const NumericType check_NumericType_unary_plus(1); + NumericType check_NumericType_unary_plus_result = + + check_NumericType_unary_plus; + + const NumericType check_NumericType_unary_minus(1); + NumericType check_NumericType_unary_minus_result = + - check_NumericType_unary_minus; + + /* + binary operators + */ + const NumericType check_NumericType_binary_addition(1); + NumericType check_NumericType_binary_addition_result = + check_NumericType_binary_addition + x; + + const NumericType check_NumericType_binary_subtraction(1); + NumericType check_NumericType_binary_subtraction_result = + check_NumericType_binary_subtraction - x; + + const NumericType check_NumericType_binary_multiplication(1); + NumericType check_NumericType_binary_multiplication_result = + check_NumericType_binary_multiplication * x; + + const NumericType check_NumericType_binary_division(1); + NumericType check_NumericType_binary_division_result = + check_NumericType_binary_division / x; + + /* + compound assignment operators + */ + NumericType + check_NumericType_computed_assignment_addition(1); + check_NumericType_computed_assignment_addition += x; + + NumericType + check_NumericType_computed_assignment_subtraction(1); + check_NumericType_computed_assignment_subtraction -= x; + + NumericType + check_NumericType_computed_assignment_multiplication(1); + check_NumericType_computed_assignment_multiplication *= x; + + NumericType + check_NumericType_computed_assignment_division(1); + check_NumericType_computed_assignment_division /= x; + + /* + use all values so as to avoid warnings + */ + check_NumericType_default_constructor = x; + return + + check_NumericType_default_constructor + + check_NumericType_constructor_from_int + + check_NumericType_copy_constructor + + check_NumericType_assignment + + check_NumericType_unary_plus_result + + check_NumericType_unary_minus_result + + check_NumericType_binary_addition_result + + check_NumericType_binary_subtraction_result + + check_NumericType_binary_multiplication_result + + check_NumericType_binary_division_result + + check_NumericType_computed_assignment_addition + + check_NumericType_computed_assignment_subtraction + + check_NumericType_computed_assignment_multiplication + + check_NumericType_computed_assignment_division + ; + } +# endif + +} // end namespace CppAD + +# endif diff --git a/build-config/cppad/include/cppad/utility/check_simple_vector.hpp b/build-config/cppad/include/cppad/utility/check_simple_vector.hpp new file mode 100644 index 00000000..638ada3e --- /dev/null +++ b/build-config/cppad/include/cppad/utility/check_simple_vector.hpp @@ -0,0 +1,199 @@ +# ifndef CPPAD_UTILITY_CHECK_SIMPLE_VECTOR_HPP +# define CPPAD_UTILITY_CHECK_SIMPLE_VECTOR_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ +/* +$begin CheckSimpleVector$$ +$spell + alloc + const + cppad.hpp + CppAD +$$ + +$section Check Simple Vector Concept$$ + + +$head Syntax$$ +$codei%# include +%$$ +$codei%CheckSimpleVector<%Scalar%, %Vector%>()%$$ +$pre +$$ +$codei%CheckSimpleVector<%Scalar%, %Vector%>(%x%, %y%)%$$ + + +$head Purpose$$ +Preforms compile and run time checks that the type specified +by $icode Vector$$ satisfies all the requirements for +a $cref SimpleVector$$ class with +$cref/elements of type/SimpleVector/Elements of Specified Type/$$ +$icode Scalar$$. +If a requirement is not satisfied, +a an error message makes it clear what condition is not satisfied. + +$head x, y$$ +If the arguments $icode x$$ and $icode y$$ are present, +they have prototype +$codei% + const %Scalar%& %x% + const %Scalar%& %y% +%$$ +In addition, the check +$codei% + %x% == %x% +%$$ +will return the boolean value $code true$$, and +$codei% + %x% == %y% +%$$ +will return $code false$$. + +$head Restrictions$$ +If the arguments $icode x$$ and $icode y$$ are not present, +the following extra assumption is made by $code CheckSimpleVector$$: +If $icode x$$ is a $icode Scalar$$ object +$codei% + %x% = 0 + %y% = 1 +%$$ +assigns values to the objects $icode x$$ and $icode y$$. +In addition, +$icode%x% == %x%$$ would return the boolean value $code true$$ and +$icode%x% == %y%$$ would return $code false$$. + +$head Include$$ +The file $code cppad/utility/check_simple_vector.hpp$$ +is included by $code cppad/cppad.hpp$$ +but it can also be included separately with out the rest +if the CppAD include files. + +$head Parallel Mode$$ +The routine $cref/thread_alloc::parallel_setup/ta_parallel_setup/$$ +must be called before it +can be used in $cref/parallel/ta_in_parallel/$$ mode. + +$head Example$$ +$children% + example/utility/check_simple_vector.cpp +%$$ +The file $cref check_simple_vector.cpp$$ +contains an example and test of this function where $icode S$$ +is the same as $icode T$$. +The comments in this example suggest a way to change the example +so $icode S$$ is not the same as $icode T$$. + +$end +--------------------------------------------------------------------------- +*/ + +# include +# include +# include +# include + +namespace CppAD { + +# ifdef NDEBUG + template + inline void CheckSimpleVector(const Scalar& x, const Scalar& y) + { } + template + inline void CheckSimpleVector(void) + { } +# else + template + struct ok_if_S_same_as_T { }; + + template + struct ok_if_S_same_as_T { T value; }; + + template + void CheckSimpleVector(const Scalar& x, const Scalar& y) + { CPPAD_ASSERT_FIRST_CALL_NOT_PARALLEL + static size_t count; + if( count > 0 ) + return; + count++; + + // value_type must be type of elements of Vector + typedef typename Vector::value_type value_type; + + // check that elements of Vector have type Scalar + struct ok_if_S_same_as_T x_copy; + x_copy.value = x; + + // check default constructor + Vector d; + + // size member function + CPPAD_ASSERT_KNOWN( + d.size() == 0, + "default construtor result does not have size zero" + ); + + // resize to same size as other vectors in test + d.resize(1); + + // check sizing constructor + Vector s(1); + + // check element assignment + s[0] = y; + CPPAD_ASSERT_KNOWN( + s[0] == y, + "element assignment failed" + ); + + // check copy constructor + s[0] = x_copy.value; + const Vector c(s); + s[0] = y; + CPPAD_ASSERT_KNOWN( + c[0] == x, + "copy constructor is shallow" + ); + + // vector assignment operator + d[0] = x; + s = d; + s[0] = y; + CPPAD_ASSERT_KNOWN( + d[0] == x, + "assignment operator is shallow" + ); + + // element access, right side const + // element assignment, left side not const + d[0] = c[0]; + CPPAD_ASSERT_KNOWN( + d[0] == x, + "element assignment from const failed" + ); + } + template + void CheckSimpleVector(void) + { Scalar x; + Scalar y; + + // use assignment and not constructor + x = 0; + y = 1; + + CheckSimpleVector(x, y); + } + +# endif + +} // end namespace CppAD + +# endif diff --git a/build-config/cppad/include/cppad/utility/elapsed_seconds.hpp b/build-config/cppad/include/cppad/utility/elapsed_seconds.hpp new file mode 100644 index 00000000..4e689014 --- /dev/null +++ b/build-config/cppad/include/cppad/utility/elapsed_seconds.hpp @@ -0,0 +1,121 @@ +# ifndef CPPAD_UTILITY_ELAPSED_SECONDS_HPP +# define CPPAD_UTILITY_ELAPSED_SECONDS_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +/* +$begin elapsed_seconds$$ +$spell + cppad.hpp + Microsoft + gettimeofday + std + chrono +$$ + +$section Returns Elapsed Number of Seconds$$ + + +$head Syntax$$ +$codei%# include +%$$ +$icode%s% = elapsed_seconds()%$$ + +$head Purpose$$ +This routine is accurate to within .02 seconds +(see $cref elapsed_seconds.cpp$$). +It does not necessary work for time intervals that are greater than a day. +$list number$$ +If the C++11 $code std::chrono::steady_clock$$ is available, +it will be used for timing. +$lnext +Otherwise, if running under the Microsoft compiler, +$code ::GetSystemTime$$ will be used for timing. +$lnext +Otherwise, if $code gettimeofday$$ is available, it is used for timing. +$lnext +Otherwise, $code std::clock()$$ will be used for timing. +$lend + +$head s$$ +is a $code double$$ equal to the +number of seconds since the first call to $code elapsed_seconds$$. + +$children% + speed/example/elapsed_seconds.cpp +%$$ +$head Example$$ +The routine $cref elapsed_seconds.cpp$$ is +an example and test of this routine. + + +$end +----------------------------------------------------------------------- +*/ + +// For some unknown reason under Fedora (which needs to be understood), +// if you move this include for cppad_assert.hpp below include for define.hpp, +// cd work/speed/example +// make test.sh +// fails with the error message 'gettimeofday' not defined. +# include + +// define nullptr +# include + +// needed before one can use CPPAD_ASSERT_FIRST_CALL_NOT_PARALLEL +# include + +// c++11 time function +# include + + + +namespace CppAD { // BEGIN_CPPAD_NAMESPACE +/*! +\file elapsed_seconds.hpp +\brief Function that returns the elapsed seconds from first call. +*/ + +/*! +Returns the elapsed number since the first call to this function. + +This routine tries is accurate to within .02 seconds. +It does not necessary work for time intervals that are less than a day. +\li +If running under the Microsoft system, it uses ::%GetSystemTime for timing. +\li +Otherwise, if gettimeofday is available, it is used. +\li +Otherwise, std::clock() is used. + +\return +The number of seconds since the first call to elapsed_seconds. +*/ +inline double elapsed_seconds(void) +// -------------------------------------------------------------------------- +{ CPPAD_ASSERT_FIRST_CALL_NOT_PARALLEL; + static bool first_ = true; + static std::chrono::time_point start_; + if( first_ ) + { start_ = std::chrono::steady_clock::now(); + first_ = false; + return 0.0; + } + std::chrono::time_point now; + now = std::chrono::steady_clock::now(); + std::chrono::duration difference = now - start_; + return difference.count(); +} +// -------------------------------------------------------------------------- +} // END_CPPAD_NAMESPACE +# endif diff --git a/build-config/cppad/include/cppad/utility/error_handler.hpp b/build-config/cppad/include/cppad/utility/error_handler.hpp new file mode 100644 index 00000000..cc45afe4 --- /dev/null +++ b/build-config/cppad/include/cppad/utility/error_handler.hpp @@ -0,0 +1,235 @@ +# ifndef CPPAD_UTILITY_ERROR_HANDLER_HPP +# define CPPAD_UTILITY_ERROR_HANDLER_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +/* +$begin ErrorHandler$$ +$spell + cppad.hpp + CppAD + exp + bool + const +$$ + +$section Replacing the CppAD Error Handler$$ + +$head Syntax$$ +$codei%# include +%$$ +$codei%ErrorHandler %info%(%handler%) +%$$ +$codei%ErrorHandler::Call(%known%, %line%, %file%, %exp%, %msg%) +%$$ + +$head Constructor$$ +When you construct a $code ErrorHandler$$ object, +the current CppAD error handler is replaced by $icode handler$$. +When the object is destructed, the previous CppAD error handler is restored. + +$subhead Parallel Mode$$ +The $code ErrorHandler$$ constructor and destructor cannot be called in +$cref/parallel/ta_in_parallel/$$ execution mode. +If this rule is not abided by, a raw C++ $code assert$$, +instead of one that uses this error handler, will be generated. + +$head Call$$ +When $code ErrorHandler::Call$$ is called, +the current CppAD error handler is used to report an error. +This starts out as a default error handler and can be replaced +using the $code ErrorHandler$$ constructor. + +$head info$$ +The object $icode info$$ is used to store information +that is necessary to restore the previous CppAD error handler. +This restoration is done when the destructor for $icode info$$ is called. + + +$head handler$$ +The argument $icode handler$$ has prototype +$codei% + void (*%handler%) + (bool, int, const char *, const char *, const char *); +%$$ +When an error is detected, +it is called with the syntax +$codei% + %handler% (%known%, %line%, %file%, %exp%, %msg%) +%$$ +This routine should not return; i.e., upon detection of the error, +the routine calling $icode handler$$ does not know how to proceed. + +$head known$$ +The $icode handler$$ argument $icode known$$ has prototype +$codei% + bool %known% +%$$ +If it is true, the error being reported is from a know problem. + +$head line$$ +The $icode handler$$ argument $icode line$$ has prototype +$codei% + int %line% +%$$ +It reports the source code line number where the error is detected. + +$head file$$ +The $icode handler$$ argument $icode file$$ has prototype +$codei% + const char *%file% +%$$ +and is a $code '\0'$$ terminated character vector. +It reports the source code file where the error is detected. + +$head exp$$ +The $icode handler$$ argument $icode exp$$ has prototype +$codei% + const char *%exp% +%$$ +and is a $code '\0'$$ terminated character vector. +It is a source code boolean expression that should have been true, +but is false, +and thereby causes this call to $icode handler$$. + +$head msg$$ +The $icode handler$$ argument $icode msg$$ has prototype +$codei% + const char *%msg% +%$$ +and is a $code '\0'$$ terminated character vector. +It reports the meaning of the error from the C++ programmers point of view. + +$children% + example/utility/error_handler.cpp% + include/cppad/core/cppad_assert.hpp +%$$ +$head Example$$ +The file +$cref error_handler.cpp$$ +contains an example and test a test of using this routine. + +$end +--------------------------------------------------------------------------- +*/ + +# include + +# include +# include +# include +# include + +namespace CppAD { // BEGIN CppAD namespace + +class ErrorHandler { + template + friend void parallel_ad(void); +public: + typedef void (*Handler) + (bool, int, const char *, const char *, const char *); + + // construct a new handler + ErrorHandler(Handler handler) : previous( Current() ) + { if( local::set_get_in_parallel(0) ) + { bool known = true; + int line = __LINE__; + const char* file = __FILE__; + const char* exp = "! local::set_get_in_parallel(0)"; + const char* msg = + "Using ErrorHandler constructor in parallel mode."; + Call(known, line, file, exp, msg); + } + Current() = handler; + } + + // destructor for an error handler + ~ErrorHandler(void) + { if( local::set_get_in_parallel(0) ) + { bool known = true; + int line = __LINE__; + const char* file = __FILE__; + const char* exp = "! local::set_get_in_parallel(0)"; + const char* msg = + "Using ErrorHandler destructor in parallel mode."; + Call(known, line, file, exp, msg); + } + Current() = previous; + } + + // report an error + static void Call( + bool known, + int line , + const char *file , + const char *exp , + const char *msg ) + { Handler handler = Current(); + handler(known, line, file, exp, msg); + } + +private: + const Handler previous; + + // The default error handler + static void Default( + bool known, + int line , + const char *file , + const char *exp , + const char *msg ) + { using std::cerr; + using std::endl; + + cerr << CPPAD_PACKAGE_STRING; + if( known ) + cerr << " error from a known source:" << endl; + else + cerr << " error from unknown source" << endl; + if( msg[0] != '\0' ) + cerr << msg << endl; + cerr << "Error detected by false result for" << endl; + cerr << " " << exp << endl; + cerr << "at line " << line << " in the file " << endl; + cerr << " " << file << endl; + + // terminate program execution + assert(false); + + // termination when NDEBUG is defined + std::exit(1); + } + + // current error handler + static Handler &Current(void) + { static bool first_call = true; + static Handler current = Default; + if( first_call ) + { if( local::set_get_in_parallel(0) ) + { bool known = false; + int line = __LINE__; + const char* file = __FILE__; + const char* exp = ""; + const char* msg = ""; + Call(known, line, file, exp, msg); + } + first_call = false; + } + return current; + } +}; + +} // END CppAD namespace + + + +# endif diff --git a/build-config/cppad/include/cppad/utility/index_sort.hpp b/build-config/cppad/include/cppad/utility/index_sort.hpp new file mode 100644 index 00000000..983d396d --- /dev/null +++ b/build-config/cppad/include/cppad/utility/index_sort.hpp @@ -0,0 +1,177 @@ +# ifndef CPPAD_UTILITY_INDEX_SORT_HPP +# define CPPAD_UTILITY_INDEX_SORT_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-18 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +/* +$begin index_sort$$ +$spell + cppad.hpp + ind + const +$$ + +$section Returns Indices that Sort a Vector$$ + + +$head Syntax$$ +$codei%# include +%$$ +$codei%index_sort(%keys%, %ind%)%$$ + +$head keys$$ +The argument $icode keys$$ has prototype +$codei% + const %KeyVector%& %keys% +%$$ +where $icode KeyVector$$ is +a $cref SimpleVector$$ class with elements that support the $code <$$ +operation. + +$head ind$$ +The argument $icode ind$$ has prototype +$codei% + %SizeVector%& %ind% +%$$ +where $icode SizeVector$$ is +a $cref SimpleVector$$ class with elements of type $code size_t$$. +The routine $cref CheckSimpleVector$$ will generate an error message +if this is not the case. + +$subhead Input$$ +The size of $icode ind$$ must be the same as the size of $icode keys$$ +and the value of its input elements does not matter. + +$subhead Return$$ +Upon return, $icode ind$$ is a permutation of the set of indices +that yields increasing order for $icode keys$$. +In other words, for all $icode%i% != %j%$$, +$codei% + %ind%[%i%] != %ind%[%j%] +%$$ +and for $icode%i% = 0 , %...% , %size%-2%$$, +$codei% + ( %keys%[ %ind%[%i%+1] ] < %keys%[ %ind%[%i%] ] ) == false +%$$ + + +$head Example$$ +$children% + example/utility/index_sort.cpp +%$$ +The file $cref index_sort.cpp$$ contains an example +and test of this routine. +It return true if it succeeds and false otherwise. + +$end +*/ +# include +# include +# include +# include + +namespace CppAD { // BEGIN_CPPAD_NAMESPACE +/*! +\file index_sort.hpp +File used to implement the CppAD index sort utility +*/ + +/*! +Helper class used by index_sort +*/ +template +class index_sort_element { +private: + /// key used to determine position of this element + Compare key_; + /// index vlaue corresponding to this key + size_t index_; +public: + /// operator requried by std::sort + bool operator<(const index_sort_element& other) const + { return key_ < other.key_; } + /// set the key for this element + void set_key(const Compare& value) + { key_ = value; } + /// set the index for this element + void set_index(const size_t& index) + { index_ = index; } + /// get the key for this element + Compare get_key(void) const + { return key_; } + /// get the index for this element + size_t get_index(void) const + { return index_; } +}; + +/*! +Compute the indices that sort a vector of keys + +\tparam KeyVector +Simple vector type that deterimene the sorting order by < operator +on its elements. + +\tparam SizeVector +Simple vector type with elements of size_t +that is used to return index values. + +\param keys [in] +values that determine the sorting order. + +\param ind [out] +must have the same size as keys. +The input value of its elements does not matter. +The output value of its elements satisfy +\code +( keys[ ind[i] ] < keys[ ind[i+1] ] ) == false +\endcode +*/ +template +void index_sort(const KeyVector& keys, SizeVector& ind) +{ typedef typename KeyVector::value_type Compare; + CheckSimpleVector(); + + typedef index_sort_element element; + + CPPAD_ASSERT_KNOWN( + size_t(keys.size()) == size_t(ind.size()), + "index_sort: vector sizes do not match" + ); + + size_t size_work = size_t(keys.size()); + size_t size_out; + element* work = + thread_alloc::create_array(size_work, size_out); + + // copy initial order into work + size_t i; + for(i = 0; i < size_work; i++) + { work[i].set_key( keys[i] ); + work[i].set_index( i ); + } + + // sort the work array + std::sort(work, work+size_work); + + // copy the indices to the output vector + for(i = 0; i < size_work; i++) + ind[i] = work[i].get_index(); + + // we are done with this work array + thread_alloc::delete_array(work); + + return; +} + +} // END_CPPAD_NAMESPACE + +# endif diff --git a/build-config/cppad/include/cppad/utility/lu_factor.hpp b/build-config/cppad/include/cppad/utility/lu_factor.hpp new file mode 100644 index 00000000..2e6fd8fc --- /dev/null +++ b/build-config/cppad/include/cppad/utility/lu_factor.hpp @@ -0,0 +1,392 @@ +# ifndef CPPAD_UTILITY_LU_FACTOR_HPP +# define CPPAD_UTILITY_LU_FACTOR_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +/* +$begin LuFactor$$ +$spell + cppad.hpp + Cpp + Geq + Lu + bool + const + ip + jp + namespace + std + typename +$$ + + +$section LU Factorization of A Square Matrix$$ + +$pre +$$ + +$head Syntax$$ +$codei%# include +%$$ +$icode%sign% = LuFactor(%ip%, %jp%, %LU%)%$$ + + +$head Description$$ +Computes an LU factorization of the matrix $icode A$$ +where $icode A$$ is a square matrix. + +$head Include$$ +The file $code cppad/utility/lu_factor.hpp$$ +is included by $code cppad/cppad.hpp$$ +but it can also be included separately with out the rest of +the $code CppAD$$ routines. + +$head Matrix Storage$$ +All matrices are stored in row major order. +To be specific, if $latex Y$$ is a vector +that contains a $latex p$$ by $latex q$$ matrix, +the size of $latex Y$$ must be equal to $latex p * q $$ and for +$latex i = 0 , \ldots , p-1$$, +$latex j = 0 , \ldots , q-1$$, +$latex \[ + Y_{i,j} = Y[ i * q + j ] +\] $$ + +$head sign$$ +The return value $icode sign$$ has prototype +$codei% + int %sign% +%$$ +If $icode A$$ is invertible, $icode sign$$ is plus or minus one +and is the sign of the permutation corresponding to the row ordering +$icode ip$$ and column ordering $icode jp$$. +If $icode A$$ is not invertible, $icode sign$$ is zero. + +$head ip$$ +The argument $icode ip$$ has prototype +$codei% + %SizeVector% &%ip% +%$$ +(see description of $cref/SizeVector/LuFactor/SizeVector/$$ below). +The size of $icode ip$$ is referred to as $icode n$$ in the +specifications below. +The input value of the elements of $icode ip$$ does not matter. +The output value of the elements of $icode ip$$ determine +the order of the rows in the permuted matrix. + +$head jp$$ +The argument $icode jp$$ has prototype +$codei% + %SizeVector% &%jp% +%$$ +(see description of $cref/SizeVector/LuFactor/SizeVector/$$ below). +The size of $icode jp$$ must be equal to $icode n$$. +The input value of the elements of $icode jp$$ does not matter. +The output value of the elements of $icode jp$$ determine +the order of the columns in the permuted matrix. + +$head LU$$ +The argument $icode LU$$ has the prototype +$codei% + %FloatVector% &%LU% +%$$ +and the size of $icode LU$$ must equal $latex n * n$$ +(see description of $cref/FloatVector/LuFactor/FloatVector/$$ below). + +$subhead A$$ +We define $icode A$$ as the matrix corresponding to the input +value of $icode LU$$. + +$subhead P$$ +We define the permuted matrix $icode P$$ in terms of $icode A$$ by +$codei% + %P%(%i%, %j%) = %A%[ %ip%[%i%] * %n% + %jp%[%j%] ] +%$$ + +$subhead L$$ +We define the lower triangular matrix $icode L$$ in terms of the +output value of $icode LU$$. +The matrix $icode L$$ is zero above the diagonal +and the rest of the elements are defined by +$codei% + %L%(%i%, %j%) = %LU%[ %ip%[%i%] * %n% + %jp%[%j%] ] +%$$ +for $latex i = 0 , \ldots , n-1$$ and $latex j = 0 , \ldots , i$$. + +$subhead U$$ +We define the upper triangular matrix $icode U$$ in terms of the +output value of $icode LU$$. +The matrix $icode U$$ is zero below the diagonal, +one on the diagonal, +and the rest of the elements are defined by +$codei% + %U%(%i%, %j%) = %LU%[ %ip%[%i%] * %n% + %jp%[%j%] ] +%$$ +for $latex i = 0 , \ldots , n-2$$ and $latex j = i+1 , \ldots , n-1$$. + +$subhead Factor$$ +If the return value $icode sign$$ is non-zero, +$codei% + %L% * %U% = %P% +%$$ +If the return value of $icode sign$$ is zero, +the contents of $icode L$$ and $icode U$$ are not defined. + +$subhead Determinant$$ +If the return value $icode sign$$ is zero, +the determinant of $icode A$$ is zero. +If $icode sign$$ is non-zero, +using the output value of $icode LU$$ +the determinant of the matrix $icode A$$ is equal to +$codei% +%sign% * %LU%[%ip%[0], %jp%[0]] * %...% * %LU%[%ip%[%n%-1], %jp%[%n%-1]] +%$$ + +$head SizeVector$$ +The type $icode SizeVector$$ must be a $cref SimpleVector$$ class with +$cref/elements of type size_t/SimpleVector/Elements of Specified Type/$$. +The routine $cref CheckSimpleVector$$ will generate an error message +if this is not the case. + +$head FloatVector$$ +The type $icode FloatVector$$ must be a +$cref/simple vector class/SimpleVector/$$. +The routine $cref CheckSimpleVector$$ will generate an error message +if this is not the case. + +$head Float$$ +This notation is used to denote the type corresponding +to the elements of a $icode FloatVector$$. +The type $icode Float$$ must satisfy the conditions +for a $cref NumericType$$ type. +The routine $cref CheckNumericType$$ will generate an error message +if this is not the case. +In addition, the following operations must be defined for any pair +of $icode Float$$ objects $icode x$$ and $icode y$$: + +$table +$bold Operation$$ $cnext $bold Description$$ $rnext +$codei%log(%x%)%$$ $cnext + returns the logarithm of $icode x$$ as a $icode Float$$ object +$tend + +$head AbsGeq$$ +Including the file $code lu_factor.hpp$$ defines the template function +$codei% + template + bool AbsGeq<%Float%>(const %Float% &%x%, const %Float% &%y%) +%$$ +in the $code CppAD$$ namespace. +This function returns true if the absolute value of +$icode x$$ is greater than or equal the absolute value of $icode y$$. +It is used by $code LuFactor$$ to choose the pivot elements. +This template function definition uses the operator +$code <=$$ to obtain the absolute value for $icode Float$$ objects. +If this operator is not defined for your use of $icode Float$$, +you will need to specialize this template so that it works for your +use of $code LuFactor$$. +$pre + +$$ +Complex numbers do not have the operation $code <=$$ defined. +The specializations +$codei% +bool AbsGeq< std::complex > + (const std::complex &%x%, const std::complex &%y%) +bool AbsGeq< std::complex > + (const std::complex &%x%, const std::complex &%y%) +%$$ +are define by including $code lu_factor.hpp$$ +These return true if the sum of the square of the real and imaginary parts +of $icode x$$ is greater than or equal the +sum of the square of the real and imaginary parts of $icode y$$. + +$children% + example/utility/lu_factor.cpp% + omh/lu_factor_hpp.omh +%$$ +$head Example$$ +The file +$cref lu_factor.cpp$$ +contains an example and test of using $code LuFactor$$ by itself. +$pre + +$$ +The file $cref lu_solve.hpp$$ provides a useful example usage of +$code LuFactor$$ with $code LuInvert$$. + +$head Source$$ +The file $cref lu_factor.hpp$$ contains the +current source code that implements these specifications. + +$end +-------------------------------------------------------------------------- +*/ +// BEGIN C++ + +# include +# include + +# include +# include +# include + +namespace CppAD { // BEGIN CppAD namespace + +// AbsGeq +template +bool AbsGeq(const Float &x, const Float &y) +{ Float xabs = x; + if( xabs <= Float(0) ) + xabs = - xabs; + Float yabs = y; + if( yabs <= Float(0) ) + yabs = - yabs; + return xabs >= yabs; +} +inline bool AbsGeq( + const std::complex &x, + const std::complex &y) +{ double xsq = x.real() * x.real() + x.imag() * x.imag(); + double ysq = y.real() * y.real() + y.imag() * y.imag(); + + return xsq >= ysq; +} +inline bool AbsGeq( + const std::complex &x, + const std::complex &y) +{ float xsq = x.real() * x.real() + x.imag() * x.imag(); + float ysq = y.real() * y.real() + y.imag() * y.imag(); + + return xsq >= ysq; +} + +// Lines that are different from code in cppad/core/lu_ratio.hpp end with // +template // +int LuFactor(SizeVector &ip, SizeVector &jp, FloatVector &LU) // +{ + // type of the elements of LU // + typedef typename FloatVector::value_type Float; // + + // check numeric type specifications + CheckNumericType(); + + // check simple vector class specifications + CheckSimpleVector(); + CheckSimpleVector(); + + size_t i, j; // some temporary indices + const Float zero( 0 ); // the value zero as a Float object + size_t imax; // row index of maximum element + size_t jmax; // column indx of maximum element + Float emax; // maximum absolute value + size_t p; // count pivots + int sign; // sign of the permutation + Float etmp; // temporary element + Float pivot; // pivot element + + // ------------------------------------------------------- + size_t n = ip.size(); + CPPAD_ASSERT_KNOWN( + size_t(jp.size()) == n, + "Error in LuFactor: jp must have size equal to n" + ); + CPPAD_ASSERT_KNOWN( + size_t(LU.size()) == n * n, + "Error in LuFactor: LU must have size equal to n * m" + ); + // ------------------------------------------------------- + + // initialize row and column order in matrix not yet pivoted + for(i = 0; i < n; i++) + { ip[i] = i; + jp[i] = i; + } + // initialize the sign of the permutation + sign = 1; + // --------------------------------------------------------- + + // Reduce the matrix P to L * U using n pivots + for(p = 0; p < n; p++) + { // determine row and column corresponding to element of + // maximum absolute value in remaining part of P + imax = jmax = n; + emax = zero; + for(i = p; i < n; i++) + { for(j = p; j < n; j++) + { CPPAD_ASSERT_UNKNOWN( + (ip[i] < n) & (jp[j] < n) + ); + etmp = LU[ ip[i] * n + jp[j] ]; + + // check if maximum absolute value so far + if( AbsGeq (etmp, emax) ) + { imax = i; + jmax = j; + emax = etmp; + } + } + } + CPPAD_ASSERT_KNOWN( + (imax < n) & (jmax < n) , + "LuFactor can't determine an element with " + "maximum absolute value.\n" + "Perhaps original matrix contains not a number or infinity.\n" + "Perhaps your specialization of AbsGeq is not correct." + ); + if( imax != p ) + { // switch rows so max absolute element is in row p + i = ip[p]; + ip[p] = ip[imax]; + ip[imax] = i; + sign = -sign; + } + if( jmax != p ) + { // switch columns so max absolute element is in column p + j = jp[p]; + jp[p] = jp[jmax]; + jp[jmax] = j; + sign = -sign; + } + // pivot using the max absolute element + pivot = LU[ ip[p] * n + jp[p] ]; + + // check for determinant equal to zero + if( pivot == zero ) + { // abort the mission + return 0; + } + + // Reduce U by the elementary transformations that maps + // LU( ip[p], jp[p] ) to one. Only need transform elements + // above the diagonal in U and LU( ip[p] , jp[p] ) is + // corresponding value below diagonal in L. + for(j = p+1; j < n; j++) + LU[ ip[p] * n + jp[j] ] /= pivot; + + // Reduce U by the elementary transformations that maps + // LU( ip[i], jp[p] ) to zero. Only need transform elements + // above the diagonal in U and LU( ip[i], jp[p] ) is + // corresponding value below diagonal in L. + for(i = p+1; i < n; i++ ) + { etmp = LU[ ip[i] * n + jp[p] ]; + for(j = p+1; j < n; j++) + { LU[ ip[i] * n + jp[j] ] -= + etmp * LU[ ip[p] * n + jp[j] ]; + } + } + } + return sign; +} +} // END CppAD namespace +// END C++ +# endif diff --git a/build-config/cppad/include/cppad/utility/lu_invert.hpp b/build-config/cppad/include/cppad/utility/lu_invert.hpp new file mode 100644 index 00000000..746d5336 --- /dev/null +++ b/build-config/cppad/include/cppad/utility/lu_invert.hpp @@ -0,0 +1,238 @@ +# ifndef CPPAD_UTILITY_LU_INVERT_HPP +# define CPPAD_UTILITY_LU_INVERT_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +/* +$begin LuInvert$$ +$spell + cppad.hpp + Lu + Cpp + jp + ip + const + namespace + typename + etmp +$$ + + +$section Invert an LU Factored Equation$$ + +$pre +$$ + +$head Syntax$$ +$codei%# include +%$$ +$codei%LuInvert(%ip%, %jp%, %LU%, %X%)%$$ + + +$head Description$$ +Solves the matrix equation $icode%A% * %X% = %B%$$ +using an LU factorization computed by $cref LuFactor$$. + +$head Include$$ +The file $code cppad/utility/lu_invert.hpp$$ +is included by $code cppad/cppad.hpp$$ +but it can also be included separately with out the rest of +the $code CppAD$$ routines. + +$head Matrix Storage$$ +All matrices are stored in row major order. +To be specific, if $latex Y$$ is a vector +that contains a $latex p$$ by $latex q$$ matrix, +the size of $latex Y$$ must be equal to $latex p * q $$ and for +$latex i = 0 , \ldots , p-1$$, +$latex j = 0 , \ldots , q-1$$, +$latex \[ + Y_{i,j} = Y[ i * q + j ] +\] $$ + +$head ip$$ +The argument $icode ip$$ has prototype +$codei% + const %SizeVector% &%ip% +%$$ +(see description for $icode SizeVector$$ in +$cref/LuFactor/LuFactor/SizeVector/$$ specifications). +The size of $icode ip$$ is referred to as $icode n$$ in the +specifications below. +The elements of $icode ip$$ determine +the order of the rows in the permuted matrix. + +$head jp$$ +The argument $icode jp$$ has prototype +$codei% + const %SizeVector% &%jp% +%$$ +(see description for $icode SizeVector$$ in +$cref/LuFactor/LuFactor/SizeVector/$$ specifications). +The size of $icode jp$$ must be equal to $icode n$$. +The elements of $icode jp$$ determine +the order of the columns in the permuted matrix. + +$head LU$$ +The argument $icode LU$$ has the prototype +$codei% + const %FloatVector% &%LU% +%$$ +and the size of $icode LU$$ must equal $latex n * n$$ +(see description for $icode FloatVector$$ in +$cref/LuFactor/LuFactor/FloatVector/$$ specifications). + +$subhead L$$ +We define the lower triangular matrix $icode L$$ in terms of $icode LU$$. +The matrix $icode L$$ is zero above the diagonal +and the rest of the elements are defined by +$codei% + %L%(%i%, %j%) = %LU%[ %ip%[%i%] * %n% + %jp%[%j%] ] +%$$ +for $latex i = 0 , \ldots , n-1$$ and $latex j = 0 , \ldots , i$$. + +$subhead U$$ +We define the upper triangular matrix $icode U$$ in terms of $icode LU$$. +The matrix $icode U$$ is zero below the diagonal, +one on the diagonal, +and the rest of the elements are defined by +$codei% + %U%(%i%, %j%) = %LU%[ %ip%[%i%] * %n% + %jp%[%j%] ] +%$$ +for $latex i = 0 , \ldots , n-2$$ and $latex j = i+1 , \ldots , n-1$$. + +$subhead P$$ +We define the permuted matrix $icode P$$ in terms of +the matrix $icode L$$ and the matrix $icode U$$ +by $icode%P% = %L% * %U%$$. + +$subhead A$$ +The matrix $icode A$$, +which defines the linear equations that we are solving, is given by +$codei% + %P%(%i%, %j%) = %A%[ %ip%[%i%] * %n% + %jp%[%j%] ] +%$$ +(Hence +$icode LU$$ contains a permuted factorization of the matrix $icode A$$.) + + +$head X$$ +The argument $icode X$$ has prototype +$codei% + %FloatVector% &%X% +%$$ +(see description for $icode FloatVector$$ in +$cref/LuFactor/LuFactor/FloatVector/$$ specifications). +The matrix $icode X$$ +must have the same number of rows as the matrix $icode A$$. +The input value of $icode X$$ is the matrix $icode B$$ and the +output value solves the matrix equation $icode%A% * %X% = %B%$$. + + +$children% + example/utility/lu_invert.cpp% + omh/lu_invert_hpp.omh +%$$ +$head Example$$ +The file $cref lu_solve.hpp$$ is a good example usage of +$code LuFactor$$ with $code LuInvert$$. +The file +$cref lu_invert.cpp$$ +contains an example and test of using $code LuInvert$$ by itself. + +$head Source$$ +The file $cref lu_invert.hpp$$ contains the +current source code that implements these specifications. + +$end +-------------------------------------------------------------------------- +*/ +// BEGIN C++ +# include +# include +# include + +namespace CppAD { // BEGIN CppAD namespace + +// LuInvert +template +void LuInvert( + const SizeVector &ip, + const SizeVector &jp, + const FloatVector &LU, + FloatVector &B ) +{ size_t k; // column index in X + size_t p; // index along diagonal in LU + size_t i; // row index in LU and X + + typedef typename FloatVector::value_type Float; + + // check numeric type specifications + CheckNumericType(); + + // check simple vector class specifications + CheckSimpleVector(); + CheckSimpleVector(); + + Float etmp; + + size_t n = ip.size(); + CPPAD_ASSERT_KNOWN( + size_t(jp.size()) == n, + "Error in LuInvert: jp must have size equal to n * n" + ); + CPPAD_ASSERT_KNOWN( + size_t(LU.size()) == n * n, + "Error in LuInvert: Lu must have size equal to n * m" + ); + size_t m = size_t(B.size()) / n; + CPPAD_ASSERT_KNOWN( + size_t(B.size()) == n * m, + "Error in LuSolve: B must have size equal to a multiple of n" + ); + + // temporary storage for reordered solution + FloatVector x(n); + + // loop over equations + for(k = 0; k < m; k++) + { // invert the equation c = L * b + for(p = 0; p < n; p++) + { // solve for c[p] + etmp = B[ ip[p] * m + k ] / LU[ ip[p] * n + jp[p] ]; + B[ ip[p] * m + k ] = etmp; + // subtract off effect on other variables + for(i = p+1; i < n; i++) + B[ ip[i] * m + k ] -= + etmp * LU[ ip[i] * n + jp[p] ]; + } + + // invert the equation x = U * c + p = n; + while( p > 0 ) + { --p; + etmp = B[ ip[p] * m + k ]; + x[ jp[p] ] = etmp; + for(i = 0; i < p; i++ ) + B[ ip[i] * m + k ] -= + etmp * LU[ ip[i] * n + jp[p] ]; + } + + // copy reordered solution into B + for(i = 0; i < n; i++) + B[i * m + k] = x[i]; + } + return; +} +} // END CppAD namespace +// END C++ +# endif diff --git a/build-config/cppad/include/cppad/utility/lu_solve.hpp b/build-config/cppad/include/cppad/utility/lu_solve.hpp new file mode 100644 index 00000000..65ce3b45 --- /dev/null +++ b/build-config/cppad/include/cppad/utility/lu_solve.hpp @@ -0,0 +1,345 @@ +# ifndef CPPAD_UTILITY_LU_SOLVE_HPP +# define CPPAD_UTILITY_LU_SOLVE_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +/* +$begin LuSolve$$ +$spell + cppad.hpp + det + exp + Leq + typename + bool + const + namespace + std + Geq + Lu + CppAD + signdet + logdet +$$ + + +$section Compute Determinant and Solve Linear Equations$$ + +$pre +$$ + +$head Syntax$$ +$codei%# include +%$$ +$icode%signdet% = LuSolve(%n%, %m%, %A%, %B%, %X%, %logdet%)%$$ + + +$head Description$$ +Use an LU factorization of the matrix $icode A$$ to +compute its determinant +and solve for $icode X$$ in the linear of equation +$latex \[ + A * X = B +\] $$ +where $icode A$$ is an +$icode n$$ by $icode n$$ matrix, +$icode X$$ is an +$icode n$$ by $icode m$$ matrix, and +$icode B$$ is an $latex n x m$$ matrix. + +$head Include$$ +The file $code cppad/utility/lu_solve.hpp$$ +is included by $code cppad/cppad.hpp$$ +but it can also be included separately with out the rest of +the $code CppAD$$ routines. + +$head Factor and Invert$$ +This routine is an easy to user interface to +$cref LuFactor$$ and $cref LuInvert$$ for computing determinants and +solutions of linear equations. +These separate routines should be used if +one right hand side $icode B$$ +depends on the solution corresponding to another +right hand side (with the same value of $icode A$$). +In this case only one call to $code LuFactor$$ is required +but there will be multiple calls to $code LuInvert$$. + + +$head Matrix Storage$$ +All matrices are stored in row major order. +To be specific, if $latex Y$$ is a vector +that contains a $latex p$$ by $latex q$$ matrix, +the size of $latex Y$$ must be equal to $latex p * q $$ and for +$latex i = 0 , \ldots , p-1$$, +$latex j = 0 , \ldots , q-1$$, +$latex \[ + Y_{i,j} = Y[ i * q + j ] +\] $$ + +$head signdet$$ +The return value $icode signdet$$ is a $code int$$ value +that specifies the sign factor for the determinant of $icode A$$. +This determinant of $icode A$$ is zero if and only if $icode signdet$$ +is zero. + +$head n$$ +The argument $icode n$$ has type $code size_t$$ +and specifies the number of rows in the matrices +$icode A$$, +$icode X$$, +and $icode B$$. +The number of columns in $icode A$$ is also equal to $icode n$$. + +$head m$$ +The argument $icode m$$ has type $code size_t$$ +and specifies the number of columns in the matrices +$icode X$$ +and $icode B$$. +If $icode m$$ is zero, +only the determinant of $icode A$$ is computed and +the matrices $icode X$$ and $icode B$$ are not used. + +$head A$$ +The argument $icode A$$ has the prototype +$codei% + const %FloatVector% &%A% +%$$ +and the size of $icode A$$ must equal $latex n * n$$ +(see description of $cref/FloatVector/LuSolve/FloatVector/$$ below). +This is the $latex n$$ by $icode n$$ matrix that +we are computing the determinant of +and that defines the linear equation. + +$head B$$ +The argument $icode B$$ has the prototype +$codei% + const %FloatVector% &%B% +%$$ +and the size of $icode B$$ must equal $latex n * m$$ +(see description of $cref/FloatVector/LuSolve/FloatVector/$$ below). +This is the $latex n$$ by $icode m$$ matrix that +defines the right hand side of the linear equations. +If $icode m$$ is zero, $icode B$$ is not used. + +$head X$$ +The argument $icode X$$ has the prototype +$codei% + %FloatVector% &%X% +%$$ +and the size of $icode X$$ must equal $latex n * m$$ +(see description of $cref/FloatVector/LuSolve/FloatVector/$$ below). +The input value of $icode X$$ does not matter. +On output, the elements of $icode X$$ contain the solution +of the equation we wish to solve +(unless $icode signdet$$ is equal to zero). +If $icode m$$ is zero, $icode X$$ is not used. + +$head logdet$$ +The argument $icode logdet$$ has prototype +$codei% + %Float% &%logdet% +%$$ +On input, the value of $icode logdet$$ does not matter. +On output, it has been set to the +log of the determinant of $icode A$$ +(but not quite). +To be more specific, +the determinant of $icode A$$ is given by the formula +$codei% + %det% = %signdet% * exp( %logdet% ) +%$$ +This enables $code LuSolve$$ to use logs of absolute values +in the case where $icode Float$$ corresponds to a real number. + +$head Float$$ +The type $icode Float$$ must satisfy the conditions +for a $cref NumericType$$ type. +The routine $cref CheckNumericType$$ will generate an error message +if this is not the case. +In addition, the following operations must be defined for any pair +of $icode Float$$ objects $icode x$$ and $icode y$$: + +$table +$bold Operation$$ $cnext $bold Description$$ $rnext +$codei%log(%x%)%$$ $cnext + returns the logarithm of $icode x$$ as a $icode Float$$ object +$tend + +$head FloatVector$$ +The type $icode FloatVector$$ must be a $cref SimpleVector$$ class with +$cref/elements of type Float/SimpleVector/Elements of Specified Type/$$. +The routine $cref CheckSimpleVector$$ will generate an error message +if this is not the case. + +$head LeqZero$$ +Including the file $code lu_solve.hpp$$ defines the template function +$codei% + template + bool LeqZero<%Float%>(const %Float% &%x%) +%$$ +in the $code CppAD$$ namespace. +This function returns true if $icode x$$ is less than or equal to zero +and false otherwise. +It is used by $code LuSolve$$ to avoid taking the log of +zero (or a negative number if $icode Float$$ corresponds to real numbers). +This template function definition assumes that the operator +$code <=$$ is defined for $icode Float$$ objects. +If this operator is not defined for your use of $icode Float$$, +you will need to specialize this template so that it works for your +use of $code LuSolve$$. +$pre + +$$ +Complex numbers do not have the operation or $code <=$$ defined. +In addition, in the complex case, +one can take the log of a negative number. +The specializations +$codei% + bool LeqZero< std::complex > (const std::complex &%x%) + bool LeqZero< std::complex >(const std::complex &%x%) +%$$ +are defined by including $code lu_solve.hpp$$. +These return true if $icode x$$ is zero and false otherwise. + +$head AbsGeq$$ +Including the file $code lu_solve.hpp$$ defines the template function +$codei% + template + bool AbsGeq<%Float%>(const %Float% &%x%, const %Float% &%y%) +%$$ +If the type $icode Float$$ does not support the $code <=$$ operation +and it is not $code std::complex$$ or $code std::complex$$, +see the documentation for $code AbsGeq$$ in $cref/LuFactor/LuFactor/AbsGeq/$$. + +$children% + example/utility/lu_solve.cpp% + omh/lu_solve_hpp.omh +%$$ +$head Example$$ +The file +$cref lu_solve.cpp$$ +contains an example and test of using this routine. + +$head Source$$ +The file $cref lu_solve.hpp$$ contains the +current source code that implements these specifications. + +$end +-------------------------------------------------------------------------- +*/ +// BEGIN C++ +# include +# include + +// link exp for float and double cases +# include + +# include +# include +# include +# include +# include + +namespace CppAD { // BEGIN CppAD namespace + +// LeqZero +template +bool LeqZero(const Float &x) +{ return x <= Float(0); } +inline bool LeqZero( const std::complex &x ) +{ return x == std::complex(0); } +inline bool LeqZero( const std::complex &x ) +{ return x == std::complex(0); } + +// LuSolve +template +int LuSolve( + size_t n , + size_t m , + const FloatVector &A , + const FloatVector &B , + FloatVector &X , + Float &logdet ) +{ + // check numeric type specifications + CheckNumericType(); + + // check simple vector class specifications + CheckSimpleVector(); + + size_t p; // index of pivot element (diagonal of L) + int signdet; // sign of the determinant + Float pivot; // pivot element + + // the value zero + const Float zero(0); + + // pivot row and column order in the matrix + std::vector ip(n); + std::vector jp(n); + + // ------------------------------------------------------- + CPPAD_ASSERT_KNOWN( + size_t(A.size()) == n * n, + "Error in LuSolve: A must have size equal to n * n" + ); + CPPAD_ASSERT_KNOWN( + size_t(B.size()) == n * m, + "Error in LuSolve: B must have size equal to n * m" + ); + CPPAD_ASSERT_KNOWN( + size_t(X.size()) == n * m, + "Error in LuSolve: X must have size equal to n * m" + ); + // ------------------------------------------------------- + + // copy A so that it does not change + FloatVector Lu(A); + + // copy B so that it does not change + X = B; + + // Lu factor the matrix A + signdet = LuFactor(ip, jp, Lu); + + // compute the log of the determinant + logdet = Float(0); + for(p = 0; p < n; p++) + { // pivot using the max absolute element + pivot = Lu[ ip[p] * n + jp[p] ]; + + // check for determinant equal to zero + if( pivot == zero ) + { // abort the mission + logdet = Float(0); + return 0; + } + + // update the determinant + if( LeqZero ( pivot ) ) + { logdet += log( - pivot ); + signdet = - signdet; + } + else + logdet += log( pivot ); + + } + + // solve the linear equations + LuInvert(ip, jp, Lu, X); + + // return the sign factor for the determinant + return signdet; +} +} // END CppAD namespace +// END C++ +# endif diff --git a/build-config/cppad/include/cppad/utility/memory_leak.hpp b/build-config/cppad/include/cppad/utility/memory_leak.hpp new file mode 100644 index 00000000..be7d59a3 --- /dev/null +++ b/build-config/cppad/include/cppad/utility/memory_leak.hpp @@ -0,0 +1,213 @@ +# ifndef CPPAD_UTILITY_MEMORY_LEAK_HPP +# define CPPAD_UTILITY_MEMORY_LEAK_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-18 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ +/* +$begin memory_leak$$ +$spell + cppad + num + alloc + hpp + bool + inuse +$$ + +$section Memory Leak Detection$$ + +$head Deprecated 2012-04-06$$ +This routine has been deprecated. +You should instead use the routine $cref ta_free_all$$. + +$head Syntax$$ +$codei%# include +%$$ +$icode%flag% = %memory_leak() +%$$ +$icode%flag% = %memory_leak%(%add_static%)%$$ + +$head Purpose$$ +This routine checks that the are no memory leaks +caused by improper use of $cref thread_alloc$$ memory allocator. +The deprecated memory allocator $cref TrackNewDel$$ is also checked. +Memory errors in the deprecated $cref omp_alloc$$ allocator are +reported as being in $code thread_alloc$$. + +$head thread$$ +It is assumed that $cref/in_parallel()/ta_in_parallel/$$ is false +and $cref/thread_num/ta_thread_num/$$ is zero when +$code memory_leak$$ is called. + +$head add_static$$ +This argument has prototype +$codei% + size_t %add_static% +%$$ +and its default value is zero. +Static variables hold onto memory forever. +If the argument $icode add_static$$ is present (and non-zero), +$code memory_leak$$ adds this amount of memory to the +$cref/inuse/ta_inuse/$$ sum that corresponds to +static variables in the program. +A call with $icode add_static$$ should be make after +a routine that has static variables which +use $cref/get_memory/ta_get_memory/$$ to allocate memory. +The value of $icode add_static$$ should be the difference of +$codei% + thread_alloc::inuse(0) +%$$ +before and after the call. +Since multiple statics may be allocated in different places in the program, +it is expected that there will be multiple calls +that use this option. + +$head flag$$ +The return value $icode flag$$ has prototype +$codei% + bool %flag% +%$$ +If $icode add_static$$ is non-zero, +the return value for $code memory_leak$$ is false. +Otherwise, the return value for $code memory_leak$$ should be false +(indicating that the only allocated memory corresponds to static variables). + +$head inuse$$ +It is assumed that, when $code memory_leak$$ is called, +there should not be any memory +$cref/inuse/ta_inuse/$$ or $cref omp_inuse$$ for any thread +(except for inuse memory corresponding to static variables). +If there is, a message is printed and $code memory_leak$$ returns false. + +$head available$$ +It is assumed that, when $code memory_leak$$ is called, +there should not be any memory +$cref/available/ta_available/$$ or $cref omp_available$$ for any thread; +i.e., it all has been returned to the system. +If there is memory still available for any thread, +$code memory_leak$$ returns false. + +$head TRACK_COUNT$$ +It is assumed that, when $code memory_leak$$ is called, +$cref/TrackCount/TrackNewDel/TrackCount/$$ will return a zero value. +If it returns a non-zero value, +$code memory_leak$$ returns false. + +$head Error Message$$ +If this is the first call to $code memory_leak$$, no message is printed. +Otherwise, if it returns true, an error message is printed +to standard output describing the memory leak that was detected. + +$end +*/ +# include +# include +# include +# include +# include + +namespace CppAD { // BEGIN_CPPAD_NAMESPACE +/*! +\file memory_leak.hpp +File that implements a memory check at end of a CppAD program +*/ + +/*! +Function that checks +allocator thread_alloc for misuse that results in memory leaks. +Deprecated routines in track_new_del.hpp and omp_alloc.hpp are also checked. + +\param add_static [in] +The amount specified by add_static is added to the amount +of memory that is expected to be used by thread zero for static variables. + +\return +If add_static is non-zero, the return value is false. +Otherwise, if one of the following errors is detected, +the return value is true: + +\li +Thread zero does not have the expected amount of inuse memory +(for static variables). +\li +A thread, other than thread zero, has any inuse memory. +\li +Any thread has available memory. + +\par +If an error is detected, diagnostic information is printed to standard +output. +*/ +inline bool memory_leak(size_t add_static = 0) +{ // CPPAD_ASSERT_FIRST_CALL_NOT_PARALLEL not necessary given asserts below + static size_t thread_zero_static_inuse = 0; + using std::cout; + using std::endl; + using CppAD::thread_alloc; + using CppAD::omp_alloc; + // -------------------------------------------------------------------- + CPPAD_ASSERT_KNOWN( + ! thread_alloc::in_parallel(), + "memory_leak: in_parallel() is true." + ); + CPPAD_ASSERT_KNOWN( + thread_alloc::thread_num() == 0, + "memory_leak: thread_num() is not zero." + ); + if( add_static != 0 ) + { thread_zero_static_inuse += add_static; + return false; + } + bool leak = false; + size_t thread = 0; + + // check that memory in use for thread zero corresponds to statics + size_t num_bytes = thread_alloc::inuse(thread); + if( num_bytes != thread_zero_static_inuse ) + { leak = true; + cout << "thread zero: static inuse = " << thread_zero_static_inuse; + cout << ", current inuse(0)= " << num_bytes << endl; + } + // check that no memory is currently available for this thread + num_bytes = thread_alloc::available(thread); + if( num_bytes != 0 ) + { leak = true; + cout << "thread zero: available = "; + cout << num_bytes << endl; + } + for(thread = 1; thread < CPPAD_MAX_NUM_THREADS; thread++) + { + // check that no memory is currently in use for this thread + num_bytes = thread_alloc::inuse(thread); + if( num_bytes != 0 ) + { leak = true; + cout << "thread " << thread << ": inuse(thread) = "; + cout << num_bytes << endl; + } + // check that no memory is currently available for this thread + num_bytes = thread_alloc::available(thread); + if( num_bytes != 0 ) + { leak = true; + cout << "thread " << thread << ": available(thread) = "; + cout << num_bytes << endl; + } + } + // ---------------------------------------------------------------------- + // check track_new_del + if( CPPAD_TRACK_COUNT() != 0 ) + { leak = true; + CppAD::TrackElement::Print(); + } + return leak; +} + +} // END_CPPAD_NAMESPACE +# endif diff --git a/build-config/cppad/include/cppad/utility/nan.hpp b/build-config/cppad/include/cppad/utility/nan.hpp new file mode 100644 index 00000000..e0940ea3 --- /dev/null +++ b/build-config/cppad/include/cppad/utility/nan.hpp @@ -0,0 +1,193 @@ +# ifndef CPPAD_UTILITY_NAN_HPP +# define CPPAD_UTILITY_NAN_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ +/* +$begin nan$$ +$spell + hasnan + cppad + hpp + CppAD + isnan + bool + const +$$ + +$section Obtain Nan or Determine if a Value is Nan$$ + +$head Syntax$$ +$codei%# include +%$$ +$icode%b% = isnan(%s%) +%$$ +$icode%b% = hasnan(%v%)%$$ + +$head Purpose$$ +It obtain and check for the value not a number $code nan$$. +The IEEE standard specifies that a floating point value $icode a$$ +is $code nan$$ if and only if the following returns true +$codei% + %a% != %a% +%$$ + +$head Include$$ +The file $code cppad/utility/nan.hpp$$ +is included by $code cppad/cppad.hpp$$ +but it can also be included separately with out the rest of +the $code CppAD$$ routines. + +$subhead Macros$$ +Some C++ compilers use preprocessor symbols called $code nan$$ +and $code isnan$$. +These preprocessor symbols will no longer be defined after +this file is included. + +$head isnan$$ +This routine determines if a scalar value is $code nan$$. + +$subhead s$$ +The argument $icode s$$ has prototype +$codei% + const %Scalar% %s% +%$$ + +$subhead b$$ +The return value $icode b$$ has prototype +$codei% + bool %b% +%$$ +It is true if the value $icode s$$ is $code nan$$. + +$head hasnan$$ +This routine determines if a +$cref SimpleVector$$ has an element that is $code nan$$. + +$subhead v$$ +The argument $icode v$$ has prototype +$codei% + const %Vector% &%v% +%$$ +(see $cref/Vector/nan/Vector/$$ for the definition of $icode Vector$$). + +$subhead b$$ +The return value $icode b$$ has prototype +$codei% + bool %b% +%$$ +It is true if the vector $icode v$$ has a $code nan$$. + + +$head nan(zero)$$ + +$subhead Deprecated 2015-10-04$$ +This routine has been deprecated, use CppAD numeric limits +$cref/quiet_NaN/numeric_limits/quiet_NaN/$$ in its place. + +$subhead Syntax$$ +$icode%s% = nan(%z%) +%$$ + +$subhead z$$ +The argument $icode z$$ has prototype +$codei% + const %Scalar% &%z% +%$$ +and its value is zero +(see $cref/Scalar/nan/Scalar/$$ for the definition of $icode Scalar$$). + +$subhead s$$ +The return value $icode s$$ has prototype +$codei% + %Scalar% %s% +%$$ +It is the value $code nan$$ for this floating point type. + +$head Scalar$$ +The type $icode Scalar$$ must support the following operations; +$table +$bold Operation$$ $cnext $bold Description$$ $rnext +$icode%a% / %b%$$ $cnext + division operator (returns a $icode Scalar$$ object) +$rnext +$icode%a% == %b%$$ $cnext + equality operator (returns a $code bool$$ object) +$rnext +$icode%a% != %b%$$ $cnext + not equality operator (returns a $code bool$$ object) +$tend +Note that the division operator will be used with $icode a$$ and $icode b$$ +equal to zero. For some types (e.g. $code int$$) this may generate +an exception. No attempt is made to catch any such exception. + +$head Vector$$ +The type $icode Vector$$ must be a $cref SimpleVector$$ class with +elements of type $icode Scalar$$. + +$children% + example/utility/nan.cpp +%$$ +$head Example$$ +The file $cref nan.cpp$$ +contains an example and test of this routine. + +$end +*/ + +# include +# include + +// needed before one can use CPPAD_ASSERT_FIRST_CALL_NOT_PARALLEL +# include + +/* +# define nan There must be a define for every CppAD undef +*/ +# ifdef nan +# undef nan +# endif + +/* +# define isnan There must be a define for every CppAD undef +*/ +# ifdef isnan +# undef isnan +# endif + +namespace CppAD { // BEGIN CppAD namespace + +template +bool isnan(const Scalar &s) +{ return (s != s); +} + +template +bool hasnan(const Vector &v) +{ + bool found_nan; + size_t i; + i = v.size(); + found_nan = false; + // on MS Visual Studio 2012, CppAD required in front of isnan ? + while(i--) + found_nan |= CppAD::isnan(v[i]); + return found_nan; +} + +template +Scalar nan(const Scalar &zero) +{ return zero / zero; +} + +} // End CppAD namespace + +# endif diff --git a/build-config/cppad/include/cppad/utility/near_equal.hpp b/build-config/cppad/include/cppad/utility/near_equal.hpp new file mode 100644 index 00000000..b9ecca72 --- /dev/null +++ b/build-config/cppad/include/cppad/utility/near_equal.hpp @@ -0,0 +1,271 @@ +# ifndef CPPAD_UTILITY_NEAR_EQUAL_HPP +# define CPPAD_UTILITY_NEAR_EQUAL_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +/* +$begin NearEqual$$ +$spell + cppad.hpp + sqrt + cout + endl + Microsoft + std + Cpp + namespace + const + bool +$$ + +$section Determine if Two Values Are Nearly Equal$$ + + +$head Syntax$$ + +$codei%# include +%$$ +$icode%b% = NearEqual(%x%, %y%, %r%, %a%)%$$ + + +$head Purpose$$ +Returns true, +if $icode x$$ and $icode y$$ are nearly equal, +and false otherwise. + +$head x$$ +The argument $icode x$$ +has one of the following possible prototypes +$codei% + const %Type% &%x%, + const std::complex<%Type%> &%x%, +%$$ + +$head y$$ +The argument $icode y$$ +has one of the following possible prototypes +$codei% + const %Type% &%y%, + const std::complex<%Type%> &%y%, +%$$ + +$head r$$ +The relative error criteria $icode r$$ has prototype +$codei% + const %Type% &%r% +%$$ +It must be greater than or equal to zero. +The relative error condition is defined as: +$latex \[ + | x - y | \leq r ( |x| + |y| ) +\] $$ + +$head a$$ +The absolute error criteria $icode a$$ has prototype +$codei% + const %Type% &%a% +%$$ +It must be greater than or equal to zero. +The absolute error condition is defined as: +$latex \[ + | x - y | \leq a +\] $$ + +$head b$$ +The return value $icode b$$ has prototype +$codei% + bool %b% +%$$ +If either $icode x$$ or $icode y$$ is infinite or not a number, +the return value is false. +Otherwise, if either the relative or absolute error +condition (defined above) is satisfied, the return value is true. +Otherwise, the return value is false. + +$head Type$$ +The type $icode Type$$ must be a +$cref NumericType$$. +The routine $cref CheckNumericType$$ will generate +an error message if this is not the case. +In addition, the following operations must be defined objects +$icode a$$ and $icode b$$ of type $icode Type$$: +$table +$bold Operation$$ $cnext + $bold Description$$ $rnext +$icode%a% <= %b%$$ $cnext + less that or equal operator (returns a $code bool$$ object) +$tend + +$head Include Files$$ +The file $code cppad/utility/near_equal.hpp$$ +is included by $code cppad/cppad.hpp$$ +but it can also be included separately with out the rest of +the $code CppAD$$ routines. + +$head Example$$ +$children% + example/utility/near_equal.cpp +%$$ +The file $cref near_equal.cpp$$ contains an example +and test of $code NearEqual$$. +It return true if it succeeds and false otherwise. + +$head Exercise$$ +Create and run a program that contains the following code: +$codep + using std::complex; + using std::cout; + using std::endl; + + complex one(1., 0), i(0., 1); + complex x = one / i; + complex y = - i; + double r = 1e-12; + double a = 0; + bool ok = CppAD::NearEqual(x, y, r, a); + if( ok ) + cout << "Ok" << endl; + else + cout << "Error" << endl; +$$ + +$end + +*/ + +# include +# include +# include +# include + +namespace CppAD { // Begin CppAD namespace + +// determine if both x and y are finite values +template +bool near_equal_isfinite(const Type &x , const Type &y) +{ Type infinity = Type( std::numeric_limits::infinity() ); + + // handle bug where some compilers return true for nan == nan + bool xNan = x != x; + bool yNan = y != y; + + // infinite cases + bool xInf = (x == infinity || x == - infinity); + bool yInf = (x == infinity || x == - infinity); + + return ! (xNan | yNan | xInf | yInf); +} + +template +bool NearEqual(const Type &x, const Type &y, const Type &r, const Type &a) +{ + CheckNumericType(); + Type zero(0); + + CPPAD_ASSERT_KNOWN( + zero <= r, + "Error in NearEqual: relative error is less than zero" + ); + CPPAD_ASSERT_KNOWN( + zero <= a, + "Error in NearEqual: absolute error is less than zero" + ); + + // check for special cases + if( ! CppAD::near_equal_isfinite(x, y) ) + return false; + + Type ax = x; + if( ax <= zero ) + ax = - ax; + + Type ay = y; + if( ay <= zero ) + ay = - ay; + + Type ad = x - y; + if( ad <= zero ) + ad = - ad; + + if( ad <= a ) + return true; + + if( ad <= r * (ax + ay) ) + return true; + + return false; +} + +template +bool NearEqual( + const std::complex &x , + const std::complex &y , + const Type &r , + const Type & a ) +{ + CheckNumericType(); +# ifndef NDEBUG + Type zero(0); +# endif + + CPPAD_ASSERT_KNOWN( + zero <= r, + "Error in NearEqual: relative error is less than zero" + ); + CPPAD_ASSERT_KNOWN( + zero <= a, + "Error in NearEqual: absolute error is less than zero" + ); + + // check for special cases + if( ! CppAD::near_equal_isfinite(x.real(), x.imag()) ) + return false; + if( ! CppAD::near_equal_isfinite(y.real(), y.imag()) ) + return false; + + std::complex d = x - y; + + Type ad = std::abs(d); + if( ad <= a ) + return true; + + Type ax = std::abs(x); + Type ay = std::abs(y); + if( ad <= r * (ax + ay) ) + return true; + + return false; +} + +template +bool NearEqual( + const std::complex &x , + const Type &y , + const Type &r , + const Type & a ) +{ + return NearEqual(x, std::complex(y, Type(0)), r, a); +} + +template +bool NearEqual( + const Type &x , + const std::complex &y , + const Type &r , + const Type & a ) +{ + return NearEqual(std::complex(x, Type(0)), y, r, a); +} + +} // END CppAD namespace + +# endif diff --git a/build-config/cppad/include/cppad/utility/ode_err_control.hpp b/build-config/cppad/include/cppad/utility/ode_err_control.hpp new file mode 100644 index 00000000..0e731bff --- /dev/null +++ b/build-config/cppad/include/cppad/utility/ode_err_control.hpp @@ -0,0 +1,598 @@ +# ifndef CPPAD_UTILITY_ODE_ERR_CONTROL_HPP +# define CPPAD_UTILITY_ODE_ERR_CONTROL_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +/* +$begin OdeErrControl$$ +$spell + cppad.hpp + nstep + maxabs + exp + scur + CppAD + xf + tf + xi + smin + smax + eabs + erel + ef + ta + tb + xa + xb + const + eb +$$ + + + +$section An Error Controller for ODE Solvers$$ + +$head Syntax$$ +$codei%# include +%$$ +$icode%xf% = OdeErrControl(%method%, %ti%, %tf%, %xi%, + %smin%, %smax%, %scur%, %eabs%, %erel%, %ef% , %maxabs%, %nstep% )%$$ + + +$head Description$$ +Let $latex \B{R}$$ denote the real numbers +and let $latex F : \B{R} \times \B{R}^n \rightarrow \B{R}^n$$ be a smooth function. +We define $latex X : [ti , tf] \rightarrow \B{R}^n$$ by +the following initial value problem: +$latex \[ +\begin{array}{rcl} + X(ti) & = & xi \\ + X'(t) & = & F[t , X(t)] +\end{array} +\] $$ +The routine $code OdeErrControl$$ can be used to adjust the step size +used an arbitrary integration methods in order to be as fast as possible +and still with in a requested error bound. + +$head Include$$ +The file $code cppad/utility/ode_err_control.hpp$$ is included by +$code cppad/cppad.hpp$$ +but it can also be included separately with out the rest of +the $code CppAD$$ routines. + +$head Notation$$ +The template parameter types $cref/Scalar/OdeErrControl/Scalar/$$ and +$cref/Vector/OdeErrControl/Vector/$$ are documented below. + +$head xf$$ +The return value $icode xf$$ has the prototype +$codei% + %Vector% %xf% +%$$ +(see description of $cref/Vector/OdeErrControl/Vector/$$ below). +and the size of $icode xf$$ is equal to $icode n$$. +If $icode xf$$ contains not a number $cref nan$$, +see the discussion of $cref/step/OdeErrControl/Method/Nan/$$. + +$head Method$$ +The class $icode Method$$ +and the object $icode method$$ satisfy the following syntax +$codei% + %Method% &%method% +%$$ +The object $icode method$$ must support $code step$$ and +$code order$$ member functions defined below: + +$subhead step$$ +The syntax +$codei% + %method%.step(%ta%, %tb%, %xa%, %xb%, %eb%) +%$$ +executes one step of the integration method. +$codei% + +%ta% +%$$ +The argument $icode ta$$ has prototype +$codei% + const %Scalar% &%ta% +%$$ +It specifies the initial time for this step in the +ODE integration. +(see description of $cref/Scalar/OdeErrControl/Scalar/$$ below). +$codei% + +%tb% +%$$ +The argument $icode tb$$ has prototype +$codei% + const %Scalar% &%tb% +%$$ +It specifies the final time for this step in the +ODE integration. +$codei% + +%xa% +%$$ +The argument $icode xa$$ has prototype +$codei% + const %Vector% &%xa% +%$$ +and size $icode n$$. +It specifies the value of $latex X(ta)$$. +(see description of $cref/Vector/OdeErrControl/Vector/$$ below). +$codei% + +%xb% +%$$ +The argument value $icode xb$$ has prototype +$codei% + %Vector% &%xb% +%$$ +and size $icode n$$. +The input value of its elements does not matter. +On output, +it contains the approximation for $latex X(tb)$$ that the method obtains. +$codei% + +%eb% +%$$ +The argument value $icode eb$$ has prototype +$codei% + %Vector% &%eb% +%$$ +and size $icode n$$. +The input value of its elements does not matter. +On output, +it contains an estimate for the error in the approximation $icode xb$$. +It is assumed (locally) that the error bound in this approximation +nearly equal to $latex K (tb - ta)^m$$ +where $icode K$$ is a fixed constant and $icode m$$ +is the corresponding argument to $code CodeControl$$. + +$subhead Nan$$ +If any element of the vector $icode eb$$ or $icode xb$$ are +not a number $code nan$$, +the current step is considered to large. +If this happens with the current step size equal to $icode smin$$, +$code OdeErrControl$$ returns with $icode xf$$ and $icode ef$$ as vectors +of $code nan$$. + +$subhead order$$ +If $icode m$$ is $code size_t$$, +the object $icode method$$ must also support the following syntax +$codei% + %m% = %method%.order() +%$$ +The return value $icode m$$ is the order of the error estimate; +i.e., there is a constant K such that if $latex ti \leq ta \leq tb \leq tf$$, +$latex \[ + | eb(tb) | \leq K | tb - ta |^m +\] $$ +where $icode ta$$, $icode tb$$, and $icode eb$$ are as in +$icode%method%.step(%ta%, %tb%, %xa%, %xb%, %eb%)%$$ + + +$head ti$$ +The argument $icode ti$$ has prototype +$codei% + const %Scalar% &%ti% +%$$ +It specifies the initial time for the integration of +the differential equation. + + +$head tf$$ +The argument $icode tf$$ has prototype +$codei% + const %Scalar% &%tf% +%$$ +It specifies the final time for the integration of +the differential equation. + +$head xi$$ +The argument $icode xi$$ has prototype +$codei% + const %Vector% &%xi% +%$$ +and size $icode n$$. +It specifies value of $latex X(ti)$$. + +$head smin$$ +The argument $icode smin$$ has prototype +$codei% + const %Scalar% &%smin% +%$$ +The step size during a call to $icode method$$ is defined as +the corresponding value of $latex tb - ta$$. +If $latex tf - ti \leq smin$$, +the integration will be done in one step of size $icode tf - ti$$. +Otherwise, +the minimum value of $icode tb - ta$$ will be $latex smin$$ +except for the last two calls to $icode method$$ where it may be +as small as $latex smin / 2$$. + +$head smax$$ +The argument $icode smax$$ has prototype +$codei% + const %Scalar% &%smax% +%$$ +It specifies the maximum step size to use during the integration; +i.e., the maximum value for $latex tb - ta$$ in a call to $icode method$$. +The value of $icode smax$$ must be greater than or equal $icode smin$$. + +$head scur$$ +The argument $icode scur$$ has prototype +$codei% + %Scalar% &%scur% +%$$ +The value of $icode scur$$ is the suggested next step size, +based on error criteria, to try in the next call to $icode method$$. +On input it corresponds to the first call to $icode method$$, +in this call to $code OdeErrControl$$ (where $latex ta = ti$$). +On output it corresponds to the next call to $icode method$$, +in a subsequent call to $code OdeErrControl$$ (where $icode ta = tf$$). + +$head eabs$$ +The argument $icode eabs$$ has prototype +$codei% + const %Vector% &%eabs% +%$$ +and size $icode n$$. +Each of the elements of $icode eabs$$ must be +greater than or equal zero. +It specifies a bound for the absolute +error in the return value $icode xf$$ as an approximation for $latex X(tf)$$. +(see the +$cref/error criteria discussion/OdeErrControl/Error Criteria Discussion/$$ +below). + +$head erel$$ +The argument $icode erel$$ has prototype +$codei% + const %Scalar% &%erel% +%$$ +and is greater than or equal zero. +It specifies a bound for the relative +error in the return value $icode xf$$ as an approximation for $latex X(tf)$$ +(see the +$cref/error criteria discussion/OdeErrControl/Error Criteria Discussion/$$ +below). + +$head ef$$ +The argument value $icode ef$$ has prototype +$codei% + %Vector% &%ef% +%$$ +and size $icode n$$. +The input value of its elements does not matter. +On output, +it contains an estimated bound for the +absolute error in the approximation $icode xf$$; i.e., +$latex \[ + ef_i > | X( tf )_i - xf_i | +\] $$ +If on output $icode ef$$ contains not a number $code nan$$, +see the discussion of $cref/step/OdeErrControl/Method/Nan/$$. + +$head maxabs$$ +The argument $icode maxabs$$ is optional in the call to $code OdeErrControl$$. +If it is present, it has the prototype +$codei% + %Vector% &%maxabs% +%$$ +and size $icode n$$. +The input value of its elements does not matter. +On output, +it contains an estimate for the +maximum absolute value of $latex X(t)$$; i.e., +$latex \[ + maxabs[i] \approx \max \left\{ + | X( t )_i | \; : \; t \in [ti, tf] + \right\} +\] $$ + +$head nstep$$ +The argument $icode nstep$$ is optional in the call to $code OdeErrControl$$. +If it is present, it has the prototype +$codei% + %size_t% &%nstep% +%$$ +Its input value does not matter and its output value +is the number of calls to $icode%method%.step%$$ +used by $code OdeErrControl$$. + +$head Error Criteria Discussion$$ +The relative error criteria $icode erel$$ and +absolute error criteria $icode eabs$$ are enforced during each step of the +integration of the ordinary differential equations. +In addition, they are inversely scaled by the step size so that +the total error bound is less than the sum of the error bounds. +To be specific, if $latex \tilde{X} (t)$$ is the approximate solution +at time $latex t$$, +$icode ta$$ is the initial step time, +and $icode tb$$ is the final step time, +$latex \[ +\left| \tilde{X} (tb)_j - X (tb)_j \right| +\leq +\frac{tf - ti}{tb - ta} +\left[ eabs[j] + erel \; | \tilde{X} (tb)_j | \right] +\] $$ +If $latex X(tb)_j$$ is near zero for some $latex tb \in [ti , tf]$$, +and one uses an absolute error criteria $latex eabs[j]$$ of zero, +the error criteria above will force $code OdeErrControl$$ +to use step sizes equal to +$cref/smin/OdeErrControl/smin/$$ +for steps ending near $latex tb$$. +In this case, the error relative to $icode maxabs$$ can be judged after +$code OdeErrControl$$ returns. +If $icode ef$$ is to large relative to $icode maxabs$$, +$code OdeErrControl$$ can be called again +with a smaller value of $icode smin$$. + +$head Scalar$$ +The type $icode Scalar$$ must satisfy the conditions +for a $cref NumericType$$ type. +The routine $cref CheckNumericType$$ will generate an error message +if this is not the case. +In addition, the following operations must be defined for +$icode Scalar$$ objects $icode a$$ and $icode b$$: + +$table +$bold Operation$$ $cnext $bold Description$$ $rnext +$icode%a% <= %b%$$ $cnext + returns true (false) if $icode a$$ is less than or equal + (greater than) $icode b$$. +$rnext +$icode%a% == %b%$$ $cnext + returns true (false) if $icode a$$ is equal to $icode b$$. +$rnext +$codei%log(%a%)%$$ $cnext + returns a $icode Scalar$$ equal to the logarithm of $icode a$$ +$rnext +$codei%exp(%a%)%$$ $cnext + returns a $icode Scalar$$ equal to the exponential of $icode a$$ +$tend + + +$head Vector$$ +The type $icode Vector$$ must be a $cref SimpleVector$$ class with +$cref/elements of type Scalar/SimpleVector/Elements of Specified Type/$$. +The routine $cref CheckSimpleVector$$ will generate an error message +if this is not the case. + +$head Example$$ +$children% + example/utility/ode_err_control.cpp% + example/utility/ode_err_maxabs.cpp +%$$ +The files +$cref ode_err_control.cpp$$ +and +$cref ode_err_maxabs.cpp$$ +contain examples and tests of using this routine. +They return true if they succeed and false otherwise. + +$head Theory$$ +Let $latex e(s)$$ be the error as a function of the +step size $latex s$$ and suppose that there is a constant +$latex K$$ such that $latex e(s) = K s^m$$. +Let $latex a$$ be our error bound. +Given the value of $latex e(s)$$, a step of size $latex \lambda s$$ +would be ok provided that +$latex \[ +\begin{array}{rcl} + a & \geq & e( \lambda s ) (tf - ti) / ( \lambda s ) \\ + a & \geq & K \lambda^m s^m (tf - ti) / ( \lambda s ) \\ + a & \geq & \lambda^{m-1} s^{m-1} (tf - ti) e(s) / s^m \\ + a & \geq & \lambda^{m-1} (tf - ti) e(s) / s \\ + \lambda^{m-1} & \leq & \frac{a}{e(s)} \frac{s}{tf - ti} +\end{array} +\] $$ +Thus if the right hand side of the last inequality is greater +than or equal to one, the step of size $latex s$$ is ok. + +$head Source Code$$ +The source code for this routine is in the file +$code cppad/ode_err_control.hpp$$. + +$end +-------------------------------------------------------------------------- +*/ + +// link exp and log for float and double +# include + +# include +# include +# include + +namespace CppAD { // Begin CppAD namespace + +template +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(); + + 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.0); + Scalar one(1.0); + Scalar two(2.0); + Scalar three(3.0); + Scalar m1(double(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; +} + +template +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(xi.size()); + size_t nstep; + return OdeErrControl( + method, ti, tf, xi, smin, smax, scur, eabs, erel, ef, maxabs, nstep + ); +} + +template +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; + return OdeErrControl( + method, ti, tf, xi, smin, smax, scur, eabs, erel, ef, maxabs, nstep + ); +} + +} // End CppAD namespace + +# endif diff --git a/build-config/cppad/include/cppad/utility/ode_gear.hpp b/build-config/cppad/include/cppad/utility/ode_gear.hpp new file mode 100644 index 00000000..1f4901a7 --- /dev/null +++ b/build-config/cppad/include/cppad/utility/ode_gear.hpp @@ -0,0 +1,521 @@ +# ifndef CPPAD_UTILITY_ODE_GEAR_HPP +# define CPPAD_UTILITY_ODE_GEAR_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +/* +$begin OdeGear$$ +$spell + cppad.hpp + Jan + bool + const + CppAD + dep +$$ + + +$section An Arbitrary Order Gear Method$$ + +$head Syntax$$ +$codei%# include +%$$ +$codei%OdeGear(%F%, %m%, %n%, %T%, %X%, %e%)%$$ + + +$head Purpose$$ +This routine applies +$cref/Gear's Method/OdeGear/Gear's Method/$$ +to solve an explicit set of ordinary differential equations. +We are given +$latex f : \B{R} \times \B{R}^n \rightarrow \B{R}^n$$ be a smooth function. +This routine solves the following initial value problem +$latex \[ +\begin{array}{rcl} + x( t_{m-1} ) & = & x^0 \\ + x^\prime (t) & = & f[t , x(t)] +\end{array} +\] $$ +for the value of $latex x( t_m )$$. +If your set of ordinary differential equations are not stiff +an explicit method may be better (perhaps $cref Runge45$$.) + +$head Include$$ +The file $code cppad/utility/ode_gear.hpp$$ +is included by $code cppad/cppad.hpp$$ +but it can also be included separately with out the rest of +the $code CppAD$$ routines. + +$head Fun$$ +The class $icode Fun$$ +and the object $icode F$$ satisfy the prototype +$codei% + %Fun% &%F% +%$$ +This must support the following set of calls +$codei% + %F%.Ode(%t%, %x%, %f%) + %F%.Ode_dep(%t%, %x%, %f_x%) +%$$ + +$subhead t$$ +The argument $icode t$$ has prototype +$codei% + const %Scalar% &%t% +%$$ +(see description of $cref/Scalar/OdeGear/Scalar/$$ below). + +$subhead x$$ +The argument $icode x$$ has prototype +$codei% + const %Vector% &%x% +%$$ +and has size $icode n$$ +(see description of $cref/Vector/OdeGear/Vector/$$ below). + +$subhead f$$ +The argument $icode f$$ to $icode%F%.Ode%$$ has prototype +$codei% + %Vector% &%f% +%$$ +On input and output, $icode f$$ is a vector of size $icode n$$ +and the input values of the elements of $icode f$$ do not matter. +On output, +$icode f$$ is set equal to $latex f(t, x)$$ +(see $icode f(t, x)$$ in $cref/Purpose/OdeGear/Purpose/$$). + +$subhead f_x$$ +The argument $icode f_x$$ has prototype +$codei% + %Vector% &%f_x% +%$$ +On input and output, $icode f_x$$ is a vector of size $latex n * n$$ +and the input values of the elements of $icode f_x$$ do not matter. +On output, +$latex \[ + f\_x [i * n + j] = \partial_{x(j)} f_i ( t , x ) +\] $$ + +$subhead Warning$$ +The arguments $icode f$$, and $icode f_x$$ +must have a call by reference in their prototypes; i.e., +do not forget the $code &$$ in the prototype for +$icode f$$ and $icode f_x$$. + +$head m$$ +The argument $icode m$$ has prototype +$codei% + size_t %m% +%$$ +It specifies the order (highest power of $latex t$$) +used to represent the function $latex x(t)$$ in the multi-step method. +Upon return from $code OdeGear$$, +the $th i$$ component of the polynomial is defined by +$latex \[ + p_i ( t_j ) = X[ j * n + i ] +\] $$ +for $latex j = 0 , \ldots , m$$ (where $latex 0 \leq i < n$$). +The value of $latex m$$ must be greater than or equal one. + +$head n$$ +The argument $icode n$$ has prototype +$codei% + size_t %n% +%$$ +It specifies the range space dimension of the +vector valued function $latex x(t)$$. + +$head T$$ +The argument $icode T$$ has prototype +$codei% + const %Vector% &%T% +%$$ +and size greater than or equal to $latex m+1$$. +For $latex j = 0 , \ldots m$$, $latex T[j]$$ is the time +corresponding to time corresponding +to a previous point in the multi-step method. +The value $latex T[m]$$ is the time +of the next point in the multi-step method. +The array $latex T$$ must be monotone increasing; i.e., +$latex T[j] < T[j+1]$$. +Above and below we often use the shorthand $latex t_j$$ for $latex T[j]$$. + + +$head X$$ +The argument $icode X$$ has the prototype +$codei% + %Vector% &%X% +%$$ +and size greater than or equal to $latex (m+1) * n$$. +On input to $code OdeGear$$, +for $latex j = 0 , \ldots , m-1$$, and +$latex i = 0 , \ldots , n-1$$ +$latex \[ + X[ j * n + i ] = x_i ( t_j ) +\] $$ +Upon return from $code OdeGear$$, +for $latex i = 0 , \ldots , n-1$$ +$latex \[ + X[ m * n + i ] \approx x_i ( t_m ) +\] $$ + +$head e$$ +The vector $icode e$$ is an approximate error bound for the result; i.e., +$latex \[ + e[i] \geq | X[ m * n + i ] - x_i ( t_m ) | +\] $$ +The order of this approximation is one less than the order of +the solution; i.e., +$latex \[ + e = O ( h^m ) +\] $$ +where $latex h$$ is the maximum of $latex t_{j+1} - t_j$$. + +$head Scalar$$ +The type $icode Scalar$$ must satisfy the conditions +for a $cref NumericType$$ type. +The routine $cref CheckNumericType$$ will generate an error message +if this is not the case. +In addition, the following operations must be defined for +$icode Scalar$$ objects $icode a$$ and $icode b$$: + +$table +$bold Operation$$ $cnext $bold Description$$ $rnext +$icode%a% < %b%$$ $cnext + less than operator (returns a $code bool$$ object) +$tend + +$head Vector$$ +The type $icode Vector$$ must be a $cref SimpleVector$$ class with +$cref/elements of type Scalar/SimpleVector/Elements of Specified Type/$$. +The routine $cref CheckSimpleVector$$ will generate an error message +if this is not the case. + +$head Example$$ +$children% + example/utility/ode_gear.cpp +%$$ +The file +$cref ode_gear.cpp$$ +contains an example and test a test of using this routine. + +$head Source Code$$ +The source code for this routine is in the file +$code cppad/ode_gear.hpp$$. + +$head Theory$$ +For this discussion we use the shorthand $latex x_j$$ +for the value $latex x ( t_j ) \in \B{R}^n$$ which is not to be confused +with $latex x_i (t) \in \B{R}$$ in the notation above. +The interpolating polynomial $latex p(t)$$ is given by +$latex \[ +p(t) = +\sum_{j=0}^m +x_j +\frac{ + \prod_{i \neq j} ( t - t_i ) +}{ + \prod_{i \neq j} ( t_j - t_i ) +} +\] $$ +The derivative $latex p^\prime (t)$$ is given by +$latex \[ +p^\prime (t) = +\sum_{j=0}^m +x_j +\frac{ + \sum_{i \neq j} \prod_{k \neq i,j} ( t - t_k ) +}{ + \prod_{k \neq j} ( t_j - t_k ) +} +\] $$ +Evaluating the derivative at the point $latex t_\ell$$ we have +$latex \[ +\begin{array}{rcl} +p^\prime ( t_\ell ) & = & +x_\ell +\frac{ + \sum_{i \neq \ell} \prod_{k \neq i,\ell} ( t_\ell - t_k ) +}{ + \prod_{k \neq \ell} ( t_\ell - t_k ) +} ++ +\sum_{j \neq \ell} +x_j +\frac{ + \sum_{i \neq j} \prod_{k \neq i,j} ( t_\ell - t_k ) +}{ + \prod_{k \neq j} ( t_j - t_k ) +} +\\ +& = & +x_\ell +\sum_{i \neq \ell} +\frac{ 1 }{ t_\ell - t_i } ++ +\sum_{j \neq \ell} +x_j +\frac{ + \prod_{k \neq \ell,j} ( t_\ell - t_k ) +}{ + \prod_{k \neq j} ( t_j - t_k ) +} +\\ +& = & +x_\ell +\sum_{k \neq \ell} ( t_\ell - t_k )^{-1} ++ +\sum_{j \neq \ell} +x_j +( t_j - t_\ell )^{-1} +\prod_{k \neq \ell ,j} ( t_\ell - t_k ) / ( t_j - t_k ) +\end{array} +\] $$ +We define the vector $latex \alpha \in \B{R}^{m+1}$$ by +$latex \[ +\alpha_j = \left\{ \begin{array}{ll} +\sum_{k \neq m} ( t_m - t_k )^{-1} + & {\rm if} \; j = m +\\ +( t_j - t_m )^{-1} +\prod_{k \neq m,j} ( t_m - t_k ) / ( t_j - t_k ) + & {\rm otherwise} +\end{array} \right. +\] $$ +It follows that +$latex \[ + p^\prime ( t_m ) = \alpha_0 x_0 + \cdots + \alpha_m x_m +\] $$ +Gear's method determines $latex x_m$$ by solving the following +nonlinear equation +$latex \[ + f( t_m , x_m ) = \alpha_0 x_0 + \cdots + \alpha_m x_m +\] $$ +Newton's method for solving this equation determines iterates, +which we denote by $latex x_m^k$$, by solving the following affine +approximation of the equation above +$latex \[ +\begin{array}{rcl} +f( t_m , x_m^{k-1} ) + \partial_x f( t_m , x_m^{k-1} ) ( x_m^k - x_m^{k-1} ) +& = & +\alpha_0 x_0^k + \alpha_1 x_1 + \cdots + \alpha_m x_m +\\ +\left[ \alpha_m I - \partial_x f( t_m , x_m^{k-1} ) \right] x_m +& = & +\left[ +f( t_m , x_m^{k-1} ) - \partial_x f( t_m , x_m^{k-1} ) x_m^{k-1} +- \alpha_0 x_0 - \cdots - \alpha_{m-1} x_{m-1} +\right] +\end{array} +\] $$ +In order to initialize Newton's method; i.e. choose $latex x_m^0$$ +we define the vector $latex \beta \in \B{R}^{m+1}$$ by +$latex \[ +\beta_j = \left\{ \begin{array}{ll} +\sum_{k \neq m-1} ( t_{m-1} - t_k )^{-1} + & {\rm if} \; j = m-1 +\\ +( t_j - t_{m-1} )^{-1} +\prod_{k \neq m-1,j} ( t_{m-1} - t_k ) / ( t_j - t_k ) + & {\rm otherwise} +\end{array} \right. +\] $$ +It follows that +$latex \[ + p^\prime ( t_{m-1} ) = \beta_0 x_0 + \cdots + \beta_m x_m +\] $$ +We solve the following approximation of the equation above to determine +$latex x_m^0$$: +$latex \[ + f( t_{m-1} , x_{m-1} ) = + \beta_0 x_0 + \cdots + \beta_{m-1} x_{m-1} + \beta_m x_m^0 +\] $$ + + +$head Gear's Method$$ +C. W. Gear, +``Simultaneous Numerical Solution of Differential-Algebraic Equations,'' +IEEE Transactions on Circuit Theory, +vol. 18, no. 1, pp. 89-95, Jan. 1971. + + +$end +-------------------------------------------------------------------------- +*/ + +# include +# include +# include +# include +# include +# include +# include + +namespace CppAD { // BEGIN CppAD namespace + +template +void OdeGear( + Fun &F , + size_t m , + size_t n , + const Vector &T , + Vector &X , + Vector &e ) +{ + // temporary indices + size_t i, j, k; + + typedef typename Vector::value_type Scalar; + + // check numeric type specifications + CheckNumericType(); + + // check simple vector class specifications + CheckSimpleVector(); + + CPPAD_ASSERT_KNOWN( + m >= 1, + "OdeGear: m is less than one" + ); + CPPAD_ASSERT_KNOWN( + n > 0, + "OdeGear: n is equal to zero" + ); + CPPAD_ASSERT_KNOWN( + size_t(T.size()) >= (m+1), + "OdeGear: size of T is not greater than or equal (m+1)" + ); + CPPAD_ASSERT_KNOWN( + size_t(X.size()) >= (m+1) * n, + "OdeGear: size of X is not greater than or equal (m+1) * n" + ); + for(j = 0; j < m; j++) CPPAD_ASSERT_KNOWN( + T[j] < T[j+1], + "OdeGear: the array T is not monotone increasing" + ); + + // some constants + Scalar zero(0); + Scalar one(1); + + // vectors required by method + Vector alpha(m + 1); + Vector beta(m + 1); + Vector f(n); + Vector f_x(n * n); + Vector x_m0(n); + Vector x_m(n); + Vector b(n); + Vector A(n * n); + + // compute alpha[m] + alpha[m] = zero; + for(k = 0; k < m; k++) + alpha[m] += one / (T[m] - T[k]); + + // compute beta[m-1] + beta[m-1] = one / (T[m-1] - T[m]); + for(k = 0; k < m-1; k++) + beta[m-1] += one / (T[m-1] - T[k]); + + + // compute other components of alpha + for(j = 0; j < m; j++) + { // compute alpha[j] + alpha[j] = one / (T[j] - T[m]); + for(k = 0; k < m; k++) + { if( k != j ) + { alpha[j] *= (T[m] - T[k]); + alpha[j] /= (T[j] - T[k]); + } + } + } + + // compute other components of beta + for(j = 0; j <= m; j++) + { if( j != m-1 ) + { // compute beta[j] + beta[j] = one / (T[j] - T[m-1]); + for(k = 0; k <= m; k++) + { if( k != j && k != m-1 ) + { beta[j] *= (T[m-1] - T[k]); + beta[j] /= (T[j] - T[k]); + } + } + } + } + + // evaluate f(T[m-1], x_{m-1} ) + for(i = 0; i < n; i++) + x_m[i] = X[(m-1) * n + i]; + F.Ode(T[m-1], x_m, f); + + // solve for x_m^0 + for(i = 0; i < n; i++) + { x_m[i] = f[i]; + for(j = 0; j < m; j++) + x_m[i] -= beta[j] * X[j * n + i]; + x_m[i] /= beta[m]; + } + x_m0 = x_m; + + // evaluate partial w.r.t x of f(T[m], x_m^0) + F.Ode_dep(T[m], x_m, f_x); + + // compute the matrix A = ( alpha[m] * I - f_x ) + for(i = 0; i < n; i++) + { for(j = 0; j < n; j++) + A[i * n + j] = - f_x[i * n + j]; + A[i * n + i] += alpha[m]; + } + + // LU factor (and overwrite) the matrix A + CppAD::vector ip(n) , jp(n); +# ifndef NDEBUG + int sign = +# endif + LuFactor(ip, jp, A); + CPPAD_ASSERT_KNOWN( + sign != 0, + "OdeGear: step size is to large" + ); + + // Iterations of Newton's method + for(k = 0; k < 3; k++) + { + // only evaluate f( T[m] , x_m ) keep f_x during iteration + F.Ode(T[m], x_m, f); + + // b = f + f_x x_m - alpha[0] x_0 - ... - alpha[m-1] x_{m-1} + for(i = 0; i < n; i++) + { b[i] = f[i]; + for(j = 0; j < n; j++) + b[i] -= f_x[i * n + j] * x_m[j]; + for(j = 0; j < m; j++) + b[i] -= alpha[j] * X[ j * n + i ]; + } + LuInvert(ip, jp, A, b); + x_m = b; + } + + // return estimate for x( t[k] ) and the estimated error bound + for(i = 0; i < n; i++) + { X[m * n + i] = x_m[i]; + e[i] = x_m[i] - x_m0[i]; + if( e[i] < zero ) + e[i] = - e[i]; + } +} + +} // End CppAD namespace + +# endif diff --git a/build-config/cppad/include/cppad/utility/ode_gear_control.hpp b/build-config/cppad/include/cppad/utility/ode_gear_control.hpp new file mode 100644 index 00000000..68f75ec9 --- /dev/null +++ b/build-config/cppad/include/cppad/utility/ode_gear_control.hpp @@ -0,0 +1,544 @@ +# ifndef CPPAD_UTILITY_ODE_GEAR_CONTROL_HPP +# define CPPAD_UTILITY_ODE_GEAR_CONTROL_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +/* +$begin OdeGearControl$$ +$spell + cppad.hpp + CppAD + xf + xi + smin + smax + eabs + ef + maxabs + nstep + tf + sini + erel + dep + const + tb + ta + exp +$$ + + + +$section An Error Controller for Gear's Ode Solvers$$ + +$head Syntax$$ +$codei%# include +%$$ +$icode%xf% = OdeGearControl(%F%, %M%, %ti%, %tf%, %xi%, + %smin%, %smax%, %sini%, %eabs%, %erel%, %ef% , %maxabs%, %nstep% )%$$ + + +$head Purpose$$ +Let $latex \B{R}$$ denote the real numbers +and let $latex f : \B{R} \times \B{R}^n \rightarrow \B{R}^n$$ be a smooth function. +We define $latex X : [ti , tf] \rightarrow \B{R}^n$$ by +the following initial value problem: +$latex \[ +\begin{array}{rcl} + X(ti) & = & xi \\ + X'(t) & = & f[t , X(t)] +\end{array} +\] $$ +The routine $cref OdeGear$$ is a stiff multi-step method that +can be used to approximate the solution to this equation. +The routine $code OdeGearControl$$ sets up this multi-step method +and controls the error during such an approximation. + +$head Include$$ +The file $code cppad/utility/ode_gear_control.hpp$$ +is included by $code cppad/cppad.hpp$$ +but it can also be included separately with out the rest of +the $code CppAD$$ routines. + +$head Notation$$ +The template parameter types $cref/Scalar/OdeGearControl/Scalar/$$ and +$cref/Vector/OdeGearControl/Vector/$$ are documented below. + +$head xf$$ +The return value $icode xf$$ has the prototype +$codei% + %Vector% %xf% +%$$ +and the size of $icode xf$$ is equal to $icode n$$ +(see description of $cref/Vector/OdeGear/Vector/$$ below). +It is the approximation for $latex X(tf)$$. + +$head Fun$$ +The class $icode Fun$$ +and the object $icode F$$ satisfy the prototype +$codei% + %Fun% &%F% +%$$ +This must support the following set of calls +$codei% + %F%.Ode(%t%, %x%, %f%) + %F%.Ode_dep(%t%, %x%, %f_x%) +%$$ + +$subhead t$$ +The argument $icode t$$ has prototype +$codei% + const %Scalar% &%t% +%$$ +(see description of $cref/Scalar/OdeGear/Scalar/$$ below). + +$subhead x$$ +The argument $icode x$$ has prototype +$codei% + const %Vector% &%x% +%$$ +and has size $icode N$$ +(see description of $cref/Vector/OdeGear/Vector/$$ below). + +$subhead f$$ +The argument $icode f$$ to $icode%F%.Ode%$$ has prototype +$codei% + %Vector% &%f% +%$$ +On input and output, $icode f$$ is a vector of size $icode N$$ +and the input values of the elements of $icode f$$ do not matter. +On output, +$icode f$$ is set equal to $latex f(t, x)$$ +(see $icode f(t, x)$$ in $cref/Purpose/OdeGear/Purpose/$$). + +$subhead f_x$$ +The argument $icode f_x$$ has prototype +$codei% + %Vector% &%f_x% +%$$ +On input and output, $icode f_x$$ is a vector of size $latex N * N$$ +and the input values of the elements of $icode f_x$$ do not matter. +On output, +$latex \[ + f\_x [i * n + j] = \partial_{x(j)} f_i ( t , x ) +\] $$ + +$subhead Warning$$ +The arguments $icode f$$, and $icode f_x$$ +must have a call by reference in their prototypes; i.e., +do not forget the $code &$$ in the prototype for +$icode f$$ and $icode f_x$$. + +$head M$$ +The argument $icode M$$ has prototype +$codei% + size_t %M% +%$$ +It specifies the order of the multi-step method; i.e., +the order of the approximating polynomial +(after the initialization process). +The argument $icode M$$ must greater than or equal one. + +$head ti$$ +The argument $icode ti$$ has prototype +$codei% + const %Scalar% &%ti% +%$$ +It specifies the initial time for the integration of +the differential equation. + +$head tf$$ +The argument $icode tf$$ has prototype +$codei% + const %Scalar% &%tf% +%$$ +It specifies the final time for the integration of +the differential equation. + +$head xi$$ +The argument $icode xi$$ has prototype +$codei% + const %Vector% &%xi% +%$$ +and size $icode n$$. +It specifies value of $latex X(ti)$$. + +$head smin$$ +The argument $icode smin$$ has prototype +$codei% + const %Scalar% &%smin% +%$$ +The minimum value of $latex T[M] - T[M-1]$$ in a call to $code OdeGear$$ +will be $latex smin$$ except for the last two calls where it may be +as small as $latex smin / 2$$. +The value of $icode smin$$ must be less than or equal $icode smax$$. + +$head smax$$ +The argument $icode smax$$ has prototype +$codei% + const %Scalar% &%smax% +%$$ +It specifies the maximum step size to use during the integration; +i.e., the maximum value for $latex T[M] - T[M-1]$$ +in a call to $code OdeGear$$. + +$head sini$$ +The argument $icode sini$$ has prototype +$codei% + %Scalar% &%sini% +%$$ +The value of $icode sini$$ is the minimum +step size to use during initialization of the multi-step method; i.e., +for calls to $code OdeGear$$ where $latex m < M$$. +The value of $icode sini$$ must be less than or equal $icode smax$$ +(and can also be less than $icode smin$$). + +$head eabs$$ +The argument $icode eabs$$ has prototype +$codei% + const %Vector% &%eabs% +%$$ +and size $icode n$$. +Each of the elements of $icode eabs$$ must be +greater than or equal zero. +It specifies a bound for the absolute +error in the return value $icode xf$$ as an approximation for $latex X(tf)$$. +(see the +$cref/error criteria discussion/OdeGearControl/Error Criteria Discussion/$$ +below). + +$head erel$$ +The argument $icode erel$$ has prototype +$codei% + const %Scalar% &%erel% +%$$ +and is greater than or equal zero. +It specifies a bound for the relative +error in the return value $icode xf$$ as an approximation for $latex X(tf)$$ +(see the +$cref/error criteria discussion/OdeGearControl/Error Criteria Discussion/$$ +below). + +$head ef$$ +The argument value $icode ef$$ has prototype +$codei% + %Vector% &%ef% +%$$ +and size $icode n$$. +The input value of its elements does not matter. +On output, +it contains an estimated bound for the +absolute error in the approximation $icode xf$$; i.e., +$latex \[ + ef_i > | X( tf )_i - xf_i | +\] $$ + +$head maxabs$$ +The argument $icode maxabs$$ is optional in the call to $code OdeGearControl$$. +If it is present, it has the prototype +$codei% + %Vector% &%maxabs% +%$$ +and size $icode n$$. +The input value of its elements does not matter. +On output, +it contains an estimate for the +maximum absolute value of $latex X(t)$$; i.e., +$latex \[ + maxabs[i] \approx \max \left\{ + | X( t )_i | \; : \; t \in [ti, tf] + \right\} +\] $$ + +$head nstep$$ +The argument $icode nstep$$ has the prototype +$codei% + %size_t% &%nstep% +%$$ +Its input value does not matter and its output value +is the number of calls to $cref OdeGear$$ +used by $code OdeGearControl$$. + +$head Error Criteria Discussion$$ +The relative error criteria $icode erel$$ and +absolute error criteria $icode eabs$$ are enforced during each step of the +integration of the ordinary differential equations. +In addition, they are inversely scaled by the step size so that +the total error bound is less than the sum of the error bounds. +To be specific, if $latex \tilde{X} (t)$$ is the approximate solution +at time $latex t$$, +$icode ta$$ is the initial step time, +and $icode tb$$ is the final step time, +$latex \[ +\left| \tilde{X} (tb)_j - X (tb)_j \right| +\leq +\frac{tf - ti}{tb - ta} +\left[ eabs[j] + erel \; | \tilde{X} (tb)_j | \right] +\] $$ +If $latex X(tb)_j$$ is near zero for some $latex tb \in [ti , tf]$$, +and one uses an absolute error criteria $latex eabs[j]$$ of zero, +the error criteria above will force $code OdeGearControl$$ +to use step sizes equal to +$cref/smin/OdeGearControl/smin/$$ +for steps ending near $latex tb$$. +In this case, the error relative to $icode maxabs$$ can be judged after +$code OdeGearControl$$ returns. +If $icode ef$$ is to large relative to $icode maxabs$$, +$code OdeGearControl$$ can be called again +with a smaller value of $icode smin$$. + +$head Scalar$$ +The type $icode Scalar$$ must satisfy the conditions +for a $cref NumericType$$ type. +The routine $cref CheckNumericType$$ will generate an error message +if this is not the case. +In addition, the following operations must be defined for +$icode Scalar$$ objects $icode a$$ and $icode b$$: + +$table +$bold Operation$$ $cnext $bold Description$$ $rnext +$icode%a% <= %b%$$ $cnext + returns true (false) if $icode a$$ is less than or equal + (greater than) $icode b$$. +$rnext +$icode%a% == %b%$$ $cnext + returns true (false) if $icode a$$ is equal to $icode b$$. +$rnext +$codei%log(%a%)%$$ $cnext + returns a $icode Scalar$$ equal to the logarithm of $icode a$$ +$rnext +$codei%exp(%a%)%$$ $cnext + returns a $icode Scalar$$ equal to the exponential of $icode a$$ +$tend + + +$head Vector$$ +The type $icode Vector$$ must be a $cref SimpleVector$$ class with +$cref/elements of type Scalar/SimpleVector/Elements of Specified Type/$$. +The routine $cref CheckSimpleVector$$ will generate an error message +if this is not the case. + +$head Example$$ +$children% + example/utility/ode_gear_control.cpp +%$$ +The file +$cref ode_gear_control.cpp$$ +contains an example and test a test of using this routine. + +$head Theory$$ +Let $latex e(s)$$ be the error as a function of the +step size $latex s$$ and suppose that there is a constant +$latex K$$ such that $latex e(s) = K s^m$$. +Let $latex a$$ be our error bound. +Given the value of $latex e(s)$$, a step of size $latex \lambda s$$ +would be ok provided that +$latex \[ +\begin{array}{rcl} + a & \geq & e( \lambda s ) (tf - ti) / ( \lambda s ) \\ + a & \geq & K \lambda^m s^m (tf - ti) / ( \lambda s ) \\ + a & \geq & \lambda^{m-1} s^{m-1} (tf - ti) e(s) / s^m \\ + a & \geq & \lambda^{m-1} (tf - ti) e(s) / s \\ + \lambda^{m-1} & \leq & \frac{a}{e(s)} \frac{s}{tf - ti} +\end{array} +\] $$ +Thus if the right hand side of the last inequality is greater +than or equal to one, the step of size $latex s$$ is ok. + +$head Source Code$$ +The source code for this routine is in the file +$code cppad/ode_gear_control.hpp$$. + +$end +-------------------------------------------------------------------------- +*/ + +// link exp and log for float and double +# include + +# include + +namespace CppAD { // Begin CppAD namespace + +template +Vector OdeGearControl( + Fun &F , + size_t M , + const Scalar &ti , + const Scalar &tf , + const Vector &xi , + const Scalar &smin , + const Scalar &smax , + Scalar &sini , + const Vector &eabs , + const Scalar &erel , + Vector &ef , + Vector &maxabs, + size_t &nstep ) +{ + // check simple vector class specifications + CheckSimpleVector(); + + // dimension of the state space + size_t n = size_t(xi.size()); + + CPPAD_ASSERT_KNOWN( + M >= 1, + "Error in OdeGearControl: M is less than one" + ); + CPPAD_ASSERT_KNOWN( + smin <= smax, + "Error in OdeGearControl: smin is greater than smax" + ); + CPPAD_ASSERT_KNOWN( + sini <= smax, + "Error in OdeGearControl: sini is greater than smax" + ); + CPPAD_ASSERT_KNOWN( + size_t(eabs.size()) == n, + "Error in OdeGearControl: size of eabs is not equal to n" + ); + CPPAD_ASSERT_KNOWN( + size_t(maxabs.size()) == n, + "Error in OdeGearControl: size of maxabs is not equal to n" + ); + + // some constants + const Scalar zero(0); + const Scalar one(1); + const Scalar one_plus( Scalar(3) / Scalar(2) ); + const Scalar two(2); + const Scalar ten(10); + + // temporary indices + size_t i, k; + + // temporary Scalars + Scalar step, sprevious, lambda, axi, a, root, r; + + // vectors of Scalars + Vector T (M + 1); + Vector X( (M + 1) * n ); + Vector e(n); + Vector xf(n); + + // initial integer values + size_t m = 1; + nstep = 0; + + // initialize T + T[0] = ti; + + // initialize X, ef, maxabs + for(i = 0; i < n; i++) + for(i = 0; i < n; i++) + { X[i] = xi[i]; + ef[i] = zero; + X[i] = xi[i]; + if( zero <= xi[i] ) + maxabs[i] = xi[i]; + else + maxabs[i] = - xi[i]; + + } + + // initial step size + step = smin; + + while( T[m-1] < tf ) + { sprevious = step; + + // check maximum + if( smax <= step ) + step = smax; + + // check minimum + if( m < M ) + { if( step <= sini ) + step = sini; + } + else + if( step <= smin ) + step = smin; + + // check if near the end + if( tf <= T[m-1] + one_plus * step ) + T[m] = tf; + else + T[m] = T[m-1] + step; + + // try using this step size + nstep++; + OdeGear(F, m, n, T, X, e); + step = T[m] - T[m-1]; + + // compute value of lambda for this step + lambda = Scalar(10) * sprevious / step; + for(i = 0; i < n; i++) + { axi = X[m * n + i]; + if( axi <= zero ) + axi = - axi; + a = eabs[i] + erel * axi; + if( e[i] > zero ) + { if( m == 1 ) + root = (a / e[i]) / ten; + else + { r = ( a / e[i] ) * step / (tf - ti); + root = exp( log(r) / Scalar(m-1) ); + } + if( root <= lambda ) + lambda = root; + } + } + + bool advance; + if( m == M ) + advance = one <= lambda || step <= one_plus * smin; + else + advance = one <= lambda || step <= one_plus * sini; + + + if( advance ) + { // accept the results of this time step + CPPAD_ASSERT_UNKNOWN( m <= M ); + if( m == M ) + { // shift for next step + for(k = 0; k < m; k++) + { T[k] = T[k+1]; + for(i = 0; i < n; i++) + X[k*n + i] = X[(k+1)*n + i]; + } + } + // update ef and maxabs + for(i = 0; i < n; i++) + { ef[i] = ef[i] + e[i]; + axi = X[m * n + i]; + if( axi <= zero ) + axi = - axi; + if( axi > maxabs[i] ) + maxabs[i] = axi; + } + if( m != M ) + m++; // all we need do in this case + } + + // new step suggested by error criteria + step = std::min(lambda , ten) * step / two; + } + for(i = 0; i < n; i++) + xf[i] = X[(m-1) * n + i]; + + return xf; +} + +} // End CppAD namespace + +# endif diff --git a/build-config/cppad/include/cppad/utility/omh/cppad_vector.omh b/build-config/cppad/include/cppad/utility/omh/cppad_vector.omh new file mode 100644 index 00000000..21aa56af --- /dev/null +++ b/build-config/cppad/include/cppad/utility/omh/cppad_vector.omh @@ -0,0 +1,408 @@ +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +$begin CppAD_vector$$ +$spell + rvalues + thread_alloc + cppad.hpp + Bool + resize + cout + endl + std + Cpp + const + vec + ostream + elem + Iterators + typename + iterator + resized + dereference +$$ + + +$section The CppAD::vector Template Class$$ + +$head Syntax$$ +$codei%# include +%$$ +$codei%# include +%$$ +$codei%CppAD::vector<%Scalar%> %vec%, %other% +%$$ + +$head Description$$ +The include file $code cppad/vector.hpp$$ defines the +vector template class $code CppAD::vector$$. +This is a $cref SimpleVector$$ template class and in addition +it has the features listed below. +The purposes for this template vector class are as follows: +$list number$$ +If $code NDEBUG$$ is not defined, it checks for all +memory accesses to make sure the corresponding index is valid. +This includes when using its +$cref/iterators/CppAD_vector/Iterators/$$ +$lnext +It has a simple set of private member variables that make it +easy to understand when viewing its values in a C++ debugger. +$lnext +It uses the $cref thread_alloc$$ memory allocator which makes it fast +in a multi-threading environment; see +$cref/memory and parallel mode/CppAD_vector/Memory and Parallel Mode/$$. +$lnext +The operations it has are like the corresponding $code std::vector$$ +operation so it is easy to use. +$lend + +$head Include$$ +The files +$code cppad/utility/vector.hpp$$ and $code cppad/utility/vector_bool.hpp$$ are +included by $code cppad/cppad.hpp$$. +They can also be included separately with out the rest of the +CppAD include files. + +$subhead Deprecated 2019-08-19$$ +The file $code cppad/utility/vector.hpp$$ +includes the $code cppad/utility/vector_bool.hpp$$ +because they used to be one file. +If you want $cref/vectorBool/CppAD_vector/vectorBool/$$, +and not the rest of CppAD, you should include +$code cppad/utility/vector_bool.hpp$$. + +$head Integer Size$$ +The size $icode n$$ in the constructor syntax below can be an +$code int$$ (all simple vectors support $code size_t$$): +$codei% + CppAD::vector<%Scalar%> %vec%(%n%) +%$$ + +$head capacity$$ +If $icode cap$$ is a $code size_t$$ object, +$codei% + %cap% = %vec%.capacity() +%$$ +set $icode cap$$ to the number of $icode Scalar$$ objects that +could fit in the memory currently allocated for $icode vec$$. +Note that +$codei% + %vec%.size() <= %vec%.capacity() +%$$ + +$head swap$$ +$icode%vec%.swap(%other%) +%$$ +exchanges the contents of $icode vec$$ and $icode other$$. +For example $cref/vec.data()/CppAD_vector/data/$$ after the $code swap$$ +is equal to $icode%other%.data()%$$ before $code swap$$. + + +$head Assignment$$ +$icode%vec% = %other% +%$$ +has all the properties listed for a +$cref/simple vector assignment/SimpleVector/Assignment/$$ +plus the following: + +$subhead Check Size$$ +The size of $icode vec$$ must be either zero +or the same size as $icode other$$ before doing the assignment. +If this is not the case, and $code NDEBUG$$ is not defined, +$code CppAD::vector$$ will use +$cref ErrorHandler$$ +to generate an appropriate error report. +Requiring the sizes to agree checks that memory will not need to +be allocated to do the assignment (except when $icode vec$$ is empty). +Allowing for assignment to a vector with size zero makes the following +code work: +$codei% + CppAD::vector<%Scalar%> %vec%; + %vec% = %other%; +%$$ + +$subhead Return Reference$$ +A reference to the vector $icode vec$$ is returned. +An example use of this reference is in multiple assignments of the form +$codei% + %vec% = %other% = %another% +%$$ +where $icode another$$ is a $codei%CppAD::vector<%Scalar%>%$$ object. + +$subhead Move Semantics$$ +If the C++ compiler supports move semantic rvalues using the $code &&$$ +syntax, then it will be used during the vector assignment statement. +This means that return values and other temporaries are not be copied, +but rather pointers are transferred. + +$head Element Access$$ +If $icode i$$ has type $code size_t$$, +$codei% + %vec%[%i%] +%$$ +has all the properties listed for a +$cref/simple vector element access/SimpleVector/Element Access/$$ +plus the following: + +$subhead i$$ +This operation is defined for any $icode i$$ +that has a conversion to $code size_t$$. +The object $icode%vec%[%i%]%$$ has type $icode Scalar$$ +(is not possibly a different type that can be converted to $icode Scalar$$). + +$subhead Error Checking$$ +If $icode i$$ is not less than the size of the $icode vec$$, +and $code NDEBUUG$$ is not defined, +$code CppAD::vector$$ will use +$cref ErrorHandler$$ +to generate an appropriate error report. + +$head push_back$$ +If $icode vec$$ has size $icode n$$ and +$icode scalar$$ has type $icode Scalar$$, +$codei% + %vec%.push_back(%scalar%) +%$$ +extends the vector so that its new size is $icode%n%+1%$$ +and $icode%vec%[%n%]%$$ is equal to $icode s$$ +(equal in the sense of the $icode Scalar$$ assignment operator). + +$head push_vector$$ +If $icode vec$$ has size $icode n$$ and +$icode simple_vec$$ is a $cref/simple vector/SimpleVector/$$ +with elements of type $icode Scalar$$ and size $icode m$$, +$codei% + %vec%.push_vector(%simple_vec%) +%$$ +extends the vector $icode vec$$ so that its new size is $icode%n%+%m%$$ +and $icode%vec%[%n% + %i%]%$$ is equal to $icode%simple_vec%[%i%]%$$ +for $icode%i = 1 , ... , m-1%$$ +(equal in the sense of the $icode Scalar$$ assignment operator). + +$head Output$$ +If $icode os$$ is an $code std::ostream$$, the operation +$codei% + %os% << %vec% +%$$ +will output $icode vec$$ to the standard output stream $icode os$$. +The elements of $icode vec$$ are enclosed at the beginning by a +$code {$$ character, +they are separated by $code ,$$ characters, +and they are enclosed at the end by $code }$$ character. +It is assumed by this operation that if $icode scalar$$ +is an object with type $icode Scalar$$, +$codei% + %os% << %scalar% +%$$ +will output the value $icode scalar$$ to $icode os$$. + +$head resize$$ +If $icode n$$ is a $code size_t$$, +$codei% + %vec%.resize(%n%) +%$$ +sets the size of $icode vec$$ equal to $icode n$$. + +$subhead data$$ +The elements in $icode vec$$ before the resize operation are preserved. + +$subhead memory$$ +If before the resize, $icode%n% <= %vec%.capacity()%$$, +no memory is freed or allocated and +the capacity of $icode vec$$ does not change. +Otherwise, new memory is allocated and the elements before the resize +are copied to the new memory. +If you do not need to the elements previously in the vector, +you can resize to zero and then to the new size to avoid the copy. + +$head clear$$ +$icode%vec%.clear() +%$$ +frees all memory allocated for $icode vec$$ +and both its size and capacity are set to zero. +This can be useful when using very large vectors +and when checking for memory leaks (and there are global vectors) +see the $cref/memory/CppAD_vector/Memory and Parallel Mode/$$ discussion. + +$head data$$ +$icode%vec%.data() +%$$ +returns a pointer to a $icode Scalar$$ object such that for +$codei%0 <= %i% < %vec%.size()%$$, +$icode%vec%[%i%]%$$ and $icode%vec%.data()[%i%]%$$ +are the same $icode Scalar$$ object. +If $icode vec$$ is $code const$$, the pointer is $code const$$. +If $icode%vec%.capacity()%$$ is zero, the value of the pointer is not defined. +The pointer may no longer be valid after the following operations on +$icode vec$$: +its destructor, +$code clear$$, +$code resize$$, +$code push_back$$, +$code push_vector$$, +assignment to another vector when original size of $icode vec$$ is zero. + +$head Iterators$$ + +$subhead Syntax$$ +$codei%typename CppAD::vector<%Scalar%>::iterator +%$$ +$codei%typename CppAD::vector<%Scalar%>::const_iterator +%$$ +$icode%vec%.begin() +%$$ +$icode%vec%.end() +%$$ + +$subhead iterator$$ +is a random access iterator type for non $code const$$ objects. + +$subhead const_iterator$$ +is a random access iterator type for a $code const$$ objects. +An $code iterator$$ can be converted to a $code const_iterator$$, +but not the other way around. + +$subhead begin$$ +is an iterator corresponding to the first element of the vector. +It is a $code const_iterator$$ ($code iterator$$) +depending on if $icode vec$$ is $code const$$ (not $code const$$) + +$subhead end$$ +is an iterator corresponding to just beyond the last element of the vector. +It is a $code const_iterator$$ ($code iterator$$) +depending on if $icode vec$$ is $code const$$ (not $code const$$) + +$subhead Error Checking$$ +Each element access (dereference of the iterator) +does an error check similar to the element access +$cref/error checking/CppAD_vector/Element Access/Error Checking/$$ above. +The error handler will also be called, +if $code NDEBUG$$ is not defined and +a comparison operator (e.g. $code >$$) is used between +two iterators that correspond to different vectors. + +$head vectorBool$$ +The file $code $$ defines the class +$code CppAD::vectorBool$$. +This has the same specifications as $code CppAD::vector$$ +with the following exceptions: + +$subhead Memory$$ +The class $code vectorBool$$ conserves on memory, +on the other hand, $code CppAD::vector$$ is expected to be faster +than $code vectorBool$$. + +$subhead bit_per_unit$$ +The static function call +$codei% + %size% = vectorBool::bit_per_unit() +%$$ +returns the $code size_t$$ value $icode s$$ +which is equal to the number of boolean values (bits) that are +packed into one operation unit. +Bits are accessed using a mask with the size of an operation unit. + +$subhead data$$ +The $cref/data/CppAD_vector/data/$$ function is not supported by +$code vectorBool$$. + +$subhead Iterators$$ +The $cref/Iterators/CppAD_vector/Iterators/$$ are not supported by +$code vectorBool$$. + +$subhead Output$$ +The $code CppAD::vectorBool$$ output operator +prints each boolean value as +a $code 0$$ for false, +a $code 1$$ for true, +and does not print any other output; i.e., +the vector is written a long sequence of zeros and ones with no +surrounding $code {$$, $code }$$ and with no separating commas or spaces. + +$subhead Element Type$$ +If $icode vec_bool$$ has type $code vectorBool$$ +and $icode i$$ has type $code size_t$$, +the element access value $icode%vec_bool%[%i%]%$$ has an unspecified type, +referred to here as $icode element_t$$, that supports the following +operations: + +$list number$$ +$icode element_t$$ can be converted to $code bool$$; e.g. +the following syntax is supported: +$codei% + static_cast( %vec_bool%[%i%] ) +%$$ + +$lnext +$icode element_t$$ supports the assignment operator $code =$$ where the +right hand side is a $code bool$$ or an $icode element_t$$ object; e.g., +if $icode flag$$ has type $code bool$$, the following syntax is supported: +$codei% + %vec_bool%[%i%] = %flag% +%$$ + +$lnext +The result of an assignment to an $icode element_t$$ +also has type $icode element_t$$. +For example, if $icode other_flag$$ has type $code bool$$, +the following syntax is supported: +$codei% + %other_flag% = %vec_bool%[%i%] = %flag% +%$$ +$lend + +$head Memory and Parallel Mode$$ +These vectors use the multi-threaded fast memory allocator +$cref thread_alloc$$: + +$list number$$ +The $cref/hold_memory/ta_hold_memory/$$ routine can be used +to make memory allocation faster. +$lnext +The routine $cref/parallel_setup/ta_parallel_setup/$$ must +be called before these vectors can be used +$cref/in parallel/ta_in_parallel/$$. +$lnext +Using these vectors affects the amount of memory +$cref/in_use/ta_inuse/$$ and $cref/available/ta_available/$$. +$lnext +Calling $cref/clear/CppAD_vector/clear/$$, +makes the corresponding memory available (though $code thread_alloc$$) +to the current thread. +$lnext +Available memory +can then be completely freed using $cref/free_available/ta_free_available/$$. +$lend + +$head Example$$ +$children% + example/utility/cppad_vector.cpp% + example/utility/vector_bool.cpp +%$$ +The files +$cref cppad_vector.cpp$$ and +$cref vector_bool.cpp$$ each +contain an example and test of this template class. +They return true if they succeed and false otherwise. + +$head Exercise$$ +Create and run a program that contains the following code: +$codep + CppAD::vector x(3); + size_t i; + for(i = 0; i < 3; i++) + x[i] = 4. - i; + std::cout << "x = " << x << std::endl; +$$ + +$end diff --git a/build-config/cppad/include/cppad/utility/omh/dev_cppad_vector.omh b/build-config/cppad/include/cppad/utility/omh/dev_cppad_vector.omh new file mode 100644 index 00000000..21843232 --- /dev/null +++ b/build-config/cppad/include/cppad/utility/omh/dev_cppad_vector.omh @@ -0,0 +1,29 @@ +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +$begin dev_cppad_vector$$ +$spell + CppAD +$$ + + +$section The CppAD Vector Template Class Developer Documentation$$ + +$head User API$$ +$cref cppad_vector$$ + +$childtable% + include/cppad/local/utility/cppad_vector_itr.hpp% + include/cppad/utility/vector.hpp +%$$ + +$end diff --git a/build-config/cppad/include/cppad/utility/omh/dev_utility.omh b/build-config/cppad/include/cppad/utility/omh/dev_utility.omh new file mode 100644 index 00000000..7b803bdf --- /dev/null +++ b/build-config/cppad/include/cppad/utility/omh/dev_utility.omh @@ -0,0 +1,25 @@ +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 Bradley M. Bell + + CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + + This Source Code may also be made available under the following + Secondary License when the conditions for such availability set forth + in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +-------------------------------------------------------------------------- */ + +$begin dev_utility$$ +$spell +$$ + + +$section General Purpose Utilities Developer Documentation$$ + +$childtable% + include/cppad/utility/omh/dev_cppad_vector.omh% + include/cppad/utility/omh/dev_vector_bool.omh +%$$ + +$end diff --git a/build-config/cppad/include/cppad/utility/omh/dev_vector_bool.omh b/build-config/cppad/include/cppad/utility/omh/dev_vector_bool.omh new file mode 100644 index 00000000..587eb822 --- /dev/null +++ b/build-config/cppad/include/cppad/utility/omh/dev_vector_bool.omh @@ -0,0 +1,30 @@ +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +$begin dev_vector_bool$$ +$spell + CppAD + Bool +$$ + + +$section vectorBool Developer Documentation$$ + +$head User API$$ +$cref/vectorBool/CppAD_vector/vectorBool/$$ + +$childtable% + include/cppad/local/utility/vector_bool.hpp% + include/cppad/utility/vector_bool.hpp +%$$ + +$end diff --git a/build-config/cppad/include/cppad/utility/omh/utility.omh b/build-config/cppad/include/cppad/utility/omh/utility.omh new file mode 100644 index 00000000..769093c3 --- /dev/null +++ b/build-config/cppad/include/cppad/utility/omh/utility.omh @@ -0,0 +1,156 @@ +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell + + CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + + This Source Code may also be made available under the following + Secondary License when the conditions for such availability set forth + in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +-------------------------------------------------------------------------- */ + +$begin utility$$ +$spell + CppAD + namespace + alloc + cppad.hpp +$$ + + +$section Some General Purpose Utilities$$ +These routines can be include individually; for example, +$codep + # include +$$ +only includes the definitions necessary for the $code CppAD::vector$$ class. +They can also be included as a group, separate from the rest of CppAD, using +$codep + # include +$$ +They will also be included, along with the rest of CppAD, using +$codep + # include +$$ + +$children% + include/cppad/utility/error_handler.hpp% + + include/cppad/utility/near_equal.hpp% + include/cppad/utility/speed_test.hpp% + include/cppad/utility/time_test.hpp% + include/cppad/utility/test_boolofvoid.hpp% + + omh/numeric_type.omh% + include/cppad/utility/check_numeric_type.hpp% + omh/simple_vector.omh% + include/cppad/utility/check_simple_vector.hpp% + + include/cppad/utility/nan.hpp% + include/cppad/utility/pow_int.hpp% + include/cppad/utility/poly.hpp% + omh/lu_det_and_solve.omh% + include/cppad/utility/romberg_one.hpp% + include/cppad/utility/romberg_mul.hpp% + include/cppad/utility/runge_45.hpp% + include/cppad/utility/rosen_34.hpp% + include/cppad/utility/ode_err_control.hpp% + include/cppad/utility/ode_gear.hpp% + include/cppad/utility/ode_gear_control.hpp% + + include/cppad/utility/omh/cppad_vector.omh% + omh/thread_alloc.omh% + include/cppad/utility/index_sort.hpp% + include/cppad/utility/to_string.hpp% + include/cppad/utility/set_union.hpp% + include/cppad/utility/sparse_rc.hpp% + include/cppad/utility/sparse_rcv.hpp% + include/cppad/utility/sparse2eigen.hpp +%$$ + +$head Testing$$ +The routines listed below support numerical correctness and speed testing: +$table +$rref NearEqual$$ +$rref time_test$$ +$rref speed_test$$ +$rref SpeedTest$$ +$rref test_boolofvoid$$ +$tend + +$head C++ Concepts$$ +We refer to a the set of classes that satisfy certain conditions +as a C++ concept. +The following concepts are used by the CppAD Template library: +$table +$rref NumericType$$ +$rref CheckNumericType$$ +$rref SimpleVector$$ +$rref CheckSimpleVector$$ +$tend + + +$head General Numerical Routines$$ +The routines listed below are general purpose numerical routines +written with the floating point type a C++ template parameter. +This enables them to be used with algorithmic differentiation types, +as well as for other purposes. +$table +$rref nan$$ +$rref pow_int$$ +$rref Poly$$ +$rref LuDetAndSolve$$ +$rref RombergOne$$ +$rref RombergMul$$ +$rref Runge45$$ +$rref Rosen34$$ +$rref OdeErrControl$$ +$rref OdeGear$$ +$rref OdeGearControl$$ +$tend + +$head Miscellaneous$$ + +$subhead Error Handler$$ +All of the routines in the CppAD namespace use the following +general purpose error handler: +$table +$rref ErrorHandler$$ +$tend + +$subhead The CppAD Vector Template Class$$ +This is a simple implementation of a template vector class +(that is easy to view in a C++ debugger): +$table +$rref CppAD_vector$$ +$tend + +$subhead Multi-Threading Memory Allocation$$ +$table +$rref thread_alloc$$ +$tend + +$subhead Sorting Indices$$ +$table +$rref index_sort$$ +$tend + +$subhead to_string$$ +$table +$rref to_string$$ +$tend + +$subhead set_union$$ +$table +$rref set_union$$ +$tend + +$subhead Sparse Matrices$$ +$table +$rref sparse_rc$$ +$rref sparse_rcv$$ +$rref sparse2eigen$$ +$tend + +$end diff --git a/build-config/cppad/include/cppad/utility/omp_alloc.hpp b/build-config/cppad/include/cppad/utility/omp_alloc.hpp new file mode 100644 index 00000000..2b305f3f --- /dev/null +++ b/build-config/cppad/include/cppad/utility/omp_alloc.hpp @@ -0,0 +1,747 @@ +# ifndef CPPAD_UTILITY_OMP_ALLOC_HPP +# define CPPAD_UTILITY_OMP_ALLOC_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-18 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ +# include +# ifdef _OPENMP +# include +# endif + +namespace CppAD { // BEGIN_CPPAD_NAMESPACE +class omp_alloc{ +// ============================================================================ +public: +/* +$begin omp_max_num_threads$$ +$spell + cppad.hpp + inv + CppAD + num + omp_alloc +$$ +$section Set and Get Maximum Number of Threads for omp_alloc Allocator$$ + +$head Deprecated 2011-08-31$$ +Use the functions $cref/thread_alloc::parallel_setup/ta_parallel_setup/$$ +and $cref/thread_alloc:num_threads/ta_num_threads/$$ instead. + +$head Syntax$$ +$codei%# include +%$$ +$codei%omp_alloc::set_max_num_threads(%number%) +%$$ +$icode%number% = omp_alloc::get_max_num_threads() +%$$ + +$head Purpose$$ +By default there is only one thread and all execution is in sequential mode +(not $cref/parallel/omp_in_parallel/$$). + +$head number$$ +The argument and return value $icode number$$ has prototype +$codei% + size_t %number% +%$$ +and must be greater than zero. + +$head set_max_num_threads$$ +Informs $cref omp_alloc$$ of the maximum number of OpenMP threads. + +$head get_max_num_threads$$ +Returns the valued used in the previous call to $code set_max_num_threads$$. +If there was no such previous call, the value one is returned +(and only thread number zero can use $cref omp_alloc$$). + +$head Restrictions$$ +The function $code set_max_num_threads$$ must be called before +the program enters $cref/parallel/omp_in_parallel/$$ execution mode. +In addition, this function cannot be called while in parallel mode. + +$end +*/ + /*! + Inform omp_alloc of the maximum number of OpenMP threads and enable + parallel execution mode by initializing all statics in this file. + + \param number [in] + maximum number of OpenMP threads. + */ + static void set_max_num_threads(size_t number) + { thread_alloc::parallel_setup( + number, omp_alloc::in_parallel, omp_alloc::get_thread_num + ); + thread_alloc::hold_memory(number > 1); + } + /*! + Get the current maximum number of OpenMP threads that omp_alloc can use. + + \return + maximum number of OpenMP threads. + */ + static size_t get_max_num_threads(void) + { return thread_alloc::num_threads(); } + +/* ----------------------------------------------------------------------- +$begin omp_in_parallel$$ + +$section Is The Current Execution in OpenMP Parallel Mode$$ +$spell + cppad.hpp + omp_alloc + bool +$$ + +$head Deprecated 2011-08-31$$ +Use the function $cref/thread_alloc::in_parallel/ta_in_parallel/$$ instead. + +$head Syntax$$ +$codei%# include +%$$ +$icode%flag% = omp_alloc::in_parallel()%$$ + +$head Purpose$$ +Some of the $cref omp_alloc$$ allocation routines have different +specifications for parallel (not sequential) execution mode. +This routine enables you to determine if the current execution mode +is sequential or parallel. + +$head flag$$ +The return value has prototype +$codei% + bool %flag% +%$$ +It is true if the current execution is in parallel mode +(possibly multi-threaded) and false otherwise (sequential mode). + +$end +*/ + /// Are we in a parallel execution state; i.e., is it possible that + /// other threads are currently executing. + static bool in_parallel(void) + { +# ifdef _OPENMP + return omp_in_parallel() != 0; +# else + return false; +# endif + } + +/* ----------------------------------------------------------------------- +$begin omp_get_thread_num$$ +$spell + cppad.hpp + CppAD + num + omp_alloc + cppad.hpp +$$ + +$section Get the Current OpenMP Thread Number$$ + +$head Deprecated 2011-08-31$$ +Use the function $cref/thread_alloc::thread_num/ta_thread_num/$$ instead. + +$head Syntax$$ +$codei%# include +%$$ +$icode%thread% = omp_alloc::get_thread_num()%$$ + +$head Purpose$$ +Some of the $cref omp_alloc$$ allocation routines have a thread number. +This routine enables you to determine the current thread. + +$head thread$$ +The return value $icode thread$$ has prototype +$codei% + size_t %thread% +%$$ +and is the currently executing thread number. +If $code _OPENMP$$ is not defined, $icode thread$$ is zero. + +$end +*/ + /// Get current OpenMP thread number (zero if _OpenMP not defined). + static size_t get_thread_num(void) + { +# ifdef _OPENMP + size_t thread = static_cast( omp_get_thread_num() ); + return thread; +# else + return 0; +# endif + } +/* ----------------------------------------------------------------------- +$begin omp_get_memory$$ +$spell + cppad.hpp + num + ptr + omp_alloc +$$ + +$section Get At Least A Specified Amount of Memory$$ + +$head Deprecated 2011-08-31$$ +Use the function $cref/thread_alloc::get_memory/ta_get_memory/$$ instead. + +$head Syntax$$ +$codei%# include +%$$ +$icode%v_ptr% = omp_alloc::get_memory(%min_bytes%, %cap_bytes%)%$$ + +$head Purpose$$ +Use $cref omp_alloc$$ to obtain a minimum number of bytes of memory +(for use by the $cref/current thread/omp_get_thread_num/$$). + +$head min_bytes$$ +This argument has prototype +$codei% + size_t %min_bytes% +%$$ +It specifies the minimum number of bytes to allocate. + +$head cap_bytes$$ +This argument has prototype +$codei% + size_t& %cap_bytes% +%$$ +It's input value does not matter. +Upon return, it is the actual number of bytes (capacity) +that have been allocated for use, +$codei% + %min_bytes% <= %cap_bytes% +%$$ + +$head v_ptr$$ +The return value $icode v_ptr$$ has prototype +$codei% + void* %v_ptr% +%$$ +It is the location where the $icode cap_bytes$$ of memory +that have been allocated for use begins. + +$head Allocation Speed$$ +This allocation should be faster if the following conditions hold: +$list number$$ +The memory allocated by a previous call to $code get_memory$$ +is currently available for use. +$lnext +The current $icode min_bytes$$ is between +the previous $icode min_bytes$$ and previous $icode cap_bytes$$. +$lend + +$end +*/ + /*! + Use omp_alloc to get a specified amount of memory. + + If the memory allocated by a previous call to get_memory is now + avaialable, and min_bytes is between its previous value + and the previous cap_bytes, this memory allocation will have + optimal speed. Otherwise, the memory allocation is more complicated and + may have to wait for other threads to complete an allocation. + + \param min_bytes [in] + The minimum number of bytes of memory to be obtained for use. + + \param cap_bytes [out] + The actual number of bytes of memory obtained for use. + + \return + pointer to the beginning of the memory allocted for use. + */ + static void* get_memory(size_t min_bytes, size_t& cap_bytes) + { return thread_alloc::get_memory(min_bytes, cap_bytes); } + +/* ----------------------------------------------------------------------- +$begin omp_return_memory$$ +$spell + cppad.hpp + ptr + omp_alloc +$$ + +$section Return Memory to omp_alloc$$ + +$head Deprecated 2011-08-31$$ +Use the function $cref/thread_alloc::return_memory/ta_return_memory/$$ instead. + +$head Syntax$$ +$codei%# include +%$$ +$codei%omp_alloc::return_memory(%v_ptr%)%$$ + +$head Purpose$$ +If $cref omp_max_num_threads$$ is one, +the memory is returned to the system. +Otherwise, the memory is retained by $cref omp_alloc$$ for quick future use +by the thread that allocated to memory. + +$head v_ptr$$ +This argument has prototype +$codei% + void* %v_ptr% +%$$. +It must be a pointer to memory that is currently in use; i.e. +obtained by a previous call to $cref omp_get_memory$$ and not yet returned. + +$head Thread$$ +Either the $cref/current thread/omp_get_thread_num/$$ must be the same as during +the corresponding call to $cref omp_get_memory$$, +or the current execution mode must be sequential +(not $cref/parallel/omp_in_parallel/$$). + +$head NDEBUG$$ +If $code NDEBUG$$ is defined, $icode v_ptr$$ is not checked (this is faster). +Otherwise, a list of in use pointers is searched to make sure +that $icode v_ptr$$ is in the list. + +$end +*/ + /*! + Return memory that was obtained by get_memory. + If max_num_threads(0) == 1, + the memory is returned to the system. + Otherwise, it is retained by omp_alloc and available for use by + get_memory for this thread. + + \param v_ptr [in] + Value of the pointer returned by get_memory and still in use. + After this call, this pointer will available (and not in use). + + \par + We must either be in sequential (not parallel) execution mode, + or the current thread must be the same as for the corresponding call + to get_memory. + */ + static void return_memory(void* v_ptr) + { thread_alloc::return_memory(v_ptr); } +/* ----------------------------------------------------------------------- +$begin omp_free_available$$ +$spell + cppad.hpp + omp_alloc +$$ + +$section Free Memory Currently Available for Quick Use by a Thread$$ + +$head Deprecated 2011-08-31$$ +Use the function $cref/thread_alloc::free_available/ta_free_available/$$ +instead. + +$head Syntax$$ +$codei%# include +%$$ +$codei%omp_alloc::free_available(%thread%)%$$ + +$head Purpose$$ +Free memory, currently available for quick use by a specific thread, +for general future use. + +$head thread$$ +This argument has prototype +$codei% + size_t %thread% +%$$ +Either $cref omp_get_thread_num$$ must be the same as $icode thread$$, +or the current execution mode must be sequential +(not $cref/parallel/omp_in_parallel/$$). + +$end +*/ + /*! + Return all the memory being held as available for a thread to the system. + + \param thread [in] + this thread that will no longer have any available memory after this call. + This must either be the thread currently executing, or we must be + in sequential (not parallel) execution mode. + */ + static void free_available(size_t thread) + { thread_alloc::free_available(thread); } +/* ----------------------------------------------------------------------- +$begin omp_inuse$$ +$spell + cppad.hpp + num + inuse + omp_alloc +$$ + +$section Amount of Memory a Thread is Currently Using$$ + +$head Deprecated 2011-08-31$$ + +$head Syntax$$ +$codei%# include +%$$ +$icode%num_bytes% = omp_alloc::inuse(%thread%)%$$ +Use the function $cref/thread_alloc::inuse/ta_inuse/$$ instead. + +$head Purpose$$ +Memory being managed by $cref omp_alloc$$ has two states, +currently in use by the specified thread, +and quickly available for future use by the specified thread. +This function informs the program how much memory is in use. + +$head thread$$ +This argument has prototype +$codei% + size_t %thread% +%$$ +Either $cref omp_get_thread_num$$ must be the same as $icode thread$$, +or the current execution mode must be sequential +(not $cref/parallel/omp_in_parallel/$$). + +$head num_bytes$$ +The return value has prototype +$codei% + size_t %num_bytes% +%$$ +It is the number of bytes currently in use by the specified thread. + +$end +*/ + /*! + Determine the amount of memory that is currently inuse. + + \param thread [in] + Thread for which we are determining the amount of memory + (must be < CPPAD_MAX_NUM_THREADS). + Durring parallel execution, this must be the thread + that is currently executing. + + \return + The amount of memory in bytes. + */ + static size_t inuse(size_t thread) + { return thread_alloc::inuse(thread); } +/* ----------------------------------------------------------------------- +$begin omp_available$$ +$spell + cppad.hpp + num + omp_alloc +$$ + +$section Amount of Memory Available for Quick Use by a Thread$$ + +$head Deprecated 2011-08-31$$ +Use the function $cref/thread_alloc::available/ta_available/$$ instead. + +$head Syntax$$ +$codei%# include +%$$ +$icode%num_bytes% = omp_alloc::available(%thread%)%$$ + +$head Purpose$$ +Memory being managed by $cref omp_alloc$$ has two states, +currently in use by the specified thread, +and quickly available for future use by the specified thread. +This function informs the program how much memory is available. + +$head thread$$ +This argument has prototype +$codei% + size_t %thread% +%$$ +Either $cref omp_get_thread_num$$ must be the same as $icode thread$$, +or the current execution mode must be sequential +(not $cref/parallel/omp_in_parallel/$$). + +$head num_bytes$$ +The return value has prototype +$codei% + size_t %num_bytes% +%$$ +It is the number of bytes currently available for use by the specified thread. + +$end +*/ + /*! + Determine the amount of memory that is currently available for use. + + \copydetails inuse + */ + static size_t available(size_t thread) + { return thread_alloc::available(thread); } +/* ----------------------------------------------------------------------- +$begin omp_create_array$$ +$spell + cppad.hpp + omp_alloc + sizeof +$$ + +$section Allocate Memory and Create A Raw Array$$ + +$head Deprecated 2011-08-31$$ +Use the function $cref/thread_alloc::create_array/ta_create_array/$$ instead. + +$head Syntax$$ +$codei%# include +%$$ +$icode%array% = omp_alloc::create_array<%Type%>(%size_min%, %size_out%)%$$. + +$head Purpose$$ +Create a new raw array using $cref omp_alloc$$ a fast memory allocator +that works well in a multi-threading OpenMP environment. + +$head Type$$ +The type of the elements of the array. + +$head size_min$$ +This argument has prototype +$codei% + size_t %size_min% +%$$ +This is the minimum number of elements that there can be +in the resulting $icode array$$. + +$head size_out$$ +This argument has prototype +$codei% + size_t& %size_out% +%$$ +The input value of this argument does not matter. +Upon return, it is the actual number of elements +in $icode array$$ +($icode% size_min %<=% size_out%$$). + +$head array$$ +The return value $icode array$$ has prototype +$codei% + %Type%* %array% +%$$ +It is array with $icode size_out$$ elements. +The default constructor for $icode Type$$ is used to initialize the +elements of $icode array$$. +Note that $cref omp_delete_array$$ +should be used to destroy the array when it is no longer needed. + +$head Delta$$ +The amount of memory $cref omp_inuse$$ by the current thread, +will increase $icode delta$$ where +$codei% + sizeof(%Type%) * (%size_out% + 1) > %delta% >= sizeof(%Type%) * %size_out% +%$$ +The $cref omp_available$$ memory will decrease by $icode delta$$, +(and the allocation will be faster) +if a previous allocation with $icode size_min$$ between its current value +and $icode size_out$$ is available. + +$end +*/ + /*! + Use omp_alloc to Create a Raw Array. + + \tparam Type + The type of the elements of the array. + + \param size_min [in] + The minimum number of elements in the array. + + \param size_out [out] + The actual number of elements in the array. + + \return + pointer to the first element of the array. + The default constructor is used to initialize + all the elements of the array. + + \par + The extra_ field, in the omp_alloc node before the return value, + is set to size_out. + */ + template + static Type* create_array(size_t size_min, size_t& size_out) + { return thread_alloc::create_array(size_min, size_out); } +/* ----------------------------------------------------------------------- +$begin omp_delete_array$$ +$spell + cppad.hpp + omp_alloc + sizeof +$$ + +$section Return A Raw Array to The Available Memory for a Thread$$ + +$head Deprecated 2011-08-31$$ +Use the function $cref/thread_alloc::delete_array/ta_delete_array/$$ instead. + +$head Syntax$$ +$codei%# include +%$$ +$codei%omp_alloc::delete_array(%array%)%$$. + +$head Purpose$$ +Returns memory corresponding to a raw array +(create by $cref omp_create_array$$) to the +$cref omp_available$$ memory pool for the current thread. + +$head Type$$ +The type of the elements of the array. + +$head array$$ +The argument $icode array$$ has prototype +$codei% + %Type%* %array% +%$$ +It is a value returned by $cref omp_create_array$$ and not yet deleted. +The $icode Type$$ destructor is called for each element in the array. + +$head Thread$$ +The $cref/current thread/omp_get_thread_num/$$ must be the +same as when $cref omp_create_array$$ returned the value $icode array$$. +There is an exception to this rule: +when the current execution mode is sequential +(not $cref/parallel/omp_in_parallel/$$) the current thread number does not matter. + +$head Delta$$ +The amount of memory $cref omp_inuse$$ will decrease by $icode delta$$, +and the $cref omp_available$$ memory will increase by $icode delta$$, +where $cref/delta/omp_create_array/Delta/$$ +is the same as for the corresponding call to $code create_array$$. + +$end +*/ + /*! + Return Memory Used for a Raw Array to the Available Pool. + + \tparam Type + The type of the elements of the array. + + \param array [in] + A value returned by create_array that has not yet been deleted. + The Type destructor is used to destroy each of the elements + of the array. + + \par + Durring parallel execution, the current thread must be the same + as during the corresponding call to create_array. + */ + template + static void delete_array(Type* array) + { thread_alloc::delete_array(array); } +}; +/* -------------------------------------------------------------------------- +$begin omp_efficient$$ +$spell + cppad.hpp + omp_alloc + ptr + num + bool + const +$$ + +$section Check If A Memory Allocation is Efficient for Another Use$$ + +$head Removed$$ +This function has been removed because speed tests seem to indicate +it is just as fast, or faster, to free and then reallocate the memory. + +$head Syntax$$ +$codei%# include +%$$ +$icode%flag% = omp_alloc::efficient(%v_ptr%, %num_bytes%)%$$ + +$head Purpose$$ +Check if memory that is currently in use is an efficient +allocation for a specified number of bytes. + +$head v_ptr$$ +This argument has prototype +$codei% + const void* %v_ptr% +%$$. +It must be a pointer to memory that is currently in use; i.e. +obtained by a previous call to $cref omp_get_memory$$ and not yet returned. + +$head num_bytes$$ +This argument has prototype +$codei% + size_t %num_bytes% +%$$ +It specifies the number of bytes of the memory allocated by $icode v_ptr$$ +that we want to use. + +$head flag$$ +The return value has prototype +$codei% + bool %flag% +%$$ +It is true, +a call to $code get_memory$$ with +$cref/min_bytes/omp_get_memory/min_bytes/$$ +equal to $icode num_bytes$$ would result in a value for +$cref/cap_bytes/omp_get_memory/cap_bytes/$$ that is the same as when $code v_ptr$$ +was returned by $code get_memory$$; i.e., +$icode v_ptr$$ is an efficient memory block for $icode num_bytes$$ +bytes of information. + +$head Thread$$ +Either the $cref/current thread/omp_get_thread_num/$$ must be the same as during +the corresponding call to $cref omp_get_memory$$, +or the current execution mode must be sequential +(not $cref/parallel/omp_in_parallel/$$). + +$head NDEBUG$$ +If $code NDEBUG$$ is defined, $icode v_ptr$$ is not checked (this is faster). +Otherwise, a list of in use pointers is searched to make sure +that $icode v_ptr$$ is in the list. + +$end +--------------------------------------------------------------------------- +$begin old_max_num_threads$$ +$spell + cppad.hpp + inv + CppAD + num + omp_alloc +$$ +$section Set Maximum Number of Threads for omp_alloc Allocator$$ + +$head Removed$$ +This function has been removed from the CppAD API. +Use the function $cref/thread_alloc::parallel_setup/ta_parallel_setup/$$ +in its place. + +$head Syntax$$ +$codei%# include +%$$ +$codei%omp_alloc::max_num_threads(%number%)%$$ + +$head Purpose$$ +By default there is only one thread and all execution is in sequential mode +(not $cref/parallel/omp_in_parallel/$$). + +$head number$$ +The argument $icode number$$ has prototype +$codei% + size_t %number% +%$$ +It must be greater than zero and specifies the maximum number of +OpenMP threads that will be active at one time. + +$head Restrictions$$ +This function must be called before the program enters +$cref/parallel/omp_in_parallel/$$ execution mode. + +$end +------------------------------------------------------------------------------- +*/ +} // END_CPPAD_NAMESPACE + +# endif diff --git a/build-config/cppad/include/cppad/utility/poly.hpp b/build-config/cppad/include/cppad/utility/poly.hpp new file mode 100644 index 00000000..13588bbf --- /dev/null +++ b/build-config/cppad/include/cppad/utility/poly.hpp @@ -0,0 +1,192 @@ +# ifndef CPPAD_UTILITY_POLY_HPP +# define CPPAD_UTILITY_POLY_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ +/* +$begin Poly$$ +$spell + cppad.hpp + CppAD + namespace + cstddef + ifndef + endif + deg + const + std + da +$$ + + +$section Evaluate a Polynomial or its Derivative$$ + +$head Syntax$$ +$codei%# include +%$$ +$icode%p% = Poly(%k%, %a%, %z%)%$$ + + +$head Description$$ +Computes the $th k$$ derivative of the polynomial +$latex \[ + P(z) = a_0 + a_1 z^1 + \cdots + a_d z^d +\] $$ +If $icode k$$ is equal to zero, the return value is $latex P(z)$$. + +$head Include$$ +The file $code cppad/utility/poly.hpp$$ +is included by $code cppad/cppad.hpp$$ +but it can also be included separately with out the rest of +the $code CppAD$$ routines. +Including this file defines +$code Poly$$ within the $code CppAD$$ namespace. + +$head k$$ +The argument $icode k$$ has prototype +$codei% + size_t %k% +%$$ +It specifies the order of the derivative to calculate. + +$head a$$ +The argument $icode a$$ has prototype +$codei% + const %Vector% &%a% +%$$ +(see $cref/Vector/Poly/Vector/$$ below). +It specifies the vector corresponding to the polynomial $latex P(z)$$. + +$head z$$ +The argument $icode z$$ has prototype +$codei% + const %Type% &%z% +%$$ +(see $icode Type$$ below). +It specifies the point at which to evaluate the polynomial + +$head p$$ +The result $icode p$$ has prototype +$codei% + %Type% %p% +%$$ +(see $cref/Type/Poly/Type/$$ below) +and it is equal to the $th k$$ derivative of $latex P(z)$$; i.e., +$latex \[ +p = \frac{k !}{0 !} a_k + + \frac{(k+1) !}{1 !} a_{k+1} z^1 + + \ldots + + \frac{d !}{(d - k) !} a_d z^{d - k} +\] +$$ +If $latex k > d$$, $icode%p% = %Type%(0)%$$. + +$head Type$$ +The type $icode Type$$ is determined by the argument $icode z$$. +It is assumed that +multiplication and addition of $icode Type$$ objects +are commutative. + +$subhead Operations$$ +The following operations must be supported where +$icode x$$ and $icode y$$ are objects of type $icode Type$$ +and $icode i$$ is an $code int$$: +$table +$icode%x% = %i%$$ $cnext assignment $rnext +$icode%x% = %y%$$ $cnext assignment $rnext +$icode%x% *= %y%$$ $cnext multiplication compound assignment $rnext +$icode%x% += %y%$$ $cnext addition compound assignment + +$tend + + +$head Vector$$ +The type $icode Vector$$ must be a $cref SimpleVector$$ class with +$cref/elements of type/SimpleVector/Elements of Specified Type/$$ +$icode Type$$. +The routine $cref CheckSimpleVector$$ will generate an error message +if this is not the case. + +$head Operation Sequence$$ +The $icode Type$$ operation sequence used to calculate $icode p$$ is +$cref/independent/glossary/Operation/Independent/$$ +of $icode z$$ and the elements of $icode a$$ +(it does depend on the size of the vector $icode a$$). + + +$children% + example/utility/poly.cpp% + omh/poly_hpp.omh +%$$ + +$head Example$$ +The file +$cref poly.cpp$$ +contains an example and test of this routine. + +$head Source$$ +The file $cref poly.hpp$$ contains the +current source code that implements these specifications. + +$end +------------------------------------------------------------------------------ +*/ +// BEGIN C++ +# include // used to defined size_t +# include + +namespace CppAD { // BEGIN CppAD namespace + +template +Type Poly(size_t k, const Vector &a, const Type &z) +{ size_t i; + size_t d = a.size() - 1; + + Type tmp; + + // check Vector is Simple Vector class with Type elements + CheckSimpleVector(); + + // case where derivative order greater than degree of polynomial + if( k > d ) + { tmp = 0; + return tmp; + } + // case where we are evaluating a derivative + if( k > 0 ) + { // initialize factor as (k-1) ! + size_t factor = 1; + for(i = 2; i < k; i++) + factor *= i; + + // set b to coefficient vector corresponding to derivative + Vector b(d - k + 1); + for(i = k; i <= d; i++) + { factor *= i; + tmp = double( factor ); + b[i - k] = a[i] * tmp; + factor /= (i - k + 1); + } + // value of derivative polynomial + return Poly(0, b, z); + } + // case where we are evaluating the original polynomial + Type sum = a[d]; + i = d; + while(i > 0) + { sum *= z; + sum += a[--i]; + } + return sum; +} +} // END CppAD namespace +// END C++ +# endif diff --git a/build-config/cppad/include/cppad/utility/pow_int.hpp b/build-config/cppad/include/cppad/utility/pow_int.hpp new file mode 100644 index 00000000..2150fbc8 --- /dev/null +++ b/build-config/cppad/include/cppad/utility/pow_int.hpp @@ -0,0 +1,140 @@ +# ifndef CPPAD_UTILITY_POW_INT_HPP +# define CPPAD_UTILITY_POW_INT_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +/* +------------------------------------------------------------------------------- +$begin pow_int$$ +$spell + cppad.hpp + CppAD + namespace + const +$$ + + +$section The Integer Power Function$$ + +$head Syntax$$ +$codei%# include +%$$ +$icode%z% = pow(%x%, %y%)%$$ + +$head See Also$$ +$cref pow$$ + +$head Purpose$$ +Determines the value of the power function +$latex \[ + {\rm pow} (x, y) = x^y +\] $$ +for integer exponents $icode n$$ +using multiplication and possibly division to compute the value. +The other CppAD $cref pow$$ function may use logarithms and exponentiation +to compute derivatives of the same value +(which will not work if $icode x$$ is less than or equal zero). + +$head Include$$ +The file $code cppad/utility/pow_int.hpp$$ +is included by $code cppad/cppad.hpp$$ +but it can also be included separately with out the rest of +the $code CppAD$$ routines. +Including this file defines +this version of the $code pow$$ within the $code CppAD$$ namespace. + +$head x$$ +The argument $icode x$$ has prototype +$codei% + const %Type%& %x% +%$$ + +$head y$$ +The argument $icode y$$ has prototype +$codei% + const int& %y% +%$$ + +$head z$$ +The result $icode z$$ has prototype +$codei% + %Type% %z% +%$$ + +$head Type$$ +The type $icode Type$$ must support the following operations +where $icode a$$ and $icode b$$ are $icode Type$$ objects +and $icode i$$ is an $code int$$: +$table +$bold Operation$$ $pre $$ + $cnext $bold Description$$ + $cnext $bold Result Type$$ +$rnext +$icode%Type% %a%(%i%)%$$ + $cnext construction of a $icode Type$$ object from an $code int$$ + $cnext $icode Type$$ +$rnext +$icode%a% * %b%$$ + $cnext binary multiplication of $icode Type$$ objects + $cnext $icode Type$$ +$rnext +$icode%a% / %b%$$ + $cnext binary division of $icode Type$$ objects + $cnext $icode Type$$ +$tend + +$head Operation Sequence$$ +The $icode Type$$ operation sequence used to calculate $icode z$$ is +$cref/independent/glossary/Operation/Independent/$$ +of $icode x$$. + +$head Example$$ +$children% + example/utility/pow_int.cpp +%$$ +The file $cref pow_int.cpp$$ +is an example and test of this function. + + +$end +------------------------------------------------------------------------------- +*/ + +namespace CppAD { + + template + inline Type pow (const Type& x, const int& n) + { + Type p(1); + int n2 = n / 2; + + if( n == 0 ) + return p; + if( n < 0 ) + return p / pow(x, -n); + if( n == 1 ) + return x; + + // p = (x^2)^(n/2) + p = pow( x * x , n2 ); + + // n is even case + if( n % 2 == 0 ) + return p; + + // n is odd case + return p * x; + } + +} + +# endif diff --git a/build-config/cppad/include/cppad/utility/romberg_mul.hpp b/build-config/cppad/include/cppad/utility/romberg_mul.hpp new file mode 100644 index 00000000..e4575382 --- /dev/null +++ b/build-config/cppad/include/cppad/utility/romberg_mul.hpp @@ -0,0 +1,325 @@ +# ifndef CPPAD_UTILITY_ROMBERG_MUL_HPP +# define CPPAD_UTILITY_ROMBERG_MUL_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ +/* +$begin RombergMul$$ +$spell + cppad.hpp + bool + const + Cpp + RombergMulMul +$$ + +$section Multi-dimensional Romberg Integration$$ + + +$head Syntax$$ +$codei%# include +%$$ +$codei%RombergMul<%Fun%, %SizeVector%, %FloatVector%, %m%> %R%$$ +$pre +$$ +$icode%r% = %R%(%F%, %a%, %b%, %n%, %p%, %e%)%$$ + + +$head Description$$ +Returns the Romberg integration estimate +$latex r$$ for the multi-dimensional integral +$latex \[ +r = +\int_{a[0]}^{b[0]} \cdots \int_{a[m-1]}^{b[m-1]} +\; F(x) \; +{\bf d} x_0 \cdots {\bf d} x_{m-1} +\; + \; +\sum_{i=0}^{m-1} +O \left[ ( b[i] - a[i] ) / 2^{n[i]-1} \right]^{2(p[i]+1)} +\] $$ + +$head Include$$ +The file $code cppad/utility/romberg_mul.hpp$$ +is included by $code cppad/cppad.hpp$$ +but it can also be included separately with out the rest of +the $code CppAD$$ routines. + +$head m$$ +The template parameter $icode m$$ must be convertible to a $code size_t$$ +object with a value that can be determined at compile time; for example +$code 2$$. +It determines the dimension of the domain space for the integration. + +$head r$$ +The return value $icode r$$ has prototype +$codei% + %Float% %r% +%$$ +It is the estimate computed by $code RombergMul$$ for the integral above +(see description of $cref/Float/RombergMul/Float/$$ below). + +$head F$$ +The object $icode F$$ has the prototype +$codei% + %Fun% &%F% +%$$ +It must support the operation +$codei% + %F%(%x%) +%$$ +The argument $icode x$$ to $icode F$$ has prototype +$codei% + const %Float% &%x% +%$$ +The return value of $icode F$$ is a $icode Float$$ object + +$head a$$ +The argument $icode a$$ has prototype +$codei% + const %FloatVector% &%a% +%$$ +It specifies the lower limit for the integration +(see description of $cref/FloatVector/RombergMul/FloatVector/$$ below). + +$head b$$ +The argument $icode b$$ has prototype +$codei% + const %FloatVector% &%b% +%$$ +It specifies the upper limit for the integration. + +$head n$$ +The argument $icode n$$ has prototype +$codei% + const %SizeVector% &%n% +%$$ +A total number of $latex 2^{n[i]-1} + 1$$ +evaluations of $icode%F%(%x%)%$$ are used to estimate the integral +with respect to $latex {\bf d} x_i$$. + +$head p$$ +The argument $icode p$$ has prototype +$codei% + const %SizeVector% &%p% +%$$ +For $latex i = 0 , \ldots , m-1$$, +$latex n[i]$$ determines the accuracy order in the +approximation for the integral +that is returned by $code RombergMul$$. +The values in $icode p$$ must be less than or equal $icode n$$; i.e., +$icode%p%[%i%] <= %n%[%i%]%$$. + +$head e$$ +The argument $icode e$$ has prototype +$codei% + %Float% &%e% +%$$ +The input value of $icode e$$ does not matter +and its output value is an approximation for the absolute error in +the integral estimate. + +$head Float$$ +The type $icode Float$$ is defined as the type of the elements of +$cref/FloatVector/RombergMul/FloatVector/$$. +The type $icode Float$$ must satisfy the conditions +for a $cref NumericType$$ type. +The routine $cref CheckNumericType$$ will generate an error message +if this is not the case. +In addition, if $icode x$$ and $icode y$$ are $icode Float$$ objects, +$codei% + %x% < %y% +%$$ +returns the $code bool$$ value true if $icode x$$ is less than +$icode y$$ and false otherwise. + +$head FloatVector$$ +The type $icode FloatVector$$ must be a $cref SimpleVector$$ class. +The routine $cref CheckSimpleVector$$ will generate an error message +if this is not the case. + + +$children% + example/utility/romberg_mul.cpp +%$$ +$head Example$$ +$comment% + example/utility/romberg_mul.cpp +%$$ +The file +$cref Rombergmul.cpp$$ +contains an example and test a test of using this routine. + +$head Source Code$$ +The source code for this routine is in the file +$code cppad/romberg_mul.hpp$$. + +$end +*/ + +# include +# include +# include + +namespace CppAD { // BEGIN CppAD namespace + +template +class SliceLast { + typedef typename FloatVector::value_type Float; +private: + Fun *F; + size_t last; + FloatVector x; +public: + SliceLast( Fun *F_, size_t last_, const FloatVector &x_ ) + : F(F_) , last(last_), x(last + 1) + { size_t i; + for(i = 0; i < last; i++) + x[i] = x_[i]; + } + double operator()(const Float &xlast) + { x[last] = xlast; + return (*F)(x); + } +}; + +template +class IntegrateLast { +private: + Fun *F; + const size_t last; + const FloatVector a; + const FloatVector b; + const SizeVector n; + const SizeVector p; + Float esum; + size_t ecount; + +public: + IntegrateLast( + Fun *F_ , + size_t last_ , + const FloatVector &a_ , + const FloatVector &b_ , + const SizeVector &n_ , + const SizeVector &p_ ) + : F(F_) , last(last_), a(a_) , b(b_) , n(n_) , p(p_) + { } + Float operator()(const FloatVector &x) + { Float r, e; + SliceLast S(F, last, x); + r = CppAD::RombergOne( + S, a[last], b[last], n[last], p[last], e + ); + esum = esum + e; + ecount++; + return r; + } + void ClearEsum(void) + { esum = 0.; } + Float GetEsum(void) + { return esum; } + + void ClearEcount(void) + { ecount = 0; } + size_t GetEcount(void) + { return ecount; } +}; + +template +class RombergMul { + typedef typename FloatVector::value_type Float; +public: + RombergMul(void) + { } + Float operator() ( + Fun &F , + const FloatVector &a , + const FloatVector &b , + const SizeVector &n , + const SizeVector &p , + Float &e ) + { Float r; + + typedef IntegrateLast< + Fun , + SizeVector , + FloatVector , + Float > IntegrateOne; + + IntegrateOne Fm1(&F, m-1, a, b, n, p); + RombergMul< + IntegrateOne, + SizeVector , + FloatVector , + m-1 > RombergMulM1; + + Fm1.ClearEsum(); + Fm1.ClearEcount(); + + r = RombergMulM1(Fm1, a, b, n, p, e); + + size_t i, j; + Float prod = 1; + size_t pow2 = 1; + for(i = 0; i < m-1; i++) + { prod *= (b[i] - a[i]); + for(j = 0; j < (n[i] - 1); j++) + pow2 *= 2; + } + assert( Fm1.GetEcount() == (pow2+1) ); + + e = e + Fm1.GetEsum() * prod / Float( double(Fm1.GetEcount()) ); + + return r; + } +}; + +template +class RombergMul { + typedef typename FloatVector::value_type Float; +public: + Float operator() ( + Fun &F , + const FloatVector &a , + const FloatVector &b , + const SizeVector &n , + const SizeVector &p , + Float &e ) + { Float r; + typedef IntegrateLast< + Fun , + SizeVector , + FloatVector , + Float > IntegrateOne; + + // check simple vector class specifications + CheckSimpleVector(); + + // check numeric type specifications + CheckNumericType(); + + IntegrateOne F0(&F, 0, a, b, n, p); + + F0.ClearEsum(); + F0.ClearEcount(); + + r = F0(a); + + assert( F0.GetEcount() == 1 ); + e = F0.GetEsum(); + + return r; + } +}; + +} // END CppAD namespace + +# endif diff --git a/build-config/cppad/include/cppad/utility/romberg_one.hpp b/build-config/cppad/include/cppad/utility/romberg_one.hpp new file mode 100644 index 00000000..8255d329 --- /dev/null +++ b/build-config/cppad/include/cppad/utility/romberg_one.hpp @@ -0,0 +1,213 @@ +# ifndef CPPAD_UTILITY_ROMBERG_ONE_HPP +# define CPPAD_UTILITY_ROMBERG_ONE_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ +/* +$begin RombergOne$$ +$spell + cppad.hpp + bool + const + Cpp + RombergOne +$$ + +$section One DimensionalRomberg Integration$$ + + +$head Syntax$$ +$codei%# include +%$$ +$icode%r% = RombergOne(%F%, %a%, %b%, %n%, %e%)%$$ + + +$head Description$$ +Returns the Romberg integration estimate +$latex r$$ for a one dimensional integral +$latex \[ +r = \int_a^b F(x) {\bf d} x + O \left[ (b - a) / 2^{n-1} \right]^{2(p+1)} +\] $$ + +$head Include$$ +The file $code cppad/utility/romberg_one.hpp$$ +is included by $code cppad/cppad.hpp$$ +but it can also be included separately with out the rest of +the $code CppAD$$ routines. + +$head r$$ +The return value $icode r$$ has prototype +$codei% + %Float% %r% +%$$ +It is the estimate computed by $code RombergOne$$ for the integral above. + +$head F$$ +The object $icode F$$ can be of any type, but it must support +the operation +$codei% + %F%(%x%) +%$$ +The argument $icode x$$ to $icode F$$ has prototype +$codei% + const %Float% &%x% +%$$ +The return value of $icode F$$ is a $icode Float$$ object +(see description of $cref/Float/RombergOne/Float/$$ below). + +$head a$$ +The argument $icode a$$ has prototype +$codei% + const %Float% &%a% +%$$ +It specifies the lower limit for the integration. + +$head b$$ +The argument $icode b$$ has prototype +$codei% + const %Float% &%b% +%$$ +It specifies the upper limit for the integration. + +$head n$$ +The argument $icode n$$ has prototype +$codei% + size_t %n% +%$$ +A total number of $latex 2^{n-1} + 1$$ evaluations of $icode%F%(%x%)%$$ +are used to estimate the integral. + +$head p$$ +The argument $icode p$$ has prototype +$codei% + size_t %p% +%$$ +It must be less than or equal $latex n$$ +and determines the accuracy order in the approximation for the integral +that is returned by $code RombergOne$$. +To be specific +$latex \[ +r = \int_a^b F(x) {\bf d} x + O \left[ (b - a) / 2^{n-1} \right]^{2(p+1)} +\] $$ + + +$head e$$ +The argument $icode e$$ has prototype +$codei% + %Float% &%e% +%$$ +The input value of $icode e$$ does not matter +and its output value is an approximation for the error in +the integral estimates; i.e., +$latex \[ + e \approx \left| r - \int_a^b F(x) {\bf d} x \right| +\] $$ + +$head Float$$ +The type $icode Float$$ must satisfy the conditions +for a $cref NumericType$$ type. +The routine $cref CheckNumericType$$ will generate an error message +if this is not the case. +In addition, if $icode x$$ and $icode y$$ are $icode Float$$ objects, +$codei% + %x% < %y% +%$$ +returns the $code bool$$ value true if $icode x$$ is less than +$icode y$$ and false otherwise. + +$children% + example/utility/romberg_one.cpp +%$$ +$head Example$$ +$comment% + example/utility/romberg_one.cpp +%$$ +The file +$cref romberg_one.cpp$$ +contains an example and test a test of using this routine. + +$head Source Code$$ +The source code for this routine is in the file +$code cppad/romberg_one.hpp$$. + +$end +*/ + +# include +# include +# include + +namespace CppAD { // BEGIN CppAD namespace + +template +Float RombergOne( + Fun &F , + const Float &a , + const Float &b , + size_t n , + size_t p , + Float &e ) +{ + size_t ipow2 = 1; + size_t k, i; + Float pow2, sum, x; + + Float zero = Float(0); + Float two = Float(2); + + // check specifications for a NumericType + CheckNumericType(); + + CPPAD_ASSERT_KNOWN( + n >= 2, + "RombergOne: n must be greater than or equal 2" + ); + CppAD::vector r(n); + + // set r[i] = trapazoidal rule with 2^i intervals in [a, b] + r[0] = ( F(a) + F(b) ) * (b - a) / two; + for(i = 1; i < n; i++) + { ipow2 *= 2; + // there must be a conversion from int to any numeric type + pow2 = Float(int(ipow2)); + sum = zero; + for(k = 1; k < ipow2; k += 2) + { // start = a + (b-a)/pow2, increment = 2*(b-a)/pow2 + x = ( (pow2 - Float(double(k))) * a + double(k) * b ) / pow2; + sum = sum + F(x); + } + // combine function evaluations in sum with those in T[i-1] + r[i] = r[i-1] / two + sum * (b - a) / pow2; + } + + // now compute the higher order estimates + size_t ipow4 = 1; // order of accuract for previous estimate + Float pow4, pow4minus; + for(i = 0; i < p; i++) + { // compute estimate accurate to O[ step^(2*(i+1)) ] + // put resutls in r[n-1], r[n-2], ... , r[n-i+1] + ipow4 *= 4; + pow4 = Float(int(ipow4)); + pow4minus = Float(ipow4-1); + for(k = n-1; k > i; k--) + r[k] = ( pow4 * r[k] - r[k-1] ) / pow4minus; + } + + // error estimate for r[n] + e = r[n-1] - r[n-2]; + if( e < zero ) + e = - e; + return r[n-1]; +} + +} // END CppAD namespace + +# endif diff --git a/build-config/cppad/include/cppad/utility/rosen_34.hpp b/build-config/cppad/include/cppad/utility/rosen_34.hpp new file mode 100644 index 00000000..467fd486 --- /dev/null +++ b/build-config/cppad/include/cppad/utility/rosen_34.hpp @@ -0,0 +1,497 @@ +# ifndef CPPAD_UTILITY_ROSEN_34_HPP +# define CPPAD_UTILITY_ROSEN_34_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +/* +$begin Rosen34$$ +$spell + cppad.hpp + bool + xf + templated + const + Rosenbrock + CppAD + xi + ti + tf + Karp + Rosen + Shampine + ind + dep +$$ + + +$section A 3rd and 4th Order Rosenbrock ODE Solver$$ + +$head Syntax$$ +$codei%# include +%$$ +$icode%xf% = Rosen34(%F%, %M%, %ti%, %tf%, %xi%) +%$$ +$icode%xf% = Rosen34(%F%, %M%, %ti%, %tf%, %xi%, %e%) +%$$ + + +$head Description$$ +This is an embedded 3rd and 4th order Rosenbrock ODE solver +(see Section 16.6 of $cref/Numerical Recipes/Bib/Numerical Recipes/$$ +for a description of Rosenbrock ODE solvers). +In particular, we use the formulas taken from page 100 of +$cref/Shampine, L.F./Bib/Shampine, L.F./$$ +(except that the fraction 98/108 has been correction to be 97/108). +$pre + +$$ +We use $latex n$$ for the size of the vector $icode xi$$. +Let $latex \B{R}$$ denote the real numbers +and let $latex F : \B{R} \times \B{R}^n \rightarrow \B{R}^n$$ be a smooth function. +The return value $icode xf$$ contains a 5th order +approximation for the value $latex X(tf)$$ where +$latex X : [ti , tf] \rightarrow \B{R}^n$$ is defined by +the following initial value problem: +$latex \[ +\begin{array}{rcl} + X(ti) & = & xi \\ + X'(t) & = & F[t , X(t)] +\end{array} +\] $$ +If your set of ordinary differential equations are not stiff +an explicit method may be better (perhaps $cref Runge45$$.) + +$head Include$$ +The file $code cppad/utility/rosen_34.hpp$$ +is included by $code cppad/cppad.hpp$$ +but it can also be included separately with out the rest of +the $code CppAD$$ routines. + +$head xf$$ +The return value $icode xf$$ has the prototype +$codei% + %Vector% %xf% +%$$ +and the size of $icode xf$$ is equal to $icode n$$ +(see description of $cref/Vector/Rosen34/Vector/$$ below). +$latex \[ + X(tf) = xf + O( h^5 ) +\] $$ +where $latex h = (tf - ti) / M$$ is the step size. +If $icode xf$$ contains not a number $cref nan$$, +see the discussion of $cref/f/Rosen34/Fun/Nan/$$. + +$head Fun$$ +The class $icode Fun$$ +and the object $icode F$$ satisfy the prototype +$codei% + %Fun% &%F% +%$$ +This must support the following set of calls +$codei% + %F%.Ode(%t%, %x%, %f%) + %F%.Ode_ind(%t%, %x%, %f_t%) + %F%.Ode_dep(%t%, %x%, %f_x%) +%$$ + +$subhead t$$ +In all three cases, +the argument $icode t$$ has prototype +$codei% + const %Scalar% &%t% +%$$ +(see description of $cref/Scalar/Rosen34/Scalar/$$ below). + +$subhead x$$ +In all three cases, +the argument $icode x$$ has prototype +$codei% + const %Vector% &%x% +%$$ +and has size $icode n$$ +(see description of $cref/Vector/Rosen34/Vector/$$ below). + +$subhead f$$ +The argument $icode f$$ to $icode%F%.Ode%$$ has prototype +$codei% + %Vector% &%f% +%$$ +On input and output, $icode f$$ is a vector of size $icode n$$ +and the input values of the elements of $icode f$$ do not matter. +On output, +$icode f$$ is set equal to $latex F(t, x)$$ +(see $icode F(t, x)$$ in $cref/Description/Rosen34/Description/$$). + +$subhead f_t$$ +The argument $icode f_t$$ to $icode%F%.Ode_ind%$$ has prototype +$codei% + %Vector% &%f_t% +%$$ +On input and output, $icode f_t$$ is a vector of size $icode n$$ +and the input values of the elements of $icode f_t$$ do not matter. +On output, the $th i$$ element of +$icode f_t$$ is set equal to $latex \partial_t F_i (t, x)$$ +(see $icode F(t, x)$$ in $cref/Description/Rosen34/Description/$$). + +$subhead f_x$$ +The argument $icode f_x$$ to $icode%F%.Ode_dep%$$ has prototype +$codei% + %Vector% &%f_x% +%$$ +On input and output, $icode f_x$$ is a vector of size $icode%n%*%n%$$ +and the input values of the elements of $icode f_x$$ do not matter. +On output, the [$icode%i%*%n%+%j%$$] element of +$icode f_x$$ is set equal to $latex \partial_{x(j)} F_i (t, x)$$ +(see $icode F(t, x)$$ in $cref/Description/Rosen34/Description/$$). + +$subhead Nan$$ +If any of the elements of $icode f$$, $icode f_t$$, or $icode f_x$$ +have the value not a number $code nan$$, +the routine $code Rosen34$$ returns with all the +elements of $icode xf$$ and $icode e$$ equal to $code nan$$. + +$subhead Warning$$ +The arguments $icode f$$, $icode f_t$$, and $icode f_x$$ +must have a call by reference in their prototypes; i.e., +do not forget the $code &$$ in the prototype for +$icode f$$, $icode f_t$$ and $icode f_x$$. + +$subhead Optimization$$ +Every call of the form +$codei% + %F%.Ode_ind(%t%, %x%, %f_t%) +%$$ +is directly followed by a call of the form +$codei% + %F%.Ode_dep(%t%, %x%, %f_x%) +%$$ +where the arguments $icode t$$ and $icode x$$ have not changed between calls. +In many cases it is faster to compute the values of $icode f_t$$ +and $icode f_x$$ together and then pass them back one at a time. + +$head M$$ +The argument $icode M$$ has prototype +$codei% + size_t %M% +%$$ +It specifies the number of steps +to use when solving the differential equation. +This must be greater than or equal one. +The step size is given by $latex h = (tf - ti) / M$$, thus +the larger $icode M$$, the more accurate the +return value $icode xf$$ is as an approximation +for $latex X(tf)$$. + +$head ti$$ +The argument $icode ti$$ has prototype +$codei% + const %Scalar% &%ti% +%$$ +(see description of $cref/Scalar/Rosen34/Scalar/$$ below). +It specifies the initial time for $icode t$$ in the +differential equation; i.e., +the time corresponding to the value $icode xi$$. + +$head tf$$ +The argument $icode tf$$ has prototype +$codei% + const %Scalar% &%tf% +%$$ +It specifies the final time for $icode t$$ in the +differential equation; i.e., +the time corresponding to the value $icode xf$$. + +$head xi$$ +The argument $icode xi$$ has the prototype +$codei% + const %Vector% &%xi% +%$$ +and the size of $icode xi$$ is equal to $icode n$$. +It specifies the value of $latex X(ti)$$ + +$head e$$ +The argument $icode e$$ is optional and has the prototype +$codei% + %Vector% &%e% +%$$ +If $icode e$$ is present, +the size of $icode e$$ must be equal to $icode n$$. +The input value of the elements of $icode e$$ does not matter. +On output +it contains an element by element +estimated bound for the absolute value of the error in $icode xf$$ +$latex \[ + e = O( h^4 ) +\] $$ +where $latex h = (tf - ti) / M$$ is the step size. + +$head Scalar$$ +The type $icode Scalar$$ must satisfy the conditions +for a $cref NumericType$$ type. +The routine $cref CheckNumericType$$ will generate an error message +if this is not the case. +In addition, the following operations must be defined for +$icode Scalar$$ objects $icode a$$ and $icode b$$: + +$table +$bold Operation$$ $cnext $bold Description$$ $rnext +$icode%a% < %b%$$ $cnext + less than operator (returns a $code bool$$ object) +$tend + +$head Vector$$ +The type $icode Vector$$ must be a $cref SimpleVector$$ class with +$cref/elements of type Scalar/SimpleVector/Elements of Specified Type/$$. +The routine $cref CheckSimpleVector$$ will generate an error message +if this is not the case. + +$head Parallel Mode$$ +For each set of types +$cref/Scalar/Rosen34/Scalar/$$, +$cref/Vector/Rosen34/Vector/$$, and +$cref/Fun/Rosen34/Fun/$$, +the first call to $code Rosen34$$ +must not be $cref/parallel/ta_in_parallel/$$ execution mode. + +$head Example$$ +$children% + example/utility/rosen_34.cpp +%$$ +The file +$cref rosen_34.cpp$$ +contains an example and test a test of using this routine. + +$head Source Code$$ +The source code for this routine is in the file +$code cppad/rosen_34.hpp$$. + +$end +-------------------------------------------------------------------------- +*/ + +# include +# include +# include +# include +# include +# include +# include + +// needed before one can use CPPAD_ASSERT_FIRST_CALL_NOT_PARALLEL +# include + +namespace CppAD { // BEGIN CppAD namespace + +template +Vector Rosen34( + Fun &F , + size_t M , + const Scalar &ti , + const Scalar &tf , + const Vector &xi ) +{ Vector e( xi.size() ); + return Rosen34(F, M, ti, tf, xi, e); +} + +template +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(); + + // check simple vector class specifications + CheckSimpleVector(); + + // 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 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; +} + +} // End CppAD namespace + +# endif diff --git a/build-config/cppad/include/cppad/utility/runge_45.hpp b/build-config/cppad/include/cppad/utility/runge_45.hpp new file mode 100644 index 00000000..9392de70 --- /dev/null +++ b/build-config/cppad/include/cppad/utility/runge_45.hpp @@ -0,0 +1,427 @@ +# ifndef CPPAD_UTILITY_RUNGE_45_HPP +# define CPPAD_UTILITY_RUNGE_45_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +/* +$begin Runge45$$ +$spell + std + fabs + cppad.hpp + bool + xf + templated + const + Runge-Kutta + CppAD + xi + ti + tf + Karp +$$ + + +$section An Embedded 4th and 5th Order Runge-Kutta ODE Solver$$ + +$head Syntax$$ +$codei%# include +%$$ +$icode%xf% = Runge45(%F%, %M%, %ti%, %tf%, %xi%) +%$$ +$icode%xf% = Runge45(%F%, %M%, %ti%, %tf%, %xi%, %e%) +%$$ + + +$head Purpose$$ +This is an implementation of the +Cash-Karp embedded 4th and 5th order Runge-Kutta ODE solver +described in Section 16.2 of $cref/Numerical Recipes/Bib/Numerical Recipes/$$. +We use $latex n$$ for the size of the vector $icode xi$$. +Let $latex \B{R}$$ denote the real numbers +and let $latex F : \B{R} \times \B{R}^n \rightarrow \B{R}^n$$ +be a smooth function. +The return value $icode xf$$ contains a 5th order +approximation for the value $latex X(tf)$$ where +$latex X : [ti , tf] \rightarrow \B{R}^n$$ is defined by +the following initial value problem: +$latex \[ +\begin{array}{rcl} + X(ti) & = & xi \\ + X'(t) & = & F[t , X(t)] +\end{array} +\] $$ +If your set of ordinary differential equations +are stiff, an implicit method may be better +(perhaps $cref Rosen34$$.) + +$head Operation Sequence$$ +The $cref/operation sequence/glossary/Operation/Sequence/$$ for $icode Runge$$ +does not depend on any of its $icode Scalar$$ input values provided that +the operation sequence for +$codei% + %F%.Ode(%t%, %x%, %f%) +%$$ +does not on any of its $icode Scalar$$ inputs (see below). + +$head Include$$ +The file $code cppad/utility/runge_45.hpp$$ +is included by $code cppad/cppad.hpp$$ +but it can also be included separately with out the rest of +the $code CppAD$$ routines. + +$head xf$$ +The return value $icode xf$$ has the prototype +$codei% + %Vector% %xf% +%$$ +and the size of $icode xf$$ is equal to $icode n$$ +(see description of $cref/Vector/Runge45/Vector/$$ below). +$latex \[ + X(tf) = xf + O( h^6 ) +\] $$ +where $latex h = (tf - ti) / M$$ is the step size. +If $icode xf$$ contains not a number $cref nan$$, +see the discussion for $cref/f/Runge45/Fun/f/$$. + +$head Fun$$ +The class $icode Fun$$ +and the object $icode F$$ satisfy the prototype +$codei% + %Fun% &%F% +%$$ +The object $icode F$$ (and the class $icode Fun$$) +must have a member function named $code Ode$$ +that supports the syntax +$codei% + %F%.Ode(%t%, %x%, %f%) +%$$ + +$subhead t$$ +The argument $icode t$$ to $icode%F%.Ode%$$ has prototype +$codei% + const %Scalar% &%t% +%$$ +(see description of $cref/Scalar/Runge45/Scalar/$$ below). + +$subhead x$$ +The argument $icode x$$ to $icode%F%.Ode%$$ has prototype +$codei% + const %Vector% &%x% +%$$ +and has size $icode n$$ +(see description of $cref/Vector/Runge45/Vector/$$ below). + +$subhead f$$ +The argument $icode f$$ to $icode%F%.Ode%$$ has prototype +$codei% + %Vector% &%f% +%$$ +On input and output, $icode f$$ is a vector of size $icode n$$ +and the input values of the elements of $icode f$$ do not matter. +On output, +$icode f$$ is set equal to $latex F(t, x)$$ in the differential equation. +If any of the elements of $icode f$$ have the value not a number $code nan$$ +the routine $code Runge45$$ returns with all the +elements of $icode xf$$ and $icode e$$ equal to $code nan$$. + +$subhead Warning$$ +The argument $icode f$$ to $icode%F%.Ode%$$ +must have a call by reference in its prototype; i.e., +do not forget the $code &$$ in the prototype for $icode f$$. + +$head M$$ +The argument $icode M$$ has prototype +$codei% + size_t %M% +%$$ +It specifies the number of steps +to use when solving the differential equation. +This must be greater than or equal one. +The step size is given by $latex h = (tf - ti) / M$$, thus +the larger $icode M$$, the more accurate the +return value $icode xf$$ is as an approximation +for $latex X(tf)$$. + +$head ti$$ +The argument $icode ti$$ has prototype +$codei% + const %Scalar% &%ti% +%$$ +(see description of $cref/Scalar/Runge45/Scalar/$$ below). +It specifies the initial time for $icode t$$ in the +differential equation; i.e., +the time corresponding to the value $icode xi$$. + +$head tf$$ +The argument $icode tf$$ has prototype +$codei% + const %Scalar% &%tf% +%$$ +It specifies the final time for $icode t$$ in the +differential equation; i.e., +the time corresponding to the value $icode xf$$. + +$head xi$$ +The argument $icode xi$$ has the prototype +$codei% + const %Vector% &%xi% +%$$ +and the size of $icode xi$$ is equal to $icode n$$. +It specifies the value of $latex X(ti)$$ + +$head e$$ +The argument $icode e$$ is optional and has the prototype +$codei% + %Vector% &%e% +%$$ +If $icode e$$ is present, +the size of $icode e$$ must be equal to $icode n$$. +The input value of the elements of $icode e$$ does not matter. +On output +it contains an element by element +estimated bound for the absolute value of the error in $icode xf$$ +$latex \[ + e = O( h^5 ) +\] $$ +where $latex h = (tf - ti) / M$$ is the step size. +If on output, $icode e$$ contains not a number $code nan$$, +see the discussion for $cref/f/Runge45/Fun/f/$$. + +$head Scalar$$ +The type $icode Scalar$$ must satisfy the conditions +for a $cref NumericType$$ type. +The routine $cref CheckNumericType$$ will generate an error message +if this is not the case. + +$subhead fabs$$ +In addition, the following function must be defined for +$icode Scalar$$ objects $icode a$$ and $icode b$$ +$codei% + %a% = fabs(%b%) +%$$ +Note that this operation is only used for computing $icode e$$; hence +the operation sequence for $icode xf$$ can still be independent of +the arguments to $code Runge45$$ even if +$codei% + fabs(%b%) = std::max(-%b%, %b%) +%$$. + +$head Vector$$ +The type $icode Vector$$ must be a $cref SimpleVector$$ class with +$cref/elements of type Scalar/SimpleVector/Elements of Specified Type/$$. +The routine $cref CheckSimpleVector$$ will generate an error message +if this is not the case. + +$head Parallel Mode$$ +For each set of types +$cref/Scalar/Runge45/Scalar/$$, +$cref/Vector/Runge45/Vector/$$, and +$cref/Fun/Runge45/Fun/$$, +the first call to $code Runge45$$ +must not be $cref/parallel/ta_in_parallel/$$ execution mode. + + +$head Example$$ +$children% + example/utility/runge45_1.cpp% + example/utility/runge_45.cpp +%$$ +The file +$cref runge45_1.cpp$$ +contains a simple example and test of $code Runge45$$. +$pre + +$$ +The file +$cref runge_45.cpp$$ contains an example using $code Runge45$$ +in the context of algorithmic differentiation. +It also returns true if it succeeds and false otherwise. + +$head Source Code$$ +The source code for this routine is in the file +$code cppad/runge_45.hpp$$. + +$end +-------------------------------------------------------------------------- +*/ +# include +# include +# include +# include +# include + +// needed before one can use CPPAD_ASSERT_FIRST_CALL_NOT_PARALLEL +# include + +namespace CppAD { // BEGIN CppAD namespace + +template +Vector Runge45( + Fun &F , + size_t M , + const Scalar &ti , + const Scalar &tf , + const Vector &xi ) +{ Vector e( xi.size() ); + return Runge45(F, M, ti, tf, xi, e); +} + +template +Vector Runge45( + 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(); + + // check simple vector class specifications + CheckSimpleVector(); + + // Cash-Karp parameters for embedded Runge-Kutta method + // are static to avoid recalculation on each call and + // do not use Vector to avoid possible memory leak + static Scalar a[6] = { + Scalar(0), + Scalar(1) / Scalar(5), + Scalar(3) / Scalar(10), + Scalar(3) / Scalar(5), + Scalar(1), + Scalar(7) / Scalar(8) + }; + static Scalar b[5 * 5] = { + Scalar(1) / Scalar(5), + Scalar(0), + Scalar(0), + Scalar(0), + Scalar(0), + + Scalar(3) / Scalar(40), + Scalar(9) / Scalar(40), + Scalar(0), + Scalar(0), + Scalar(0), + + Scalar(3) / Scalar(10), + -Scalar(9) / Scalar(10), + Scalar(6) / Scalar(5), + Scalar(0), + Scalar(0), + + -Scalar(11) / Scalar(54), + Scalar(5) / Scalar(2), + -Scalar(70) / Scalar(27), + Scalar(35) / Scalar(27), + Scalar(0), + + Scalar(1631) / Scalar(55296), + Scalar(175) / Scalar(512), + Scalar(575) / Scalar(13824), + Scalar(44275) / Scalar(110592), + Scalar(253) / Scalar(4096) + }; + static Scalar c4[6] = { + Scalar(2825) / Scalar(27648), + Scalar(0), + Scalar(18575) / Scalar(48384), + Scalar(13525) / Scalar(55296), + Scalar(277) / Scalar(14336), + Scalar(1) / Scalar(4), + }; + static Scalar c5[6] = { + Scalar(37) / Scalar(378), + Scalar(0), + Scalar(250) / Scalar(621), + Scalar(125) / Scalar(594), + Scalar(0), + Scalar(512) / Scalar(1771) + }; + + CPPAD_ASSERT_KNOWN( + M >= 1, + "Error in Runge45: the number of steps is less than one" + ); + CPPAD_ASSERT_KNOWN( + e.size() == xi.size(), + "Error in Runge45: size of e not equal to size of xi" + ); + size_t i, j, k, m; // indices + + size_t n = xi.size(); // number of components in X(t) + Scalar ns = Scalar(int(M)); // number of steps as Scalar object + Scalar h = (tf - ti) / ns; // step size + Scalar zero_or_nan = Scalar(0); // zero (nan if Ode returns has a nan) + for(i = 0; i < n; i++) // initialize e = 0 + e[i] = zero_or_nan; + + // vectors used to store values returned by F + Vector fh(6 * n), xtmp(n), ftmp(n), x4(n), x5(n), xf(n); + + xf = xi; // initialize solution + for(m = 0; m < M; m++) + { // time at beginning of this interval + // (convert to int to avoid MS compiler warning) + Scalar t = ti * (Scalar(int(M - m)) / ns) + + tf * (Scalar(int(m)) / ns); + + // loop over integration steps + x4 = x5 = xf; // start x4 and x5 at same point for each step + for(j = 0; j < 6; j++) + { // loop over function evaluations for this step + xtmp = xf; // location for next function evaluation + for(k = 0; k < j; k++) + { // loop over previous function evaluations + Scalar bjk = b[ (j-1) * 5 + k ]; + for(i = 0; i < n; i++) + { // loop over elements of x + xtmp[i] += bjk * fh[i * 6 + k]; + } + } + // ftmp = F(t + a[j] * h, xtmp) + F.Ode(t + a[j] * h, xtmp, ftmp); + + // if ftmp has a nan, set zero_or_nan to nan + for(i = 0; i < n; i++) + zero_or_nan *= ftmp[i]; + + for(i = 0; i < n; i++) + { // loop over elements of x + Scalar fhi = ftmp[i] * h; + fh[i * 6 + j] = fhi; + x4[i] += c4[j] * fhi; + x5[i] += c5[j] * fhi; + x5[i] += zero_or_nan; + } + } + // accumulate error bound + for(i = 0; i < n; i++) + { // cant use abs because cppad.hpp may not be included + Scalar diff = x5[i] - x4[i]; + e[i] += fabs(diff); + e[i] += zero_or_nan; + } + + // advance xf for this step using x5 + xf = x5; + } + return xf; +} + +} // End CppAD namespace + +# endif diff --git a/build-config/cppad/include/cppad/utility/set_union.hpp b/build-config/cppad/include/cppad/utility/set_union.hpp new file mode 100644 index 00000000..e8987fb0 --- /dev/null +++ b/build-config/cppad/include/cppad/utility/set_union.hpp @@ -0,0 +1,91 @@ +# ifndef CPPAD_UTILITY_SET_UNION_HPP +# define CPPAD_UTILITY_SET_UNION_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-18 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +/* +$begin set_union$$ +$spell + set + const + std + cppad + hpp +$$ + +$section Union of Standard Sets$$ + +$head Syntax$$ +$codei%# include +%$$ +$icode%result% = set_union(%left%, %right%)%$$ + +$head Purpose$$ +This is a simplified (and restricted) interface to +the $code std::union$$ operation. + +$head Element$$ +This is the type of the elements of the sets. + +$head left$$ +This argument has prototype +$codei% + const std::set<%Element%>& %left% +%$$ + +$head right$$ +This argument has prototype +$codei% + const std::set<%Element%>& %right% +%$$ + +$head result$$ +The return value has prototype +$codei% + std::set<%Element%>& %result% +%$$ +It contains the union of $icode left$$ and $icode right$$. +Note that C++11 detects that the return value is a temporary +and uses it for the result instead of making a separate copy. + +$children% + example/utility/set_union.cpp +%$$ +$head Example$$ +The file $cref set_union.cpp$$ contains an example and test of this + + +$end +*/ + +# include +# include +# include + +namespace CppAD { + template + std::set set_union( + const std::set& left , + const std::set& right ) + { std::set result; + std::set_union( + left.begin() , + left.end() , + right.begin() , + right.end() , + std::inserter(result, result.begin()) + ); + return result; + } +} + +# endif diff --git a/build-config/cppad/include/cppad/utility/sparse2eigen.hpp b/build-config/cppad/include/cppad/utility/sparse2eigen.hpp new file mode 100644 index 00000000..e6e5e28c --- /dev/null +++ b/build-config/cppad/include/cppad/utility/sparse2eigen.hpp @@ -0,0 +1,138 @@ +# ifndef CPPAD_UTILITY_SPARSE2EIGEN_HPP +# define CPPAD_UTILITY_SPARSE2EIGEN_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +/* +$begin sparse2eigen$$ +$spell + CppAD + Eigen + cppad.hpp + const + Ptr + nnz + cmake + namespace +$$ + +$section Convert A CppAD Sparse Matrix to an Eigen Sparse Matrix$$ + +$head Syntax$$ +$codei%# include +%$$ +$codei%sparse2eigen(%source%, %destination%)%$$ + +$head Prototype$$ +$srcthisfile%0 + %// BEGIN_PROTOTYPE%// END_PROTOTYPE% +1%$$ + +$head Include$$ +If $cref/include_eigen/cmake/include_eigen/$$ is specified on the cmake command line, +the file $code cppad/utility/sparse2eigen.hpp$$ +is included by $code cppad/cppad.hpp$$. +In any case, +it can also be included separately with out the rest of +the $code CppAD$$ routines. +Including this file defines +this version of the $code sparse2eigen$$ within the $code CppAD$$ namespace. + +$head SizeVector$$ +We use $cref/SizeVector/sparse_rc/SizeVector/$$ to denote a +$cref SimpleVector$$ class with elements of $code size_t$$. + +$head ValueVector$$ +We use $icode ValueVector$$ to denote a +$cref SimpleVector$$ class with elements of type $icode value_type$$. + +$head Options$$ +We use $icode Options$$ to denote either +$code Eigen::RowMajor$$ of $code Eigen::ColMajor$$. + +$head value_type$$ +The type of elements of elements in $icode source$$ and $icode destination$$ +must be the same. We use $icode value_type$$ to denote this type. + +$head source$$ +This is the CppAD sparse matrix that is being converted to eigen format. + +$head destination$$ +This is the Eigen sparse matrix that is the result of the conversion. + +$head Compressed$$ +The result matrix $icode destination$$ +is in compressed format. For example, let +$codei% + size_t %% %nnz% = %source%.nnz(); + const %s_vector%& %s_value% = %source%.val(); + const %value_type%* %d_value% = %destination%.valuePtr(); + const %s_vector%& %row_major% = %source%.row_major(); + const %s_vector%& %col_major% = %source%.col_major(); +%$$ +It follows that, for $icode%k% = 0 , %...%, %nnz%$$: +If $icode Options$$ is $code Eigen::RowMajor$$, +$codei% + %d_value%[%k%] == %s_value%[ %row_major%[%k%] ] +%$$ +If $icode Options$$ is $code Eigen::ColMajor$$, +$codei% + %d_value%[%k%] == %s_value%[ %col_major%[%k%] ] +%$$ + +$children%example/sparse/sparse2eigen.cpp +%$$ + +$head Example$$ +The file $cref sparse2eigen.cpp$$ contains an example and test +of $code sparse2eigen.cpp$$ It return true if the test passes +and false otherwise. + +$end +*/ +# include +# include +# include +# include + +namespace CppAD { // BEGIN CPPAD_NAMESPACE + +// BEGIN_PROTOTYPE +template +void sparse2eigen( +const CppAD::sparse_rcv& source , +Eigen::SparseMatrix& destination ) +// END_PROTOTYPE +{ using Eigen::Index; + typedef typename ValueVector::value_type value_type; + typedef Eigen::Triplet triplet; + std::vector vec( source.nnz() ); + // + const SizeVector& row = source.row(); + const SizeVector& col = source.col(); + const ValueVector& val = source.val(); + // + for(size_t k = 0; k < source.nnz(); k++) + vec[k] = triplet( int(row[k]), int(col[k]), val[k] ); + // + size_t nr = source.nr(); + size_t nc = source.nc(); + destination.resize( Index(nr), Index(nc) ); + destination.setFromTriplets(vec.begin(), vec.end()); + // + CPPAD_ASSERT_UNKNOWN( destination.isCompressed() ); + // + return; +} + +} // END_CPPAD_NAMESPACE +# endif diff --git a/build-config/cppad/include/cppad/utility/sparse_rc.hpp b/build-config/cppad/include/cppad/utility/sparse_rc.hpp new file mode 100644 index 00000000..3936988c --- /dev/null +++ b/build-config/cppad/include/cppad/utility/sparse_rc.hpp @@ -0,0 +1,380 @@ +# ifndef CPPAD_UTILITY_SPARSE_RC_HPP +# define CPPAD_UTILITY_SPARSE_RC_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +/* +$begin sparse_rc$$ +$spell + CppAD + const + nnz + cppad + hpp + rc + nr + nc + resize +$$ +$section Row and Column Index Sparsity Patterns$$ + +$head Syntax$$ +$codei%# include +%$$ +$codei%sparse_rc<%SizeVector%> %empty% +%$$ +$codei%sparse_rc<%SizeVector%> %pattern%(%nr%, %nc%, %nnz%) +%$$ +$icode%pattern% = %other% +%$$ +$icode%pattern%.swap(%other%) +%$$ +$icode%resize%(%nr%, %nc%, %nnz%) +%$$ +$icode%pattern%.set(%k%, %r%, %c%) +%$$ +$icode%pattern%.nr() +%$$ +$icode%pattern%.nc() +%$$ +$icode%pattern%.nnz() +%$$ +$codei%const %SizeVector%& %row%( %pattern%.row() ) +%$$ +$codei%const %SizeVector%& %col%( %pattern%.col() ) +%$$ +$icode%row_major% = %pattern%.row_major() +%$$ +$icode%col_major% = %pattern%.col_major() +%$$ + +$head SizeVector$$ +We use $icode SizeVector$$ to denote $cref SimpleVector$$ class +$cref/with elements of type/SimpleVector/Elements of Specified Type/$$ +$code size_t$$. +In addition, $icode SimpleVector$$ must support the $code swap$$ operation +between two of its vectors. + +$head empty$$ +This is an empty sparsity pattern. To be specific, +the corresponding number of rows $icode nr$$, +number of columns $icode nc$$, +and number of possibly non-zero values $icode nnz$$, +are all zero. + +$head pattern$$ +This object is used to hold a sparsity pattern for a matrix. +The sparsity $icode pattern$$ is $code const$$ +except during its constructor, $code resize$$, and $code set$$. + +$head other$$ +The $icode other$$ variable has prototype +$codei% + sparse_rc<%SizeVector%> %other% +%$$ + +$subhead Assignment$$ +After the assignment statement, $icode other$$ is an independent copy +of $icode pattern$$; i.e. it has all the same values as $icode pattern$$ +and changes to $icode other$$ do not affect $icode pattern$$. +A move semantics version of the assignment operator is defined; e.g., +it is used when $icode other$$ in the assignment syntax +is a function return value. + +$subhead swap$$ +After the swap operation $icode other$$ ($icode pattern$$) is equivalent +to $icode pattern$$ ($icode other$$) before the operation. + +$head nr$$ +This argument has prototype +$codei% + size_t %nr% +%$$ +It specifies the number of rows in the sparsity pattern. +The function call $code nr()$$ returns the value of $icode nr$$. + +$head nc$$ +This argument has prototype +$codei% + size_t %nc% +%$$ +It specifies the number of columns in the sparsity pattern. +The function call $code nc()$$ returns the value of $icode nc$$. + +$head nnz$$ +This argument has prototype +$codei% + size_t %nnz% +%$$ +It specifies the number of possibly non-zero +index pairs in the sparsity pattern. +The function call $code nnz()$$ returns the value of $icode nnz$$. + +$head resize$$ +The current sparsity pattern is lost and a new one is started +with the specified parameters. The elements in the $icode row$$ +and $icode col$$ vectors should be assigned using $code set$$. + +$head set$$ +This function sets the values +$codei% + %row%[%k%] = %r% + %col%[%k%] = %c% +%$$ + +$subhead k$$ +This argument has type +$codei% + size_t %k% +%$$ +and must be less than $icode nnz$$. + +$subhead r$$ +This argument has type +$codei% + size_t %r% +%$$ +It specifies the value assigned to $icode%row%[%k%]%$$ and must +be less than $icode nr$$. + +$subhead c$$ +This argument has type +$codei% + size_t %c% +%$$ +It specifies the value assigned to $icode%col%[%k%]%$$ and must +be less than $icode nc$$. + +$head row$$ +This vector has size $icode nnz$$ and +$icode%row%[%k%]%$$ +is the row index of the $th k$$ possibly non-zero +index pair in the sparsity pattern. + +$head col$$ +This vector has size $icode nnz$$ and +$icode%col%[%k%]%$$ is the column index of the $th k$$ possibly non-zero +index pair in the sparsity pattern. + +$head row_major$$ +This vector has prototype +$codei% + %SizeVector% %row_major% +%$$ +and its size $icode nnz$$. +It sorts the sparsity pattern in row-major order. +To be specific, +$codei% + %col%[ %row_major%[%k%] ] <= %col%[ %row_major%[%k%+1] ] +%$$ +and if $icode%col%[ %row_major%[%k%] ] == %col%[ %row_major%[%k%+1] ]%$$, +$codei% + %row%[ %row_major%[%k%] ] < %row%[ %row_major%[%k%+1] ] +%$$ +This routine generates an assert if there are two entries with the same +row and column values (if $code NDEBUG$$ is not defined). + +$head col_major$$ +This vector has prototype +$codei% + %SizeVector% %col_major% +%$$ +and its size $icode nnz$$. +It sorts the sparsity pattern in column-major order. +To be specific, +$codei% + %row%[ %col_major%[%k%] ] <= %row%[ %col_major%[%k%+1] ] +%$$ +and if $icode%row%[ %col_major%[%k%] ] == %row%[ %col_major%[%k%+1] ]%$$, +$codei% + %col%[ %col_major%[%k%] ] < %col%[ %col_major%[%k%+1] ] +%$$ +This routine generates an assert if there are two entries with the same +row and column values (if $code NDEBUG$$ is not defined). + +$children% + example/utility/sparse_rc.cpp +%$$ +$head Example$$ +The file $cref sparse_rc.cpp$$ +contains an example and test of this class. + +$end +*/ +/*! +\file sparse_rc.hpp +A Matrix sparsity pattern class. +*/ +# include // for size_t +# include // for CPPAD_ASSERT +# include // for row and column major ordering + +namespace CppAD { // BEGIN CPPAD_NAMESPACE + +/// sparsity pattern for a matrix with indices of type size_t +template +class sparse_rc { +private: + /// number of rows in the sparsity pattern + size_t nr_; + /// number of columns in the sparsity pattern + size_t nc_; + /// number of possibly non-zero index pairs + size_t nnz_; + /// row_[k] is the row index for the k-th possibly non-zero entry + SizeVector row_; + /// col_[k] is the column index for the k-th possibly non-zero entry + SizeVector col_; +public: + /// default constructor + /// Eigen vector is ambiguous for row_(0), col_(0) so use default ctor + sparse_rc(void) + : nr_(0), nc_(0), nnz_(0) + { } + /// move semantics constructor + /// (none of the default constructor values are used by destructor) + sparse_rc(sparse_rc&& other) + { swap(other); } + /// destructor + ~sparse_rc(void) + { } + /// move semantics assignment + /// sizing constructor + /// Eigen vector is ambiguous for row_(0), col_(0) so use default ctor + sparse_rc(size_t nr, size_t nc, size_t nnz) + : nr_(nr), nc_(nc), nnz_(nnz) + { row_.resize(nnz); + col_.resize(nnz); + } + /// copy constructor + sparse_rc(const sparse_rc& other) + : + nr_(other.nr_) , + nc_(other.nc_) , + nnz_(other.nnz_) , + row_(other.row_) , + col_(other.col_) + { } + /// assignment + void operator=(const sparse_rc& other) + { nr_ = other.nr_; + nc_ = other.nc_; + nnz_ = other.nnz_; + // simple vector assignment requires vectors to have same size + row_.resize(nnz_); + col_.resize(nnz_); + row_ = other.row_; + col_ = other.col_; + } + /// swap + void swap(sparse_rc& other) + { std::swap( nr_ , other.nr_ ); + std::swap( nc_ , other.nc_ ); + std::swap( nnz_ , other.nnz_ ); + // + row_.swap( other.row_ ); + col_.swap( other.col_ ); + } + void operator=(sparse_rc&& other) + { swap(other); } + /// resize + void resize(size_t nr, size_t nc, size_t nnz) + { nr_ = nr; + nc_ = nc; + nnz_ = nnz; + row_.resize(nnz); + col_.resize(nnz); + } + /// set row and column for a possibly non-zero element + void set(size_t k, size_t r, size_t c) + { CPPAD_ASSERT_KNOWN( + k < nnz_, + "The index k is not less than nnz in sparse_rc::set" + ); + CPPAD_ASSERT_KNOWN( + r < nr_, + "The index r is not less than nr in sparse_rc::set" + ); + CPPAD_ASSERT_KNOWN( + c < nc_, + "The index c is to not less than nc in sparse_rc::set" + ); + row_[k] = r; + col_[k] = c; + // + } + /// number of rows in matrix + size_t nr(void) const + { return nr_; } + /// number of columns in matrix + size_t nc(void) const + { return nc_; } + /// number of possibly non-zero elements in matrix + size_t nnz(void) const + { return nnz_; } + /// row indices + const SizeVector& row(void) const + { return row_; } + /// column indices + const SizeVector& col(void) const + { return col_; } + /// row-major order + SizeVector row_major(void) const + { SizeVector keys(nnz_), row_major(nnz_); + for(size_t k = 0; k < nnz_; k++) + { CPPAD_ASSERT_UNKNOWN( row_[k] < nr_ ); + keys[k] = row_[k] * nc_ + col_[k]; + } + index_sort(keys, row_major); +# ifndef NDEBUG + for(size_t ell = 0; ell + 1 < nnz_; ell++) + { size_t k = row_major[ ell ]; + size_t kp = row_major[ ell + 1 ]; + CPPAD_ASSERT_KNOWN( + row_[k] != row_[kp] || col_[k] != col_[kp], + "sparse_rc: row_major: duplicate entry in this pattern" + ); + CPPAD_ASSERT_UNKNOWN( + row_[k] +%$$ +$codei%sparse_rcv<%SizeVector%, %ValueVector%> %empty% +%$$ +$codei%sparse_rcv<%SizeVector%, %ValueVector%> %matrix%(%pattern%) +%$$ +$icode%matrix% = %other% +%$$ +$icode%matrix%.swap( %other% ) +%$$ +$icode%matrix%.set(%k%, %v%) +%$$ +$icode%nr% = %matrix%.nr() +%$$ +$icode%nc% = %matrix%.nc() +%$$ +$icode%nnz% = %matrix%.nnz() +%$$ +$codei%const %SizeVector%& %row%( %matrix%.row() ) +%$$ +$codei%const %SizeVector%& %col%( %matrix%.col() ) +%$$ +$codei%const %ValueVector%& %val%( %matrix%.val() ) +%$$ +$codei%const sparse_rc<%SizeVector%>& %pat%( %matrix%.pat() ) +%$$ +$icode%row_major% = %matrix%.row_major() +%$$ +$icode%col_major% = %matrix%.col_major() +%$$ + +$head SizeVector$$ +We use $cref/SizeVector/sparse_rc/SizeVector/$$ to denote the +$cref SimpleVector$$ class corresponding to $icode pattern$$. + +$head ValueVector$$ +We use $icode ValueVector$$ to denote the +$cref SimpleVector$$ class corresponding to $icode val$$. + +$head empty$$ +This is an empty sparse matrix object. To be specific, +the corresponding number of rows $icode nr$$, +number of columns $icode nc$$, +and number of possibly non-zero values $icode nnz$$, +are all zero. + + +$head pattern$$ +This constructor argument has prototype +$codei% + const sparse_rc<%SizeVector%>& %pattern% +%$$ +It specifies the number of rows, number of columns and +the possibly non-zero entries in the $icode matrix$$. + +$head matrix$$ +This is a sparse matrix object with the sparsity specified by $icode pattern$$. +Only the $icode val$$ vector can be changed. All other values returned by +$icode matrix$$ are fixed during the constructor and constant there after. +The $icode val$$ vector is only changed by the constructor +and the $code set$$ function. +There are two exceptions to this rule, where $icode other$$ appears in the +assignment and swap syntax. + +$head other$$ +The $icode other$$ variable has prototype +$codei% + sparse_rcv<%SizeVector%, %ValueVector%> %other% +%$$ + +$subhead Assignment$$ +After this assignment statement, $icode other$$ is an independent copy +of $icode matrix$$; i.e. it has all the same values as $icode matrix$$ +and changes to $icode other$$ do not affect $icode matrix$$. +A move semantics version of the assignment operator is defined; e.g., +it is used when $icode other$$ in the assignment syntax +is a function return value; + +$subhead swap$$ +After the swap operation $icode other$$ ($icode matrix$$) is equivalent +to $icode matrix$$ ($icode other$$) before the operation. + +$head nr$$ +This return value has prototype +$codei% + size_t %nr% +%$$ +and is the number of rows in $icode matrix$$. + +$head nc$$ +This argument and return value has prototype +$codei% + size_t %nc% +%$$ +and is the number of columns in $icode matrix$$. + +$head nnz$$ +We use the notation $icode nnz$$ to denote the number of +possibly non-zero entries in $icode matrix$$. + +$head set$$ +This function sets the value +$codei% + %val%[%k%] = %v% +%$$ + +$subhead k$$ +This argument has type +$codei% + size_t %k% +%$$ +and must be less than $icode nnz$$. + +$subhead v$$ +This argument has type +$codei% + const %ValueVector%::value_type& %v% +%$$ +It specifies the value assigned to $icode%val%[%k%]%$$. + + +$head row$$ +This vector has size $icode nnz$$ and +$icode%row%[%k%]%$$ +is the row index of the $th k$$ possibly non-zero +element in $icode matrix$$. + +$head col$$ +This vector has size $icode nnz$$ and +$icode%col[%k%]%$$ is the column index of the $th k$$ possibly non-zero +element in $icode matrix$$ + +$head val$$ +This vector has size $icode nnz$$ and +$icode%val[%k%]%$$ is value of the $th k$$ possibly non-zero entry +in the sparse matrix (the value may be zero). + +$head pat$$ +This is equal to the sparsity pattern; i.e., +$icode pattern$$ in the constructor. + +$head row_major$$ +This vector has prototype +$codei% + %SizeVector% %row_major% +%$$ +and its size $icode nnz$$. +It sorts the sparsity pattern in row-major order. +To be specific, +$codei% + %col%[ %row_major%[%k%] ] <= %col%[ %row_major%[%k%+1] ] +%$$ +and if $icode%col%[ %row_major%[%k%] ] == %col%[ %row_major%[%k%+1] ]%$$, +$codei% + %row%[ %row_major%[%k%] ] < %row%[ %row_major%[%k%+1] ] +%$$ +This routine generates an assert if there are two entries with the same +row and column values (if $code NDEBUG$$ is not defined). + +$head col_major$$ +This vector has prototype +$codei% + %SizeVector% %col_major% +%$$ +and its size $icode nnz$$. +It sorts the sparsity pattern in column-major order. +To be specific, +$codei% + %row%[ %col_major%[%k%] ] <= %row%[ %col_major%[%k%+1] ] +%$$ +and if $icode%row%[ %col_major%[%k%] ] == %row%[ %col_major%[%k%+1] ]%$$, +$codei% + %col%[ %col_major%[%k%] ] < %col%[ %col_major%[%k%+1] ] +%$$ +This routine generates an assert if there are two entries with the same +row and column values (if $code NDEBUG$$ is not defined). + +$head Eigen Matrix$$ +If you have the $cref/eigen package/eigen/$$ in your include path, +you can use $cref sparse2eigen$$ to convert a sparse matrix to eigen format. + +$children% + example/utility/sparse_rcv.cpp +%$$ +$head Example$$ +The file $cref sparse_rcv.cpp$$ +contains an example and test of this class. + +$end +*/ +/*! +\file sparse_rcv.hpp +A sparse matrix class. +*/ +# include + +namespace CppAD { // BEGIN CPPAD_NAMESPACE + +/// Sparse matrices with elements of type Scalar +template +class sparse_rcv { +private: + /// sparsity pattern + sparse_rc pattern_; + /// value_type + typedef typename ValueVector::value_type value_type; + /// val_[k] is the value for the k-th possibly non-zero entry in the matrix + ValueVector val_; +public: + // ------------------------------------------------------------------------ + /// default constructor + sparse_rcv(void) + : pattern_(0, 0, 0) + { } + /// move semantics constructor + /// (none of the default constructor values are used by destructor) + sparse_rcv(sparse_rcv&& other) + { swap(other); } + /// destructor + ~sparse_rcv(void) + { } + /// constructor + sparse_rcv(const sparse_rc& pattern ) + : + pattern_(pattern) , + val_(pattern_.nnz()) + { } + /// assignment + void operator=(const sparse_rcv& other) + { pattern_ = other.pattern_; + // simple vector assignment requires vectors to have same size + val_.resize( other.nnz() ); + val_ = other.val(); + } + /// swap + void swap(sparse_rcv& other) + { pattern_.swap( other.pattern_ ); + val_.swap( other.val_ ); + } + /// move semantics assignment + void operator=(sparse_rcv&& other) + { swap(other); } + // ------------------------------------------------------------------------ + void set(size_t k, const value_type& v) + { CPPAD_ASSERT_KNOWN( + pattern_.nnz(), + "The index k is not less than nnz in sparse_rcv::set" + ); + val_[k] = v; + } + /// number of rows in matrix + size_t nr(void) const + { return pattern_.nr(); } + /// number of columns in matrix + size_t nc(void) const + { return pattern_.nc(); } + /// number of possibly non-zero elements in matrix + size_t nnz(void) const + { return pattern_.nnz(); } + /// row indices + const SizeVector& row(void) const + { return pattern_.row(); } + /// column indices + const SizeVector& col(void) const + { return pattern_.col(); } + /// value for possibly non-zero elements + const ValueVector& val(void) const + { return val_; } + /// sparsity pattern + const sparse_rc& pat(void) const + { return pattern_; } + /// row-major order + SizeVector row_major(void) const + { return pattern_.row_major(); } + /// column-major indices + SizeVector col_major(void) const + { return pattern_.col_major(); } +}; + +} // END_CPPAD_NAMESPACE + +# endif diff --git a/build-config/cppad/include/cppad/utility/speed_test.hpp b/build-config/cppad/include/cppad/utility/speed_test.hpp new file mode 100644 index 00000000..535f0971 --- /dev/null +++ b/build-config/cppad/include/cppad/utility/speed_test.hpp @@ -0,0 +1,477 @@ +# ifndef CPPAD_UTILITY_SPEED_TEST_HPP +# define CPPAD_UTILITY_SPEED_TEST_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +/* +$begin speed_test$$ +$spell + gettimeofday + vec + cppad.hpp + Microsoft + namespace + std + const + cout + ctime + ifdef + const + endif + cpp +$$ + + +$section Run One Speed Test and Return Results$$ + +$head Syntax$$ +$codei%# include +%$$ +$icode%rate_vec% = speed_test(%test%, %size_vec%, %time_min%)%$$ + +$head See Also$$ +$cref time_test$$ + +$head Purpose$$ +The $code speed_test$$ function executes a speed test +for various sized problems +and reports the rate of execution. + +$head Motivation$$ +It is important to separate small calculation units +and test them individually. +This way individual changes can be tested in the context of the +routine that they are in. +On many machines, accurate timing of a very short execution +sequences is not possible. +In addition, +there may be set up and tear down time for a test that +we do not really want included in the timing. +For this reason $code speed_test$$ +automatically determines how many times to +repeat the section of the test that we wish to time. + + +$head Include$$ +The file $code cppad/utility/speed_test.hpp$$ defines the +$code speed_test$$ function. +This file is included by $code cppad/cppad.hpp$$ +and it can also be included separately with out the rest of +the $code CppAD$$ routines. + +$head Vector$$ +We use $icode Vector$$ to denote a +$cref/simple vector class/SimpleVector/$$ with elements +of type $code size_t$$. + +$head test$$ +The $code speed_test$$ argument $icode test$$ is a function with the syntax +$codei% + %test%(%size%, %repeat%) +%$$ +and its return value is $code void$$. + +$subhead size$$ +The $icode test$$ argument $icode size$$ has prototype +$codei% + size_t %size% +%$$ +It specifies the size for this test. + +$subhead repeat$$ +The $icode test$$ argument $icode repeat$$ has prototype +$codei% + size_t %repeat% +%$$ +It specifies the number of times to repeat the test. + +$head size_vec$$ +The $code speed_test$$ argument $icode size_vec$$ has prototype +$codei% + const %Vector%& %size_vec% +%$$ +This vector determines the size for each of the tests problems. + +$head time_min$$ +The argument $icode time_min$$ has prototype +$codei% + double %time_min% +%$$ +It specifies the minimum amount of time in seconds +that the $icode test$$ routine should take. +The $icode repeat$$ argument to $icode test$$ is increased +until this amount of execution time is reached. + +$head rate_vec$$ +The return value $icode rate_vec$$ has prototype +$codei% + %Vector%& %rate_vec% +%$$ +We use $latex n$$ to denote its size which is the same as +the vector $icode size_vec$$. +For $latex i = 0 , \ldots , n-1$$, +$codei% + %rate_vec%[%i%] +%$$ +is the ratio of $icode repeat$$ divided by time in seconds +for the problem with size $icode%size_vec%[%i%]%$$. + +$head Timing$$ +If your system supports the unix $code gettimeofday$$ function, +it will be used to measure time. +Otherwise, +time is measured by the difference in +$codep + (double) clock() / (double) CLOCKS_PER_SEC +$$ +in the context of the standard $code $$ definitions. + +$children% + speed/example/speed_test.cpp +%$$ +$head Example$$ +The routine $cref speed_test.cpp$$ is an example and test +of $code speed_test$$. + +$end +----------------------------------------------------------------------- +*/ + +# include +# include + +# include +# include + + +namespace CppAD { // BEGIN CppAD namespace + +// implemented as an inline so that can include in multiple link modules +// with this same file +template +Vector speed_test( + void test(size_t size, size_t repeat), + const Vector& size_vec , + double time_min ) +{ + // check that size_vec is a simple vector with size_t elements + CheckSimpleVector(); + + size_t n = size_vec.size(); + Vector rate_vec(n); + size_t i; + for(i = 0; i < n; i++) + { size_t size = size_vec[i]; + size_t repeat = 1; + double s0 = elapsed_seconds(); + double s1 = elapsed_seconds(); + while( s1 - s0 < time_min ) + { repeat = 2 * repeat; + s0 = elapsed_seconds(); + test(size, repeat); + s1 = elapsed_seconds(); + } + double rate = .5 + double(repeat) / (s1 - s0); + // first convert to float to avoid warning with g++ -Wconversion + rate_vec[i] = static_cast( static_cast(rate) ); + } + return rate_vec; +} + +} // END CppAD namespace + +/* +$begin SpeedTest$$ +$spell + cppad.hpp + Microsoft + namespace + std + const + cout + ctime + ifdef + const + endif + cpp +$$ + + +$section Run One Speed Test and Print Results$$ + +$head Syntax$$ + +$codei%# include +%$$ +$codei%SpeedTest(%Test%, %first%, %inc%, %last%)%$$ + +$head See Also$$ +$cref time_test$$ + +$head Purpose$$ +The $code SpeedTest$$ function executes a speed test +for various sized problems +and reports the results on standard output; i.e. $code std::cout$$. +The size of each test problem is included in its report +(unless $icode first$$ is equal to $icode last$$). + +$head Motivation$$ +It is important to separate small calculation units +and test them individually. +This way individual changes can be tested in the context of the +routine that they are in. +On many machines, accurate timing of a very short execution +sequences is not possible. +In addition, +there may be set up time for a test that +we do not really want included in the timing. +For this reason $code SpeedTest$$ +automatically determines how many times to +repeat the section of the test that we wish to time. + + +$head Include$$ +The file $code speed_test.hpp$$ contains the +$code SpeedTest$$ function. +This file is included by $code cppad/utility/cppad.hpp$$ +but it can also be included separately with out the rest of +the $code CppAD$$ routines. + +$head Test$$ +The $code SpeedTest$$ argument $icode Test$$ is a function with the syntax +$codei% + %name% = %Test%(%size%, %repeat%) +%$$ + +$subhead size$$ +The $icode Test$$ argument $icode size$$ has prototype +$codei% + size_t %size% +%$$ +It specifies the size for this test. + +$subhead repeat$$ +The $icode Test$$ argument $icode repeat$$ has prototype +$codei% + size_t %repeat% +%$$ +It specifies the number of times to repeat the test. + +$subhead name$$ +The $icode Test$$ result $icode name$$ has prototype +$codei% + std::string %name% +%$$ +The results for this test are reported on $code std::cout$$ +with $icode name$$ as an identifier for the test. +It is assumed that, +for the duration of this call to $code SpeedTest$$, +$icode Test$$ will always return +the same value for $icode name$$. +If $icode name$$ is the empty string, +no test name is reported by $code SpeedTest$$. + +$head first$$ +The $code SpeedTest$$ argument $icode first$$ has prototype +$codei% + size_t %first% +%$$ +It specifies the size of the first test problem reported by this call to +$code SpeedTest$$. + +$head last$$ +The $code SpeedTest$$ argument $icode last$$ has prototype +$codei% + size_t %last% +%$$ +It specifies the size of the last test problem reported by this call to +$code SpeedTest$$. + +$head inc$$ +The $code SpeedTest$$ argument $icode inc$$ has prototype +$codei% + int %inc% +%$$ +It specifies the increment between problem sizes; i.e., +all values of $icode size$$ in calls to $icode Test$$ are given by +$codei% + %size% = %first% + %j% * %inc% +%$$ +where $icode j$$ is a positive integer. +The increment can be positive or negative but it cannot be zero. +The values $icode first$$, $icode last$$ and $icode inc$$ must +satisfy the relation +$latex \[ + inc * ( last - first ) \geq 0 +\] $$ + +$head rate$$ +The value displayed in the $code rate$$ column on $code std::cout$$ +is defined as the value of $icode repeat$$ divided by the +corresponding elapsed execution time in seconds. +The elapsed execution time is measured by the difference in +$codep + (double) clock() / (double) CLOCKS_PER_SEC +$$ +in the context of the standard $code $$ definitions. + + +$head Errors$$ +If one of the restrictions above is violated, +the CppAD error handler is used to report the error. +You can redefine this action using the instructions in +$cref ErrorHandler$$ + +$head Example$$ +$children% + speed/example/speed_program.cpp +%$$ +The program $cref speed_program.cpp$$ is an example usage +of $code SpeedTest$$. + +$end +----------------------------------------------------------------------- +*/ +// BEGIN C++ + + +# include +# include +# include +# include + +namespace CppAD { // BEGIN CppAD namespace + +inline void SpeedTestNdigit(size_t value, size_t &ndigit, size_t &pow10) +{ pow10 = 10; + ndigit = 1; + while( pow10 <= value ) + { pow10 *= 10; + ndigit += 1; + } +} + +// implemented as an inline so that can include in multiple link modules +// with this same file +inline void SpeedTest( + std::string Test(size_t size, size_t repeat), + size_t first, + int inc, + size_t last +) +{ + + using std::cout; + using std::endl; + + size_t size; + size_t repeat; + size_t rate; + size_t digit; + size_t ndigit; + size_t pow10; + size_t maxSize; + size_t maxSizeDigit; + + double s0; + double s1; + + std::string name; + + CPPAD_ASSERT_KNOWN( + inc != 0 && first != 0 && last != 0, + "inc, first, or last is zero in call to SpeedTest" + ); + CPPAD_ASSERT_KNOWN( + (inc > 0 && first <= last) || (inc < 0 && first >= last), + "SpeedTest: increment is positive and first > last or " + "increment is negative and first < last" + ); + + // compute maxSize + maxSize = size = first; + while( (inc > 0 && size <= last) || (inc < 0 && size >= last) ) + { + if( size > maxSize ) + maxSize = size; + + // next size + if( int(size) + inc > 0 ) + size = size_t( int(size) + inc ); + else + size = 0; + } + SpeedTestNdigit(maxSize, maxSizeDigit, pow10); + + size = first; + while( (inc > 0 && size <= last) || (inc < 0 && size >= last) ) + { + repeat = 1; + s0 = elapsed_seconds(); + s1 = elapsed_seconds(); + while( s1 - s0 < 1. ) + { repeat = 2 * repeat; + s0 = elapsed_seconds(); + name = Test(size, repeat); + s1 = elapsed_seconds(); + } + double r = .5 + double(repeat) / (s1 - s0); + // first convert to float to avoid warning with g++ -Wconversion + rate = static_cast( static_cast( r ) ); + + if( size == first && name != "" ) + cout << name << endl; + + if( first != last ) + { + // convert int(size_t) to avoid warning on _MSC_VER sys + std::cout << "size = " << int(size); + + SpeedTestNdigit(size, ndigit, pow10); + while( ndigit < maxSizeDigit ) + { cout << " "; + ndigit++; + } + cout << " "; + } + + cout << "rate = "; + SpeedTestNdigit(rate, ndigit, pow10); + while( ndigit > 0 ) + { + pow10 /= 10; + digit = rate / pow10; + + // convert int(size_t) to avoid warning on _MSC_VER sys + std::cout << int(digit); + + rate = rate % pow10; + ndigit -= 1; + + if( (ndigit > 0) && (ndigit % 3 == 0) ) + cout << ","; + } + cout << endl; + + // next size + if( int(size) + inc > 0 ) + size = size_t( int(size) + inc ); + else + size = 0; + } + return; +} + +} // END CppAD namespace + +// END C++ +# endif diff --git a/build-config/cppad/include/cppad/utility/test_boolofvoid.hpp b/build-config/cppad/include/cppad/utility/test_boolofvoid.hpp new file mode 100644 index 00000000..903e1f3d --- /dev/null +++ b/build-config/cppad/include/cppad/utility/test_boolofvoid.hpp @@ -0,0 +1,172 @@ +# ifndef CPPAD_UTILITY_TEST_BOOLOFVOID_HPP +# define CPPAD_UTILITY_TEST_BOOLOFVOID_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-18 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ +/* +$begin test_boolofvoid$$ +$spell + boolofvoid + const + std + bool + ipopt + cpp + cppad + hpp +$$ + +$section Object that Runs a Group of Tests$$ + +$head Syntax$$ +$codei%# include +%$$ +$codei%test_boolofvoid %Run%(%group%, %width%) +%$$ +$icode%Run%(%test%, %name%) +%$$ +$icode%ok% = %Run%.summary(%memory_ok%)%$$ + +$head Purpose$$ +The object $icode Run$$ is used to run a group of tests functions +and report the results on standard output. + +$head group$$ +The argument has prototype +$codei% + const std::string& %group% +%$$ +It is the name for this group of tests. + +$head width$$ +The argument has prototype +$codei% + size_t %width% +%$$ +It is the number of columns used to display the name of each test. +It must be greater than the maximum number of characters in a test name. + +$head test$$ +The argument has prototype +$codei% + bool %test%(void) +%$$ +It is a function that returns true (when the test passes) and false +otherwise. + +$head name$$ +The argument has prototype +$codei% + const std::string& %name% +%$$ +It is the name for the corresponding $icode test$$. + +$head memory_ok$$ +The argument has prototype +$codei% + bool %memory_ok% +%$$ +It is false if a memory leak is detected (and true otherwise). + +$head ok$$ +This is true if all of the tests pass (including the memory leak test), +otherwise it is false. + +$head Example$$ +See any of the main programs in the example directory; e.g., +$code example/ipopt_solve.cpp$$. + +$end +*/ + +# include +# include + +namespace CppAD { // BEGIN_CPPAD_NAMESPACE + +/// One class object is used to run a group of tests +class test_boolofvoid { +private: + /// name for the group of test this object will run + const std::string group_; + /// number of characters used to display the name for each indiviual test + /// (must be larger than the number of characters in name for each test) + const size_t width_; + /// number of tests that have passed + size_t n_ok_; + /// number of tests that have failed + size_t n_error_; + +public: + /// ctor + test_boolofvoid(const std::string& group, size_t width) : + group_(group) , + width_(width) , + n_ok_(0) , + n_error_(0) + { std::cout << "Begin test group " << group_ << std::endl; } + /// destructor + ~test_boolofvoid(void) + { std::cout << "End test group " << group_ << std::endl; } + /// run one test + bool operator()(bool test(void), const std::string& name) + { CPPAD_ASSERT_KNOWN( + name.size() < width_ , + "test_boolofvoid: name does not have less characters than width" + ); + std::cout.width( int(width_) ); + std::cout.setf( std::ios_base::left ); + std::cout << name; + // + bool ok = test(); + if( ok ) + { std::cout << "OK" << std::endl; + n_ok_++; + } + else + { std::cout << "Error" << std::endl; + n_error_++; + } + return ok; + } + /// nuber of tests that passed + size_t n_ok(void) const + { return n_ok_; } + /// nuber of tests that failed + size_t n_error(void) const + { return n_error_; } + /// summary + bool summary(bool memory_ok ) + { + std::cout.width( int(width_) ); + std::cout.setf( std::ios_base::left ); + std::cout << "memory_leak"; + // + if( memory_ok ) + { std::cout << "OK" << std::endl; + n_ok_++; + } + else + { std::cout << "Error" << std::endl; + n_error_++; + } + if( n_error_ == 0 ) + std::cout << "All " << n_ok_ << " tests passed." << std::endl; + else + std::cout << n_error_ << " tests failed." << std::endl; + // + return n_error_ == 0; + } +}; + +} // END_CPPAD_NAMESPACE + +# endif diff --git a/build-config/cppad/include/cppad/utility/thread_alloc.hpp b/build-config/cppad/include/cppad/utility/thread_alloc.hpp new file mode 100644 index 00000000..50b9a1be --- /dev/null +++ b/build-config/cppad/include/cppad/utility/thread_alloc.hpp @@ -0,0 +1,1515 @@ +# ifndef CPPAD_UTILITY_THREAD_ALLOC_HPP +# define CPPAD_UTILITY_THREAD_ALLOC_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +# include +# include +# include + + +# ifdef _MSC_VER +// Supress warning that Microsoft compiler changed its behavior and is now +// doing the correct thing at the statement: +// new(array + i) Type(); +# pragma warning(disable:4345) +# endif + +# include +# include +# include +namespace CppAD { // BEGIN_CPPAD_NAMESPACE +/*! +\file thread_alloc.hpp +File used to define the CppAD multi-threading allocator class +*/ + +/*! +\def CPPAD_MAX_NUM_CAPACITY +Maximum number of different capacities the allocator will attempt. +This must be larger than the log base two of numeric_limit::max(). +*/ +# define CPPAD_MAX_NUM_CAPACITY 100 + +/*! +\def CPPAD_MIN_DOUBLE_CAPACITY +Minimum number of double values that will fit in an allocation. +*/ +# define CPPAD_MIN_DOUBLE_CAPACITY 16 + +/*! +\def CPPAD_TRACE_CAPACITY +If NDEBUG is not defined, print all calls to get_memory and return_memory +that correspond to this capacity and thread CPPAD_TRACE_THREAD. +(Note that if CPPAD_TRACE_CAPACITY is zero, or any other value not in the list +of capacities, no tracing will be done.) +*/ +# define CPPAD_TRACE_CAPACITY 0 + +/*! +\def CPPAD_TRACE_THREAD +If NDEBUG is not defined, print all calls to get_memory and return_memory +that correspond to this thead and capacity CPPAD_TRACE_CAPACITY. +*/ +# define CPPAD_TRACE_THREAD 0 + +/* +Note that Section 3.6.2 of ISO/IEC 14882:1998(E) states: "The storage for +objects with static storage duration (3.7.1) shall be zero-initialized +(8.5) before any other initialization takes place." +*/ + +/*! +Capacity vector for memory allocation block sizes. + +Only one of these objects should be created and used as a +static variable inside of the thread_alloc::capacity_info function. +*/ + +/*! +Allocator class that works well with an multi-threading environment. +*/ +class thread_alloc{ +// ============================================================================ +private: + + class capacity_t { + public: + /// number of capacity values actually used + size_t number; + /// the different capacity values + size_t value[CPPAD_MAX_NUM_CAPACITY]; + /// ctor + capacity_t(void) + { // Cannot figure out how to call thread_alloc::in_parallel here. + // CPPAD_ASSERT_UNKNOWN( + // ! thread_alloc::in_parallel() , "thread_alloc: " + // "parallel mode and parallel_setup not yet called." + // ); + number = 0; + size_t capacity = CPPAD_MIN_DOUBLE_CAPACITY * sizeof(double); + while( capacity < std::numeric_limits::max() / 2 ) + { CPPAD_ASSERT_UNKNOWN( number < CPPAD_MAX_NUM_CAPACITY ); + value[number++] = capacity; + // next capactiy is 3/2 times the current one + capacity = 3 * ( (capacity + 1) / 2 ); + } + CPPAD_ASSERT_UNKNOWN( number > 0 ); + } + }; + + class block_t { + public: + /// extra information (currently used by create and delete array) + size_t extra_; + /// an index that uniquely idenfifies both thread and capacity + size_t tc_index_; + /// pointer to the next memory allocation with the same tc_index_ + void* next_; + // ----------------------------------------------------------------- + /// make default constructor private. It is only used by constructor + /// for `root arrays below. + block_t(void) : extra_(0), tc_index_(0), next_(nullptr) + { } + }; + + // --------------------------------------------------------------------- + /// Vector of fixed capacity values for this allocator + static const capacity_t* capacity_info(void) + { CPPAD_ASSERT_FIRST_CALL_NOT_PARALLEL; + static const capacity_t capacity; + return &capacity; + } + // --------------------------------------------------------------------- + /// Structure of information for each thread + struct thread_alloc_info { + /// count of available bytes for this thread + size_t count_inuse_; + /// count of inuse bytes for this thread + size_t count_available_; + /// root of available list for this thread and each capacity + block_t root_available_[CPPAD_MAX_NUM_CAPACITY]; + /*! + root of inuse list for this thread and each capacity + If NDEBUG or CPPAD_DEBUG_AND_RELEASE is defined, this memory is not + used, but it still helps to separate this structure from the structure + for the next thread. + */ + block_t root_inuse_[CPPAD_MAX_NUM_CAPACITY]; + }; + // --------------------------------------------------------------------- + /*! + Set and Get hold available memory flag. + + \param set [in] + if true, the value returned by this return is changed. + + \param new_value [in] + if set is true, this is the new value returned by this routine. + Otherwise, new_value is ignored. + + \return + the current setting for this routine (which is initially false). + */ + static bool set_get_hold_memory(bool set, bool new_value = false) + { static bool value = false; + if( set ) + value = new_value; + return value; + } + // --------------------------------------------------------------------- + /*! + Get pointer to the information for this thread. + + \param thread [in] + Is the thread number for this information pointer. + + \param clear + If clear is true, then the information pointer for this thread + is deleted and the nullptr pointer is returned. + There must be no memory currently in either the inuse or avaialble + lists when this routine is called. + + \return + is the current informaiton pointer for this thread. + If clear is false, and the current pointer is nullptr, + a new infromation record is allocated and its pointer returned. + In this case, if info is the retured pointer, + info->count_inuse == 0 and + info->count_available == 0. + In addition, + for c = 0 , ... , CPPAD_MAX_NUM_CAPACITY-1 + info->root_inuse_[c].next_ == nullptr and + info->root_available_[c].next_ == nullptr. + */ + static thread_alloc_info* thread_info( + size_t thread , + bool clear = false ) + { static thread_alloc_info* all_info[CPPAD_MAX_NUM_THREADS]; + static thread_alloc_info zero_info; + + CPPAD_ASSERT_FIRST_CALL_NOT_PARALLEL; + + CPPAD_ASSERT_UNKNOWN( thread < CPPAD_MAX_NUM_THREADS ); + + thread_alloc_info* info = all_info[thread]; + if( clear ) + { if( info != nullptr ) + { +# ifndef NDEBUG + CPPAD_ASSERT_UNKNOWN( + info->count_inuse_ == 0 && + info->count_available_ == 0 + ); + for(size_t c = 0; c < CPPAD_MAX_NUM_CAPACITY; c++) + { CPPAD_ASSERT_UNKNOWN( + info->root_inuse_[c].next_ == nullptr && + info->root_available_[c].next_ == nullptr + ); + } +# endif + if( thread != 0 ) + ::operator delete( reinterpret_cast(info) ); + info = nullptr; + all_info[thread] = info; + } + } + else if( info == nullptr ) + { if( thread == 0 ) + info = &zero_info; + else + { size_t size = sizeof(thread_alloc_info); + void* v_ptr = ::operator new(size); + info = reinterpret_cast(v_ptr); + } + all_info[thread] = info; + + // initialize the information record + for(size_t c = 0; c < CPPAD_MAX_NUM_CAPACITY; c++) + { info->root_inuse_[c].next_ = nullptr; + info->root_available_[c].next_ = nullptr; + } + info->count_inuse_ = 0; + info->count_available_ = 0; + } + return info; + } + // ----------------------------------------------------------------------- + /*! + Increase the number of bytes of memory that are currently in use; i.e., + that been obtained with get_memory and not yet returned. + + \param inc [in] + amount to increase memory in use. + + \param thread [in] + Thread for which we are increasing the number of bytes in use + (must be less than num_threads). + Durring parallel execution, this must be the thread + that is currently executing. + */ + static void inc_inuse(size_t inc, size_t thread) + { + CPPAD_ASSERT_UNKNOWN( thread < num_threads() ); + CPPAD_ASSERT_UNKNOWN( + thread == thread_num() || (! in_parallel()) + ); + thread_alloc_info* info = thread_info(thread); + + // do the addition + size_t result = info->count_inuse_ + inc; + CPPAD_ASSERT_UNKNOWN( result >= info->count_inuse_ ); + + info->count_inuse_ = result; + } + // ----------------------------------------------------------------------- + /*! + Increase the number of bytes of memory that are currently avaialble; i.e., + have been obtained obtained from the system and are being held future use. + + \copydetails inc_inuse + */ + static void inc_available(size_t inc, size_t thread) + { + CPPAD_ASSERT_UNKNOWN( thread < CPPAD_MAX_NUM_THREADS); + CPPAD_ASSERT_UNKNOWN( + thread == thread_num() || (! in_parallel()) + ); + thread_alloc_info* info = thread_info(thread); + // do the addition + size_t result = info->count_available_ + inc; + CPPAD_ASSERT_UNKNOWN( result >= info->count_available_ ); + + info->count_available_ = result; + } + // ----------------------------------------------------------------------- + /*! + Decrease the number of bytes of memory that are currently in use; i.e., + that been obtained with get_memory and not yet returned. + + \param dec [in] + amount to decrease number of bytes in use. + + \param thread [in] + Thread for which we are decreasing the number of bytes in use + (must be less than num_threads). + Durring parallel execution, this must be the thread + that is currently executing. + */ + static void dec_inuse(size_t dec, size_t thread) + { + CPPAD_ASSERT_UNKNOWN( + thread < num_threads() || (! in_parallel()) + ); + CPPAD_ASSERT_UNKNOWN( + thread == thread_num() || (! in_parallel()) + ); + thread_alloc_info* info = thread_info(thread); + + // do the subtraction + CPPAD_ASSERT_UNKNOWN( info->count_inuse_ >= dec ); + info->count_inuse_ = info->count_inuse_ - dec; + } + // ----------------------------------------------------------------------- + /*! + Decrease the number of bytes of memory that are currently avaialble; i.e., + have been obtained obtained from the system and are being held future use. + + \copydetails dec_inuse + */ + static void dec_available(size_t dec, size_t thread) + { + CPPAD_ASSERT_UNKNOWN( thread < CPPAD_MAX_NUM_THREADS); + CPPAD_ASSERT_UNKNOWN( + thread == thread_num() || (! in_parallel()) + ); + thread_alloc_info* info = thread_info(thread); + // do the subtraction + CPPAD_ASSERT_UNKNOWN( info->count_available_ >= dec ); + info->count_available_ = info->count_available_ - dec; + } + + // ---------------------------------------------------------------------- + /*! + Set and get the number of threads that are sharing memory. + + \param number_new + If number is zero, we are only retreiving the current maximum + number of threads. Otherwise, we are setting and retreiving + maximum number of threads. + + \return + the number of threads that are sharing memory. + If number_new is non-zero, the return value is equal to + number_new. + */ + static size_t set_get_num_threads(size_t number_new) + { static size_t number_user = 1; + + CPPAD_ASSERT_UNKNOWN( number_new <= CPPAD_MAX_NUM_THREADS ); + CPPAD_ASSERT_UNKNOWN( ! in_parallel() || (number_new == 0) ); + + // case where we are changing the number of threads + if( number_new != 0 ) + number_user = number_new; + + return number_user; + } + /*! + Set and call the routine that determine the current thread number. + + \return + returns value for the most recent setting for thread_num_new. + If set is true, + or the most recent setting is nullptr (its initial value), + the return value is zero. + Otherwise the routine corresponding to the most recent setting + is called and its value returned by set_get_thread_num. + + \param thread_num_new [in] + If set is false, thread_num_new it is not used. + Otherwise, the current value of thread_num_new becomes the + most recent setting for thread_num. + + \param set + If set is true, then thread_num_new is becomes the most + recent setting for this set_get_thread_num. + */ + static size_t set_get_thread_num( + size_t (*thread_num_new)(void) , + bool set = false ) + { static size_t (*thread_num_user)(void) = nullptr; + + if( set ) + { thread_num_user = thread_num_new; + return 0; + } + + if( thread_num_user == nullptr ) + return 0; + + size_t thread = thread_num_user(); + CPPAD_ASSERT_KNOWN( + thread < set_get_num_threads(0) , + "parallel_setup: thread_num() >= num_threads" + ); + return thread; + } +// ============================================================================ +public: +/* +$begin ta_parallel_setup$$ +$spell + alloc + num + bool +$$ +$section Setup thread_alloc For Use in Multi-Threading Environment$$ + + + + +$head Syntax$$ +$codei%thread_alloc::parallel_setup(%num_threads%, %in_parallel%, %thread_num%) +%$$ + +$head Purpose$$ +By default there is only one thread and all execution is in sequential mode, +i.e., multiple threads are not sharing the same memory; i.e. +not in parallel mode. + +$head Speed$$ +It should be faster, even when $icode num_thread$$ is equal to one, +for $code thread_alloc$$ to hold onto memory. +This can be accomplished using the function call +$codei% + thread_alloc::hold_memory(true) +%$$ +see $cref/hold_memory/ta_hold_memory/$$. + +$head num_threads$$ +This argument has prototype +$codei% + size_t %num_threads% +%$$ +and must be greater than zero. +It specifies the number of threads that are sharing memory. +The case $icode%num_threads% == 1%$$ is a special case that is +used to terminate a multi-threading environment. + +$head in_parallel$$ +This function has prototype +$codei% + bool %in_parallel%(void) +%$$ +It must return $code true$$ if there is more than one thread +currently executing. +Otherwise it can return false. +$pre + +$$ +In the special case where $icode%num_threads% == 1%$$, +the routine $icode in_parallel$$ is not used. + +$head thread_num$$ +This function has prototype +$codei% + size_t %thread_num%(void) +%$$ +It must return a thread number that uniquely identifies the +currently executing thread. +Furthermore +$codei% + 0 <= %thread_num%() < %num_threads% +%$$. +In the special case where $icode%num_threads% == 1%$$, +the routine $icode thread_num$$ is not used. +$pre + +$$ +Note that this function is called by other routines so, +as soon as a new thread is executing, +one must be certain that $icode thread_num()$$ will +work for that thread. + +$head Restrictions$$ +The function $code parallel_setup$$ must be called before +the program enters $cref/parallel/ta_in_parallel/$$ execution mode. +In addition, this function cannot be called while in parallel mode. + +$head Example$$ +The files +$cref simple_ad_openmp.cpp$$, +$cref simple_ad_bthread.cpp$$, and +$cref simple_ad_pthread.cpp$$, +contain examples and tests that use this function. + +$end +*/ + /*! + Set thread_alloc up for parallel mode usage. + + \param num_threads [in] + Is the number of thread that may be executing at the same time. + + \param in_parallel [in] + Is the routine that determines if we are in parallel mode or not. + + \param thread_num [in] + Is the routine that determines the current thread number + (between zero and num_threads minus one). + */ + static void parallel_setup( + size_t num_threads , + bool (*in_parallel)(void) , + size_t (*thread_num)(void) ) + { + // Special case where we go back to single thread mode right away + // (previous settings may no longer be valid) + if( num_threads == 1 ) + { bool set = true; + set_get_num_threads(num_threads); + // emphasize that this routine is outside thread_alloc class + CppAD::local::set_get_in_parallel(nullptr, set); + set_get_thread_num(nullptr, set); + return; + } + + CPPAD_ASSERT_KNOWN( + num_threads <= CPPAD_MAX_NUM_THREADS , + "parallel_setup: num_threads is too large" + ); + CPPAD_ASSERT_KNOWN( + num_threads != 0 , + "parallel_setup: num_threads == zero" + ); + CPPAD_ASSERT_KNOWN( + in_parallel != nullptr , + "parallel_setup: num_threads != 1 and in_parallel == nullptr" + ); + CPPAD_ASSERT_KNOWN( + thread_num != nullptr , + "parallel_setup: num_threads != 1 and thread_num == nullptr" + ); + + // Make sure that constructors for all static variables in this file + // are called in sequential mode. + for(size_t thread = 0; thread < num_threads; thread++) + thread_info(thread); + capacity_info(); + size_t cap_bytes; + void* v_ptr = get_memory(0, cap_bytes); + + // free memory allocated by call to get_memory above + return_memory(v_ptr); + free_available( set_get_thread_num(nullptr) ); + + // delay this so thread_num() call above is in previous mode + // (current setings may not yet be valid) + if( num_threads > 1 ) + { bool set = true; + set_get_num_threads(num_threads); + // emphasize that this routine is outside thread_alloc class + CppAD::local::set_get_in_parallel(in_parallel, set); + set_get_thread_num(thread_num, set); + } + } +/* +$begin ta_num_threads$$ +$spell + inv + CppAD + num + alloc +$$ +$section Get Number of Threads$$ + + +$head Syntax$$ +$icode%number% = thread_alloc::num_threads()%$$ + +$head Purpose$$ +Determine the number of threads as set during $cref/parallel_setup/ta_parallel_setup/$$. + +$head number$$ +The return value $icode number$$ has prototype +$codei% + size_t %number% +%$$ +and is equal to the value of +$cref/num_threads/ta_parallel_setup/num_threads/$$ +in the previous call to $icode parallel_setup$$. +If there was no such previous call, the value one is returned. + +$head Example$$ +The example and test $cref thread_alloc.cpp$$ uses this routine. + +$end +*/ + /*! + Get the current number of threads that thread_alloc can use. + */ + static size_t num_threads(void) + { return set_get_num_threads(0); } +/* ----------------------------------------------------------------------- +$begin ta_in_parallel$$ + +$section Is The Current Execution in Parallel Mode$$ +$spell + thread_alloc + bool +$$ + + +$head Syntax$$ +$icode%flag% = thread_alloc::in_parallel()%$$ + +$head Purpose$$ +Some of the $cref thread_alloc$$ allocation routines have different +specifications for parallel (not sequential) execution mode. +This routine enables you to determine if the current execution mode +is sequential or parallel. + +$head flag$$ +The return value has prototype +$codei% + bool %flag% +%$$ +It is true if the current execution is in parallel mode +(possibly multi-threaded) and false otherwise (sequential mode). + +$head Example$$ +$cref thread_alloc.cpp$$ + +$end +*/ + /// Are we in a parallel execution state; i.e., is it possible that + /// other threads are currently executing. + static bool in_parallel(void) + { // emphasize that this routine is outside thread_alloc class + return CppAD::local::set_get_in_parallel(0); + } +/* ----------------------------------------------------------------------- +$begin ta_thread_num$$ +$spell + CppAD + num + thread_alloc + cppad.hpp +$$ + +$section Get the Current Thread Number$$ + + +$head Syntax$$ +$icode%thread% = thread_alloc::thread_num()%$$ + +$head Purpose$$ +Some of the $cref thread_alloc$$ allocation routines have a thread number. +This routine enables you to determine the current thread. + +$head thread$$ +The return value $icode thread$$ has prototype +$codei% + size_t %thread% +%$$ +and is the currently executing thread number. + +$head Example$$ +$cref thread_alloc.cpp$$ + +$end +*/ + /// Get current thread number + static size_t thread_num(void) + { return set_get_thread_num(nullptr); } +/* ----------------------------------------------------------------------- +$begin ta_get_memory$$ +$spell + std + num + ptr + thread_alloc +$$ + +$section Get At Least A Specified Amount of Memory$$ + + +$head Syntax$$ +$icode%v_ptr% = thread_alloc::get_memory(%min_bytes%, %cap_bytes%)%$$ + +$head Purpose$$ +Use $cref thread_alloc$$ to obtain a minimum number of bytes of memory +(for use by the $cref/current thread/ta_thread_num/$$). + +$head min_bytes$$ +This argument has prototype +$codei% + size_t %min_bytes% +%$$ +It specifies the minimum number of bytes to allocate. +This value must be less than +$codep + std::numeric_limits::max() / 2 +$$ + +$head cap_bytes$$ +This argument has prototype +$codei% + size_t& %cap_bytes% +%$$ +It's input value does not matter. +Upon return, it is the actual number of bytes (capacity) +that have been allocated for use, +$codei% + %min_bytes% <= %cap_bytes% +%$$ + +$head v_ptr$$ +The return value $icode v_ptr$$ has prototype +$codei% + void* %v_ptr% +%$$ +It is the location where the $icode cap_bytes$$ of memory +that have been allocated for use begins. + +$head Allocation Speed$$ +This allocation should be faster if the following conditions hold: +$list number$$ +The memory allocated by a previous call to $code get_memory$$ +is currently available for use. +$lnext +The current $icode min_bytes$$ is between +the previous $icode min_bytes$$ and previous $icode cap_bytes$$. +$lend + +$head Alignment$$ +We call a memory allocation aligned if the address is a multiple +of the number of bytes in a $code size_t$$ value. +If the system $code new$$ allocator is aligned, then $icode v_ptr$$ +pointer is also aligned. + +$head Example$$ +$cref thread_alloc.cpp$$ + +$end +*/ + /*! + Use thread_alloc to get a specified amount of memory. + + If the memory allocated by a previous call to get_memory is now + avaialable, and min_bytes is between its previous value + and the previous cap_bytes, this memory allocation will have + optimal speed. Otherwise, the memory allocation is more complicated and + may have to wait for other threads to complete an allocation. + + \param min_bytes [in] + The minimum number of bytes of memory to be obtained for use. + + \param cap_bytes [out] + The actual number of bytes of memory obtained for use. + + \return + pointer to the beginning of the memory allocated for use. + */ + static void* get_memory(size_t min_bytes, size_t& cap_bytes) + { // see first_trace below + CPPAD_ASSERT_FIRST_CALL_NOT_PARALLEL; + + // check that number of requested bytes is not to large + CPPAD_ASSERT_KNOWN( + min_bytes < std::numeric_limits::max() / 2 , + "get_memory(min_bytes, cap_bytes): min_bytes is too large" + ); + + size_t num_cap = capacity_info()->number; + using std::cout; + using std::endl; + + // determine the capacity for this request + size_t c_index = 0; + const size_t* capacity_vec = capacity_info()->value; + while( capacity_vec[c_index] < min_bytes ) + { ++c_index; + CPPAD_ASSERT_UNKNOWN(c_index < num_cap ); + } + cap_bytes = capacity_vec[c_index]; + + // determine the thread, capacity, and info for this thread + size_t thread = thread_num(); + size_t tc_index = thread * num_cap + c_index; + thread_alloc_info* info = thread_info(thread); + +# ifndef NDEBUG + // trace allocation + static bool first_trace = true; + if( cap_bytes == CPPAD_TRACE_CAPACITY && + thread == CPPAD_TRACE_THREAD && first_trace ) + { cout << endl; + cout << "thread_alloc: Trace for Thread = " << thread; + cout << " and capacity = " << cap_bytes << endl; + if( first_trace ) + first_trace = false; + } + +# ifndef CPPAD_DEBUG_AND_RELEASE + // Root nodes for both lists. Note these are different for different + // threads because tc_index is different for different threads. + block_t* inuse_root = info->root_inuse_ + c_index; +# endif +# endif + block_t* available_root = info->root_available_ + c_index; + + // check if we already have a node we can use + void* v_node = available_root->next_; + block_t* node = reinterpret_cast(v_node); + if( node != nullptr ) + { CPPAD_ASSERT_UNKNOWN( node->tc_index_ == tc_index ); + + // remove node from available list + available_root->next_ = node->next_; + + // return value for get_memory + void* v_ptr = reinterpret_cast(node + 1); +# ifndef NDEBUG +# ifndef CPPAD_DEBUG_AND_RELEASE + // add node to inuse list + node->next_ = inuse_root->next_; + inuse_root->next_ = v_node; +# endif + + // trace allocation + if( cap_bytes == CPPAD_TRACE_CAPACITY && + thread == CPPAD_TRACE_THREAD ) + { cout << "get_memory: v_ptr = " << v_ptr << endl; } +# endif + + // adjust counts + inc_inuse(cap_bytes, thread); + dec_available(cap_bytes, thread); + + // return pointer to memory, do not inclue thread_alloc information + return v_ptr; + } + + // Create a new node with thread_alloc information at front. + // This uses the system allocator, which is thread safe, but slower, + // because the thread might wait for a lock on the allocator. + v_node = ::operator new(sizeof(block_t) + cap_bytes); + node = reinterpret_cast(v_node); + node->tc_index_ = tc_index; + void* v_ptr = reinterpret_cast(node + 1); + +# ifndef NDEBUG +# ifndef CPPAD_DEBUG_AND_RELEASE + // add node to inuse list + node->next_ = inuse_root->next_; + inuse_root->next_ = v_node; +# endif + + // trace allocation + if( cap_bytes == CPPAD_TRACE_CAPACITY && + thread == CPPAD_TRACE_THREAD ) + { cout << "get_memory: v_ptr = " << v_ptr << endl; } +# endif + + // adjust counts + inc_inuse(cap_bytes, thread); + + return v_ptr; + } + +/* ----------------------------------------------------------------------- +$begin ta_return_memory$$ +$spell + num + ptr + thread_alloc +$$ + +$section Return Memory to thread_alloc$$ + + +$head Syntax$$ +$codei%thread_alloc::return_memory(%v_ptr%)%$$ + +$head Purpose$$ +If $cref/hold_memory/ta_hold_memory/$$ is false, +the memory is returned to the system. +Otherwise, the memory is retained by $cref thread_alloc$$ for quick future use +by the thread that allocated to memory. + +$head v_ptr$$ +This argument has prototype +$codei% + void* %v_ptr% +%$$. +It must be a pointer to memory that is currently in use; i.e. +obtained by a previous call to +$cref/get_memory/ta_get_memory/$$ and not yet returned. + +$head Thread$$ +Either the $cref/current thread/ta_thread_num/$$ must be the same as during +the corresponding call to $cref/get_memory/ta_get_memory/$$, +or the current execution mode must be sequential +(not $cref/parallel/ta_in_parallel/$$). + +$head NDEBUG$$ +If $code NDEBUG$$ is defined, $icode v_ptr$$ is not checked (this is faster). +Otherwise, a list of in use pointers is searched to make sure +that $icode v_ptr$$ is in the list. + +$head Example$$ +$cref thread_alloc.cpp$$ + +$end +*/ + /*! + Return memory that was obtained by get_memory. + If num_threads() == 1, + the memory is returned to the system. + Otherwise, it is retained by thread_alloc and available for use by + get_memory for this thread. + + \param v_ptr [in] + Value of the pointer returned by get_memory and still in use. + After this call, this pointer will available (and not in use). + + \par + We must either be in sequential (not parallel) execution mode, + or the current thread must be the same as for the corresponding call + to get_memory. + */ + static void return_memory(void* v_ptr) + { size_t num_cap = capacity_info()->number; + + block_t* node = reinterpret_cast(v_ptr) - 1; + size_t tc_index = node->tc_index_; + size_t thread = tc_index / num_cap; + size_t c_index = tc_index % num_cap; + size_t capacity = capacity_info()->value[c_index]; + + CPPAD_ASSERT_UNKNOWN( thread < CPPAD_MAX_NUM_THREADS ); + CPPAD_ASSERT_KNOWN( + thread == thread_num() || (! in_parallel()), + "Attempt to return memory for a different thread " + "while in parallel mode" + ); + + thread_alloc_info* info = thread_info(thread); +# ifndef NDEBUG +# ifndef CPPAD_DEBUG_AND_RELEASE + // remove node from inuse list + void* v_node = reinterpret_cast(node); + block_t* inuse_root = info->root_inuse_ + c_index; + block_t* previous = inuse_root; + while( (previous->next_ != nullptr) & (previous->next_ != v_node) ) + previous = reinterpret_cast(previous->next_); + + // check that v_ptr is valid + if( previous->next_ != v_node ) + { using std::endl; + std::ostringstream oss; + oss << "return_memory: attempt to return memory not in use"; + oss << endl; + oss << "v_ptr = " << v_ptr << endl; + oss << "thread = " << thread << endl; + oss << "capacity = " << capacity << endl; + oss << "See CPPAD_TRACE_THREAD & CPPAD_TRACE_CAPACITY in"; + oss << endl << "# include " << endl; + // oss.str() returns a string object with a copy of the current + // contents in the stream buffer. + std::string msg_str = oss.str(); + // msg_str.c_str() returns a pointer to the c-string + // representation of the string object's value. + const char* msg_char_star = msg_str.c_str(); + CPPAD_ASSERT_KNOWN(false, msg_char_star ); + } + // remove v_ptr from inuse list + previous->next_ = node->next_; +# endif + // trace option + if( capacity==CPPAD_TRACE_CAPACITY && thread==CPPAD_TRACE_THREAD ) + { std::cout << "return_memory: v_ptr = " << v_ptr << std::endl; } + +# endif + // capacity bytes are removed from the inuse pool + dec_inuse(capacity, thread); + + // check for case where we just return the memory to the system + if( ! set_get_hold_memory(false) ) + { ::operator delete( reinterpret_cast(node) ); + return; + } + + // add this node to available list for this thread and capacity + block_t* available_root = info->root_available_ + c_index; + node->next_ = available_root->next_; + available_root->next_ = reinterpret_cast(node); + + // capacity bytes are added to the available pool + inc_available(capacity, thread); + } +/* ----------------------------------------------------------------------- +$begin ta_free_available$$ +$spell + num + thread_alloc +$$ + +$section Free Memory Currently Available for Quick Use by a Thread$$ +$spell + inuse +$$ + + +$head Syntax$$ +$codei%thread_alloc::free_available(%thread%)%$$ + +$head Purpose$$ +Return to the system all the memory that is currently being +$cref/held/ta_hold_memory/$$ for quick use by the specified thread. + +$subhead Extra Memory$$ +In the case where $icode%thread% > 0%$$, +some extra memory is used to track allocations by the specified thread. +If +$codei% + thread_alloc::inuse(%thread%) == 0 +%$$ +the extra memory is also returned to the system. + +$head thread$$ +This argument has prototype +$codei% + size_t %thread% +%$$ +Either $cref/thread_num/ta_thread_num/$$ must be the same as $icode thread$$, +or the current execution mode must be sequential +(not $cref/parallel/ta_in_parallel/$$). + +$head Example$$ +$cref thread_alloc.cpp$$ + +$end +*/ + /*! + Return all the memory being held as available for a thread to the system. + + \param thread [in] + this thread that will no longer have any available memory after this call. + This must either be the thread currently executing, or we must be + in sequential (not parallel) execution mode. + */ + static void free_available(size_t thread) + { CPPAD_ASSERT_KNOWN( + thread < CPPAD_MAX_NUM_THREADS, + "Attempt to free memory for a thread >= CPPAD_MAX_NUM_THREADS" + ); + CPPAD_ASSERT_KNOWN( + thread == thread_num() || (! in_parallel()), + "Attempt to free memory for a different thread " + "while in parallel mode" + ); + + size_t num_cap = capacity_info()->number; + if( num_cap == 0 ) + return; + const size_t* capacity_vec = capacity_info()->value; + size_t c_index; + thread_alloc_info* info = thread_info(thread); + for(c_index = 0; c_index < num_cap; c_index++) + { size_t capacity = capacity_vec[c_index]; + block_t* available_root = info->root_available_ + c_index; + void* v_ptr = available_root->next_; + while( v_ptr != nullptr ) + { block_t* node = reinterpret_cast(v_ptr); + void* next = node->next_; + ::operator delete(v_ptr); + v_ptr = next; + + dec_available(capacity, thread); + } + available_root->next_ = nullptr; + } + CPPAD_ASSERT_UNKNOWN( available(thread) == 0 ); + if( inuse(thread) == 0 ) + { // clear the information for this thread + thread_info(thread, true); + } + } +/* ----------------------------------------------------------------------- +$begin ta_hold_memory$$ +$spell + alloc + num +$$ + +$section Control When Thread Alloc Retains Memory For Future Use$$ + +$head Syntax$$ +$codei%thread_alloc::hold_memory(%value%)%$$ + +$head Purpose$$ +It should be faster, even when $icode num_thread$$ is equal to one, +for $code thread_alloc$$ to hold onto memory. +Calling $icode hold_memory$$ with $icode value$$ equal to true, +instructs $code thread_alloc$$ to hold onto memory, +and put it in the $cref/available/ta_available/$$ pool, +after each call to $cref/return_memory/ta_return_memory/$$. + +$head value$$ +If $icode value$$ is true, +$code thread_alloc$$ with hold onto memory for future quick use. +If it is false, future calls to $cref/return_memory/ta_return_memory/$$ +will return the corresponding memory to the system. +By default (when $code hold_memory$$ has not been called) +$code thread_alloc$$ does not hold onto memory. + +$head free_available$$ +Memory that is being held by $code thread_alloc$$ can be returned +to the system using $cref/free_available/ta_free_available/$$. + +$end +*/ + /*! + Change the thread_alloc hold memory setting. + + \param value [in] + New value for the thread_alloc hold memory setting. + */ + static void hold_memory(bool value) + { bool set = true; + set_get_hold_memory(set, value); + } + +/* ----------------------------------------------------------------------- +$begin ta_inuse$$ +$spell + num + inuse + thread_alloc +$$ + +$section Amount of Memory a Thread is Currently Using$$ + + +$head Syntax$$ +$icode%num_bytes% = thread_alloc::inuse(%thread%)%$$ + +$head Purpose$$ +Memory being managed by $cref thread_alloc$$ has two states, +currently in use by the specified thread, +and quickly available for future use by the specified thread. +This function informs the program how much memory is in use. + +$head thread$$ +This argument has prototype +$codei% + size_t %thread% +%$$ +Either $cref/thread_num/ta_thread_num/$$ must be the same as $icode thread$$, +or the current execution mode must be sequential +(not $cref/parallel/ta_in_parallel/$$). + +$head num_bytes$$ +The return value has prototype +$codei% + size_t %num_bytes% +%$$ +It is the number of bytes currently in use by the specified thread. + +$head Example$$ +$cref thread_alloc.cpp$$ + +$end +*/ + /*! + Determine the amount of memory that is currently inuse. + + \param thread [in] + Thread for which we are determining the amount of memory + (must be < CPPAD_MAX_NUM_THREADS). + Durring parallel execution, this must be the thread + that is currently executing. + + \return + The amount of memory in bytes. + */ + static size_t inuse(size_t thread) + { + CPPAD_ASSERT_UNKNOWN( thread < CPPAD_MAX_NUM_THREADS); + CPPAD_ASSERT_UNKNOWN( + thread == thread_num() || (! in_parallel()) + ); + thread_alloc_info* info = thread_info(thread); + return info->count_inuse_; + } +/* ----------------------------------------------------------------------- +$begin ta_available$$ +$spell + num + thread_alloc +$$ + +$section Amount of Memory Available for Quick Use by a Thread$$ + + +$head Syntax$$ +$icode%num_bytes% = thread_alloc::available(%thread%)%$$ + +$head Purpose$$ +Memory being managed by $cref thread_alloc$$ has two states, +currently in use by the specified thread, +and quickly available for future use by the specified thread. +This function informs the program how much memory is available. + +$head thread$$ +This argument has prototype +$codei% + size_t %thread% +%$$ +Either $cref/thread_num/ta_thread_num/$$ must be the same as $icode thread$$, +or the current execution mode must be sequential +(not $cref/parallel/ta_in_parallel/$$). + +$head num_bytes$$ +The return value has prototype +$codei% + size_t %num_bytes% +%$$ +It is the number of bytes currently available for use by the specified thread. + +$head Example$$ +$cref thread_alloc.cpp$$ + +$end +*/ + /*! + Determine the amount of memory that is currently available for use. + + \copydetails inuse + */ + static size_t available(size_t thread) + { + CPPAD_ASSERT_UNKNOWN( thread < CPPAD_MAX_NUM_THREADS); + CPPAD_ASSERT_UNKNOWN( + thread == thread_num() || (! in_parallel()) + ); + thread_alloc_info* info = thread_info(thread); + return info->count_available_; + } +/* ----------------------------------------------------------------------- +$begin ta_create_array$$ +$spell + inuse + thread_alloc + sizeof +$$ + +$section Allocate An Array and Call Default Constructor for its Elements$$ + + +$head Syntax$$ +$icode%array% = thread_alloc::create_array<%Type%>(%size_min%, %size_out%)%$$. + +$head Purpose$$ +Create a new raw array using $cref thread_alloc$$ memory allocator +(works well in a multi-threading environment) +and call default constructor for each element. + +$head Type$$ +The type of the elements of the array. + +$head size_min$$ +This argument has prototype +$codei% + size_t %size_min% +%$$ +This is the minimum number of elements that there can be +in the resulting $icode array$$. + +$head size_out$$ +This argument has prototype +$codei% + size_t& %size_out% +%$$ +The input value of this argument does not matter. +Upon return, it is the actual number of elements +in $icode array$$ +($icode% size_min %<=% size_out%$$). + +$head array$$ +The return value $icode array$$ has prototype +$codei% + %Type%* %array% +%$$ +It is array with $icode size_out$$ elements. +The default constructor for $icode Type$$ is used to initialize the +elements of $icode array$$. +Note that $cref/delete_array/ta_delete_array/$$ +should be used to destroy the array when it is no longer needed. + +$head Delta$$ +The amount of memory $cref/inuse/ta_inuse/$$ by the current thread, +will increase $icode delta$$ where +$codei% + sizeof(%Type%) * (%size_out% + 1) > %delta% >= sizeof(%Type%) * %size_out% +%$$ +The $cref/available/ta_available/$$ memory will decrease by $icode delta$$, +(and the allocation will be faster) +if a previous allocation with $icode size_min$$ between its current value +and $icode size_out$$ is available. + +$head Alignment$$ +We call a memory allocation aligned if the address is a multiple +of the number of bytes in a $code size_t$$ value. +If the system $code new$$ allocator is aligned, then $icode array$$ +pointer is also aligned. + +$head Example$$ +$cref thread_alloc.cpp$$ + +$end +*/ + /*! + Use thread_alloc to allocate an array, then call default construtor + for each element. + + \tparam Type + The type of the elements of the array. + + \param size_min [in] + The minimum number of elements in the array. + + \param size_out [out] + The actual number of elements in the array. + + \return + pointer to the first element of the array. + The default constructor is used to initialize + all the elements of the array. + + \par + The extra_ field, in the thread_alloc node before the return value, + is set to size_out. + */ + template + static Type* create_array(size_t size_min, size_t& size_out) + { // minimum number of bytes to allocate + size_t min_bytes = size_min * sizeof(Type); + // do the allocation + size_t num_bytes; + void* v_ptr = get_memory(min_bytes, num_bytes); + // This is where the array starts + Type* array = reinterpret_cast(v_ptr); + // number of Type values in the allocation + size_out = num_bytes / sizeof(Type); + // store this number in the extra field + block_t* node = reinterpret_cast(v_ptr) - 1; + node->extra_ = size_out; + + // call default constructor for each element + size_t i; + for(i = 0; i < size_out; i++) + new(array + i) Type(); + + return array; + } +/* ----------------------------------------------------------------------- +$begin ta_delete_array$$ +$spell + inuse + thread_alloc + sizeof + deallocate +$$ + +$section Deallocate An Array and Call Destructor for its Elements$$ + + +$head Syntax$$ +$codei%thread_alloc::delete_array(%array%)%$$. + +$head Purpose$$ +Returns memory corresponding to an array created by +(create by $cref/create_array/ta_create_array/$$) to the +$cref/available/ta_available/$$ memory pool for the current thread. + +$head Type$$ +The type of the elements of the array. + +$head array$$ +The argument $icode array$$ has prototype +$codei% + %Type%* %array% +%$$ +It is a value returned by $cref/create_array/ta_create_array/$$ and not yet deleted. +The $icode Type$$ destructor is called for each element in the array. + +$head Thread$$ +The $cref/current thread/ta_thread_num/$$ must be the +same as when $cref/create_array/ta_create_array/$$ returned the value $icode array$$. +There is an exception to this rule: +when the current execution mode is sequential +(not $cref/parallel/ta_in_parallel/$$) the current thread number does not matter. + +$head Delta$$ +The amount of memory $cref/inuse/ta_inuse/$$ will decrease by $icode delta$$, +and the $cref/available/ta_available/$$ memory will increase by $icode delta$$, +where $cref/delta/ta_create_array/Delta/$$ +is the same as for the corresponding call to $code create_array$$. + +$head Example$$ +$cref thread_alloc.cpp$$ + +$end +*/ + /*! + Return Memory Used for an Array to the Available Pool + (include destructor call for each element). + + \tparam Type + The type of the elements of the array. + + \param array [in] + A value returned by create_array that has not yet been deleted. + The Type destructor is used to destroy each of the elements + of the array. + + \par + Durring parallel execution, the current thread must be the same + as during the corresponding call to create_array. + */ + template + static void delete_array(Type* array) + { // determine the number of values in the array + block_t* node = reinterpret_cast(array) - 1; + size_t size = node->extra_; + + // call destructor for each element + size_t i; + for(i = 0; i < size; i++) + (array + i)->~Type(); + + // return the memory to the available pool for this thread + thread_alloc::return_memory( reinterpret_cast(array) ); + } +/* ----------------------------------------------------------------------- +$begin ta_free_all$$ +$spell + alloc + bool + inuse +$$ + +$section Free All Memory That Was Allocated for Use by thread_alloc$$ + + +$head Syntax$$ +$icode%ok% = thread_alloc::free_all()%$$. + +$head Purpose$$ +Returns all memory that was used by $code thread_alloc$$ to the system. + +$head ok$$ +The return value $icode ok$$ has prototype +$codei% + bool %ok% +%$$ +Its value will be $code true$$ if all the memory can be freed. +This requires that for all $icode thread$$ indices, there is no memory +$cref/inuse/ta_inuse/$$; i.e., +$codei% + 0 == thread_alloc::inuse(%thread%) +%$$ +Otherwise, the return value will be false. + +$head Restrictions$$ +This function cannot be called while in parallel mode. + +$head Example$$ +$cref thread_alloc.cpp$$ +$end +*/ + /*! + Return to the system all thread_alloc memory that is not currently inuse. + + \return + If no thread_alloc memory is currently inuse, + all memory is returned to the system and the return value is true. + Otherwise the return value is false. + */ + static bool free_all(void) + { CPPAD_ASSERT_KNOWN( + ! in_parallel(), + "free_all cannot be used while in parallel execution" + ); + bool ok = true; + size_t thread = CPPAD_MAX_NUM_THREADS; + while(thread--) + { ok &= inuse(thread) == 0; + free_available(thread); + } + return ok; + } +}; + + +} // END_CPPAD_NAMESPACE + +// preprocessor symbols local to this file +# undef CPPAD_MAX_NUM_CAPACITY +# undef CPPAD_MIN_DOUBLE_CAPACITY +# undef CPPAD_TRACE_CAPACITY +# undef CPPAD_TRACE_THREAD +# endif diff --git a/build-config/cppad/include/cppad/utility/time_test.hpp b/build-config/cppad/include/cppad/utility/time_test.hpp new file mode 100644 index 00000000..8a3c1d16 --- /dev/null +++ b/build-config/cppad/include/cppad/utility/time_test.hpp @@ -0,0 +1,300 @@ +# ifndef CPPAD_UTILITY_TIME_TEST_HPP +# define CPPAD_UTILITY_TIME_TEST_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +/* +$begin time_test$$ +$spell + gettimeofday + vec + cppad.hpp + Microsoft + namespace + std + const + cout + ctime + ifdef + const + endif + cpp +$$ + + +$section Determine Amount of Time to Execute a Test$$ + +$head Syntax$$ +$codei%# include +%$$ +$icode%time% = time_test(%test%, %time_min%) +%$$ +$icode%time% = time_test(%test%, %time_min%, %test_size%) +%$$ +$icode%time% = time_test(%test%, %time_min%, %test_size%, %repeat_out%) +%$$ + +$head Purpose$$ +The $code time_test$$ function executes a timing test +and reports the amount of wall clock time for execution. + +$head Motivation$$ +It is important to separate small calculation units +and test them individually. +This way individual changes can be tested in the context of the +routine that they are in. +On many machines, accurate timing of a very short execution +sequences is not possible. +In addition, +there may be set up and tear down time for a test that +we do not really want included in the timing. +For this reason $code time_test$$ +automatically determines how many times to +repeat the section of the test that we wish to time. + +$head Include$$ +The file $code cppad/utility/time_test.hpp$$ defines the +$code time_test$$ function. +This file is included by $code cppad/cppad.hpp$$ +and it can also be included separately with out the rest of +the $code CppAD$$ routines. + +$head test$$ +The $code time_test$$ argument $icode test$$ is a function, +or function object. +In the case where $icode test_size$$ is not present, +$icode test$$ supports the syntax +$codei% + %test%(%repeat%) +%$$ +In the case where $icode test_size$$ is present, +$icode test$$ supports the syntax +$codei% + %test%(%size%, %repeat%) +%$$ +In either case, the return value for $icode test$$ is $code void$$. + +$subhead size$$ +If the argument $icode size$$ is present, +it has prototype +$codei% + size_t %size% +%$$ +and is equal to the $icode test_size$$ argument to $code time_test$$. + +$subhead repeat$$ +The $icode test$$ argument $icode repeat$$ has prototype +$codei% + size_t %repeat% +%$$ +It specifies the number of times to repeat the test. + +$head time_min$$ +The argument $icode time_min$$ has prototype +$codei% + double %time_min% +%$$ +It specifies the minimum amount of time in seconds +that the $icode test$$ routine should take. +The $icode repeat$$ argument to $icode test$$ is increased +until this amount of execution time (or more) is reached. + +$head test_size$$ +If this argument is present, it argument has prototype +$codei% + size_t %test_size% +%$$ +In this case $icode test_size$$ will be present, and have the same value, +in each call to $icode test$$. + +$head repeat_out$$ +If this argument is present, it has prototype +$codei% + size_t& %repeat_out% +%$$ +This input value of this argument does not matter. +Upon return, it is the value of $cref/repeat/time_test/test/repeat/$$ +that corresponds to the return value $icode time$$; i.e., +the actual total time of the test is +$codei% + %total_time% = %repeat% * %time% +%$$ + +$head time$$ +The return value $icode time$$ has prototype +$codei% + double %time% +%$$ +and is the number of wall clock seconds that it took +to execute $icode test$$ divided by the value used for $icode repeat$$. + +$head Timing$$ +The routine $cref elapsed_seconds$$ will be used to determine the +amount of time it took to execute the test. + +$children% + include/cppad/utility/elapsed_seconds.hpp% + speed/example/time_test.cpp +%$$ +$head Example$$ +The routine $cref time_test.cpp$$ is an example and test +of $code time_test$$. + +$end +----------------------------------------------------------------------- +*/ + +# include +# include +# include +# include +# include + +# define CPPAD_EXTRA_RUN_BEFORE_TIMING 0 + +namespace CppAD { // BEGIN_CPPAD_NAMESPACE +/*! +\file time_test.hpp +\brief Function that preforms one timing test (for speed of execution). +*/ + +/*! +Preform one wall clock execution timing test. + +\tparam Test +Either the type void (*)(size_t) +or a function object type that supports the same syntax. + +\param test +The function, or function object, that supports the operation +test(repeat) where repeat is the number of times +to repeat the tests operaiton that is being timed. + +\param time_min +is the minimum amount of time that test should take to preform +the repetitions of the operation being timed. + +\return +is the time for each execution of the test. +*/ +template +double time_test(Test test, double time_min ) +{ +# if CPPAD_EXTRA_RUN_BEFORE_TIMING + test(1); +# endif + size_t repeat = 0; + double s0 = elapsed_seconds(); + double s1 = s0; + while( s1 - s0 < time_min ) + { repeat = std::max(size_t(1), 2 * repeat); + s0 = elapsed_seconds(); + test(repeat); + s1 = elapsed_seconds(); + } + double time = (s1 - s0) / double(repeat); + return time; +} +/*! +Preform one wall clock execution timing test. + +\tparam Test +Either the type void (*)(size_t, size_t) +or a function object type that supports the same syntax. + +\param test +The function, or function object, that supports the operation +test(size, repeat) where size +is the size for this test and repeat is the number of times +to repeat the tests operaiton that is being timed. + +\param time_min +is the minimum amount of time that test should take to preform +the repetitions of the operation being timed. + +\param test_size +will be used for the value of size in the call to test. + +\return +is the time for each execution of the test. +*/ +template +double time_test(Test test, double time_min, size_t test_size) +{ +# if CPPAD_EXTRA_RUN_BEFORE_TIMING + test(test_size, 1); +# endif + size_t repeat = 0; + double s0 = elapsed_seconds(); + double s1 = s0; + while( s1 - s0 < time_min ) + { repeat = std::max(size_t(1), 2 * repeat); + s0 = elapsed_seconds(); + test(test_size, repeat); + s1 = elapsed_seconds(); + } + double time = (s1 - s0) / double(repeat); + return time; +} +/*! +Preform one wall clock execution timing test. + +\tparam Test +Either the type void (*)(size_t, size_t) +or a function object type that supports the same syntax. + +\param test +The function, or function object, that supports the operation +test(size, repeat) where size +is the size for this test and repeat is the number of times +to repeat the tests operaiton that is being timed. + +\param time_min +is the minimum amount of time that test should take to preform +the repetitions of the operation being timed. + +\param test_size +will be used for the value of size in the call to test. + +\param repeat_out +the return value is the number of times the test was repeated; +i.e., the return value is the total time divided by repeat. + +\return +is the time for each execution of the test. +*/ +template +double time_test( + Test test, double time_min, size_t test_size, size_t& repeat_out +) +{ +# if CPPAD_EXTRA_RUN_BEFORE_TIMING + test(test_size, 1); +# endif + repeat_out = 0; + double s0 = elapsed_seconds(); + double s1 = s0; + while( s1 - s0 < time_min ) + { repeat_out = std::max(size_t(1), 2 * repeat_out); + s0 = elapsed_seconds(); + test(test_size, repeat_out); + s1 = elapsed_seconds(); + } + double time = (s1 - s0) / double(repeat_out); + return time; +} + +} // END_CPPAD_NAMESPACE + +# undef CPPAD_EXTRA_RUN_BEFORE_TIMING +// END PROGRAM +# endif diff --git a/build-config/cppad/include/cppad/utility/to_string.hpp b/build-config/cppad/include/cppad/utility/to_string.hpp new file mode 100644 index 00000000..8df0865c --- /dev/null +++ b/build-config/cppad/include/cppad/utility/to_string.hpp @@ -0,0 +1,172 @@ +# ifndef CPPAD_UTILITY_TO_STRING_HPP +# define CPPAD_UTILITY_TO_STRING_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +/* +$begin to_string$$ +$spell + cppad.hpp + long long + std + const + ostringstream +$$ + +$section Convert Certain Types to a String$$ + +$head Syntax$$ +$codei%# include +%$$ +$icode%s% = to_string(%value%)%$$. + +$head See Also$$ +$cref base_to_string$$, $cref ad_to_string$$ + +$head Purpose$$ +This routine is similar to the C++11 routine $code std::to_string$$ +with the following differences: +$list number$$ +It works with C++98. +$lnext +It has been extended to the fundamental floating point types. +$lnext +It has specifications for extending to an arbitrary type; see +$cref base_to_string$$. +$lnext +If $code $$ is included, +and it has been extended to a $icode Base$$ type, +it automatically extends to the +$cref/AD types above Base/glossary/AD Type Above Base/$$. +$lnext +For integer types, conversion to a string is exact. +For floating point types, conversion to a string yields a value +that has relative error within machine epsilon. +$lend + +$head value$$ + +$subhead Integer$$ +The argument $icode value$$ can have the following prototype +$codei% + const %Integer%& %value% +%$$ +where $icode Integer$$ is any of the fundamental integer types; e.g., +$code short int$$ and $code unsigned long$$. +Note that if C++11 is supported by this compilation, +$code unsigned long long$$ is also a fundamental integer type. + +$subhead Float$$ +The argument $icode value$$ can have the following prototype +$codei% + const %Float%& %value% +%$$ +where $icode Float$$ is any of the fundamental floating point types; i.e., +$code float$$, $code double$$, and $code long double$$. + +$head s$$ +The return value has prototype +$codei% + std::string %s% +%$$ +and contains a representation of the specified $icode value$$. + +$subhead Integer$$ +If $icode value$$ is an $codei Integer$$, +the representation is equivalent to $codei%os% << %value%$$ +where $icode os$$ is an $code std::ostringstream$$. + +$subhead Float$$ +If $icode value$$ is a $codei Float$$, +enough digits are used in the representation so that +the result is accurate to withing round off error. + +$children% + example/utility/to_string.cpp +%$$ +$head Example$$ +The file $cref to_string.cpp$$ +contains an example and test of this routine. + +$end +*/ +# include +# include +# include +# include +# include + +# define CPPAD_SPECIALIZE_TO_STRING_INTEGER(Type) \ +template <> struct to_string_struct\ +{ std::string operator()(const Type& value) \ + { std::stringstream os;\ + os << value;\ + return os.str();\ + }\ +}; + +# define CPPAD_SPECIALIZE_TO_STRING_FLOAT(Float) \ +template <> struct to_string_struct\ +{ std::string operator()(const Float& value) \ + { std::stringstream os;\ + int n_digits = 1 + std::numeric_limits::digits10;\ + os << std::setprecision(n_digits);\ + os << value;\ + return os.str();\ + }\ +}; + +namespace CppAD { + + // Default implementation, + // each type must define its own specilization. + template + struct to_string_struct + { std::string operator()(const Type& value) + { CPPAD_ASSERT_KNOWN( + false, + "to_string is not implemented for this type" + ); + // return empty string + return std::string(""); + } + }; + + // specialization for the fundamental integer types + CPPAD_SPECIALIZE_TO_STRING_INTEGER(signed short) + CPPAD_SPECIALIZE_TO_STRING_INTEGER(unsigned short) + // + CPPAD_SPECIALIZE_TO_STRING_INTEGER(signed int) + CPPAD_SPECIALIZE_TO_STRING_INTEGER(unsigned int) + // + CPPAD_SPECIALIZE_TO_STRING_INTEGER(signed long) + CPPAD_SPECIALIZE_TO_STRING_INTEGER(unsigned long) + // + CPPAD_SPECIALIZE_TO_STRING_INTEGER(signed long long) + CPPAD_SPECIALIZE_TO_STRING_INTEGER(unsigned long long) + + // specialization for the fundamental floating point types + CPPAD_SPECIALIZE_TO_STRING_FLOAT(float) + CPPAD_SPECIALIZE_TO_STRING_FLOAT(double) + CPPAD_SPECIALIZE_TO_STRING_FLOAT(long double) + + // link from function to function object in structure + template + std::string to_string(const Type& value) + { to_string_struct to_str; + return to_str(value); + } +} + +# undef CPPAD_SPECIALIZE_TO_STRING_FLOAT +# undef CPPAD_SPECIALIZE_TO_STRING_INTEGER +# endif diff --git a/build-config/cppad/include/cppad/utility/track_new_del.hpp b/build-config/cppad/include/cppad/utility/track_new_del.hpp new file mode 100644 index 00000000..143ba32a --- /dev/null +++ b/build-config/cppad/include/cppad/utility/track_new_del.hpp @@ -0,0 +1,533 @@ +# ifndef CPPAD_UTILITY_TRACK_NEW_DEL_HPP +# define CPPAD_UTILITY_TRACK_NEW_DEL_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ +/* +$begin TrackNewDel$$ +$spell + cppad.hpp + Cpp + newptr + Vec + oldptr + newlen + ncopy + const +$$ + +$section Routines That Track Use of New and Delete$$ + +$head Deprecated 2007-07-23$$ +All these routines have been deprecated. +You should use the $cref thread_alloc$$ memory allocator instead +(which works better in both a single thread and +properly in multi-threading environment). + +$head Syntax$$ +$codei%# include +%$$ +$icode%newptr% = TrackNewVec(%file%, %line%, %newlen%, %oldptr%) +%$$ +$codei%TrackDelVec(%file%, %line%, %oldptr%) +%$$ +$icode%newptr% = TrackExtend(%file%, %line%, %newlen%, %ncopy%, %oldptr%) +%$$ +$icode%count% = TrackCount(%file%, %line%)%$$ + + +$head Purpose$$ +These routines +aid in the use of $code new[]$$ and $code delete[]$$ +during the execution of a C++ program. + +$head Include$$ +The file $code cppad/utility/track_new_del.hpp$$ is included by +$code cppad/cppad.hpp$$ +but it can also be included separately with out the rest of the +CppAD include files. + + +$head file$$ +The argument $icode file$$ has prototype +$codei% + const char *%file% +%$$ +It should be the source code file name +where the call to $code TrackNew$$ is located. +The best way to accomplish this is the use the preprocessor symbol +$code __FILE__$$ for this argument. + +$head line$$ +The argument $icode line$$ has prototype +$codei% + int %line% +%$$ +It should be the source code file line number +where the call to $code TrackNew$$ is located. +The best way to accomplish this is the use the preprocessor symbol +$code __LINE__$$ for this argument. + +$head oldptr$$ +The argument $icode oldptr$$ has prototype +$codei% + %Type% *%oldptr% +%$$ +This argument is used to identify the type $icode Type$$. + +$head newlen$$ +The argument $icode newlen$$ has prototype +$codei% + size_t %newlen% +%$$ + +$head head newptr$$ +The return value $icode newptr$$ has prototype +$codei% + %Type% *%newptr% +%$$ +It points to the newly allocated vector of objects +that were allocated using +$codei% + new Type[%newlen%] +%$$ + +$head ncopy$$ +The argument $icode ncopy$$ has prototype +$codei% + size_t %ncopy% +%$$ +This specifies the number of elements that are copied from +the old array to the new array. +The value of $icode ncopy$$ +must be less than or equal $icode newlen$$. + +$head TrackNewVec$$ +If $code NDEBUG$$ is defined, this routine only sets +$codei% + %newptr% = %Type% new[%newlen%] +%$$ +The value of $icode oldptr$$ does not matter +(except that it is used to identify $icode Type$$). +If $code NDEBUG$$ is not defined, $code TrackNewVec$$ also +tracks the this memory allocation. +In this case, if memory cannot be allocated +$cref ErrorHandler$$ is used to generate a message +stating that there was not sufficient memory. + +$subhead Macro$$ +The preprocessor macro call +$codei% + CPPAD_TRACK_NEW_VEC(%newlen%, %oldptr%) +%$$ +expands to +$codei% + CppAD::TrackNewVec(__FILE__, __LINE__, %newlen%, %oldptr%) +%$$ + +$subhead Previously Deprecated$$ +The preprocessor macro $code CppADTrackNewVec$$ is the +same as $code CPPAD_TRACK_NEW_VEC$$ and was previously deprecated. + +$head TrackDelVec$$ +This routine is used to a vector of objects +that have been allocated using $code TrackNew$$ or $code TrackExtend$$. +If $code NDEBUG$$ is defined, this routine only frees memory with +$codei% + delete [] %oldptr% +%$$ +If $code NDEBUG$$ is not defined, $code TrackDelete$$ also checks that +$icode oldptr$$ was allocated by $code TrackNew$$ or $code TrackExtend$$ +and has not yet been freed. +If this is not the case, +$cref ErrorHandler$$ is used to generate an error message. + +$subhead Macro$$ +The preprocessor macro call +$codei% + CPPAD_TRACK_DEL_VEC(%oldptr%) +%$$ +expands to +$codei% + CppAD::TrackDelVec(__FILE__, __LINE__, %oldptr%) +%$$ + +$subhead Previously Deprecated$$ +The preprocessor macro $code CppADTrackDelVec$$ is the +same as $code CPPAD_TRACK_DEL_VEC$$ was previously deprecated. + +$head TrackExtend$$ +This routine is used to +allocate a new vector (using $code TrackNewVec$$), +copy $icode ncopy$$ elements from the old vector to the new vector. +If $icode ncopy$$ is greater than zero, $icode oldptr$$ +must have been allocated using $code TrackNewVec$$ or $code TrackExtend$$. +In this case, the vector pointed to by $icode oldptr$$ +must be have at least $icode ncopy$$ elements +and it will be deleted (using $code TrackDelVec$$). +Note that the dependence of $code TrackExtend$$ on $code NDEBUG$$ +is indirectly through the routines $code TrackNewVec$$ and +$code TrackDelVec$$. + +$subhead Macro$$ +The preprocessor macro call +$codei% + CPPAD_TRACK_EXTEND(%newlen%, %ncopy%, %oldptr%) +%$$ +expands to +$codei% + CppAD::TrackExtend(__FILE__, __LINE__, %newlen%, %ncopy%, %oldptr%) +%$$ + +$subhead Previously Deprecated$$ +The preprocessor macro $code CppADTrackExtend$$ is the +same as $code CPPAD_TRACK_EXTEND$$ and was previously deprecated. + +$head TrackCount$$ +The return value $icode count$$ has prototype +$codei% + size_t %count% +%$$ +If $code NDEBUG$$ is defined, $icode count$$ will be zero. +Otherwise, it will be +the number of vectors that +have been allocated +(by $code TrackNewVec$$ or $code TrackExtend$$) +and not yet freed +(by $code TrackDelete$$). + +$subhead Macro$$ +The preprocessor macro call +$codei% + CPPAD_TRACK_COUNT() +%$$ +expands to +$codei% + CppAD::TrackCount(__FILE__, __LINE__) +%$$ + +$subhead Previously Deprecated$$ +The preprocessor macro $code CppADTrackCount$$ is the +same as $code CPPAD_TRACK_COUNT$$ and was previously deprecated. + +$head Multi-Threading$$ +These routines cannot be used $cref/in_parallel/ta_in_parallel/$$ +execution mode. +Use the $cref thread_alloc$$ routines instead. + +$end +------------------------------------------------------------------------------ +*/ +# include +# include +# include +# include +# include + +# ifndef CPPAD_TRACK_DEBUG +# define CPPAD_TRACK_DEBUG 0 +# endif + +// ------------------------------------------------------------------------- +# define CPPAD_TRACK_NEW_VEC(newlen, oldptr) \ + CppAD::TrackNewVec(__FILE__, __LINE__, newlen, oldptr) + +# define CPPAD_TRACK_DEL_VEC(oldptr) \ + CppAD::TrackDelVec(__FILE__, __LINE__, oldptr) + +# define CPPAD_TRACK_EXTEND(newlen, ncopy, oldptr) \ + CppAD::TrackExtend(__FILE__, __LINE__, newlen, ncopy, oldptr) + +# define CPPAD_TRACK_COUNT() \ + CppAD::TrackCount(__FILE__, __LINE__) +// ------------------------------------------------------------------------- +# define CppADTrackNewVec CPPAD_TRACK_NEW_VEC +# define CppADTrackDelVec CPPAD_TRACK_DEL_VEC +# define CppADTrackExtend CPPAD_TRACK_EXTEND +# define CppADTrackCount CPPAD_TRACK_COUNT +// ------------------------------------------------------------------------- +namespace CppAD { // Begin CppAD namespace + +// TrackElement ------------------------------------------------------------ +class TrackElement { + +public: + std::string file; // corresponding file name + int line; // corresponding line number + void *ptr; // value returned by TrackNew + TrackElement *next; // next element in linked list + + // default contructor (used to initialize root) + TrackElement(void) + : file(""), line(0), ptr(nullptr), next(nullptr) + { } + + TrackElement(const char *f, int l, void *p) + : file(f), line(l), ptr(p), next(nullptr) + { CPPAD_ASSERT_UNKNOWN( p != nullptr); + } + + // There is only one tracking list and it starts it here + static TrackElement *Root(void) + { CPPAD_ASSERT_UNKNOWN( ! thread_alloc::in_parallel() ); + static TrackElement root; + return &root; + } + + // Print one tracking element + static void Print(TrackElement* E) + { + CPPAD_ASSERT_UNKNOWN( ! thread_alloc::in_parallel() ); + using std::cout; + cout << "E = " << E; + cout << ", E->next = " << E->next; + cout << ", E->ptr = " << E->ptr; + cout << ", E->line = " << E->line; + cout << ", E->file = " << E->file; + cout << std::endl; + } + + // Print the linked list for a thread + static void Print(void) + { + CPPAD_ASSERT_UNKNOWN( ! thread_alloc::in_parallel() ); + using std::cout; + using std::endl; + TrackElement *E = Root(); + // convert int(size_t) to avoid warning on _MSC_VER systems + cout << "Begin Track List" << endl; + while( E->next != nullptr ) + { E = E->next; + Print(E); + } + cout << "End Track List:" << endl; + cout << endl; + } +}; + + +// TrackError ---------------------------------------------------------------- +inline void TrackError( + const char *routine, + const char *file, + int line, + const char *msg ) +{ + CPPAD_ASSERT_UNKNOWN( ! thread_alloc::in_parallel() ); + std::ostringstream buf; + buf << routine + << ": at line " + << line + << " in file " + << file + << std::endl + << msg; + std::string str = buf.str(); + size_t n = str.size(); + size_t i; + char *message = new char[n + 1]; + for(i = 0; i < n; i++) + message[i] = str[i]; + message[n] = '\0'; + CPPAD_ASSERT_KNOWN( false , message); +} + +// TrackNewVec --------------------------------------------------------------- +# ifdef NDEBUG +template +Type *TrackNewVec( + const char *file, int line, size_t len, Type * /* oldptr */ ) +{ +# if CPPAD_TRACK_DEBUG + static bool first = true; + if( first ) + { std::cout << "NDEBUG is defined for TrackNewVec" << std::endl; + first = false; + } +# endif + return (new Type[len]); +} + +# else + +template +Type *TrackNewVec( + const char *file , + int line , + size_t len , + Type * /* oldptr */ ) +{ + CPPAD_ASSERT_KNOWN( + ! thread_alloc::in_parallel() , + "attempt to use TrackNewVec in parallel execution mode." + ); + // try to allocate the new memrory + Type *newptr = nullptr; + try + { newptr = new Type[len]; + } + catch(...) + { TrackError("TrackNewVec", file, line, + "Cannot allocate sufficient memory" + ); + } + // create tracking element + void *vptr = static_cast(newptr); + TrackElement *E = new TrackElement(file, line, vptr); + + // get the root + TrackElement *root = TrackElement::Root(); + + // put this elemenent at the front of linked list + E->next = root->next; + root->next = E; + +# if CPPAD_TRACK_DEBUG + std::cout << "TrackNewVec: "; + TrackElement::Print(E); +# endif + + return newptr; +} + +# endif + +// TrackDelVec -------------------------------------------------------------- +# ifdef NDEBUG +template +void TrackDelVec(const char *file, int line, Type *oldptr) +{ +# if CPPAD_TRACK_DEBUG + static bool first = true; + if( first ) + { std::cout << "NDEBUG is defined in TrackDelVec" << std::endl; + first = false; + } +# endif + delete [] oldptr; +} + +# else + +template +void TrackDelVec( + const char *file , + int line , + Type *oldptr ) +{ + CPPAD_ASSERT_KNOWN( + ! thread_alloc::in_parallel() , + "attempt to use TrackDelVec in parallel execution mode." + ); + TrackElement *P; + TrackElement *E; + + // search list for pointer + P = TrackElement::Root(); + E = P->next; + void *vptr = static_cast(oldptr); + while(E != nullptr && E->ptr != vptr) + { P = E; + E = E->next; + } + + // check if pointer was not in list + if( E == nullptr || E->ptr != vptr ) TrackError( + "TrackDelVec", file, line, + "Invalid value for the argument oldptr.\n" + "Possible linking of debug and NDEBUG compilations of CppAD." + ); + +# if CPPAD_TRACK_DEBUG + std::cout << "TrackDelVec: "; + TrackElement::Print(E); +# endif + + // remove tracking element from list + P->next = E->next; + + // delete allocated pointer + delete [] oldptr; + + // delete tracking element + delete E; + + return; +} + +# endif + +// TrackExtend -------------------------------------------------------------- +template +Type *TrackExtend( + const char *file , + int line , + size_t newlen , + size_t ncopy , + Type *oldptr ) +{ + CPPAD_ASSERT_KNOWN( + ! thread_alloc::in_parallel() , + "attempt to use TrackExtend in parallel execution mode." + ); + +# if CPPAD_TRACK_DEBUG + using std::cout; + cout << "TrackExtend: file = " << file; + cout << ", line = " << line; + cout << ", newlen = " << newlen; + cout << ", ncopy = " << ncopy; + cout << ", oldptr = " << oldptr; + cout << std::endl; +# endif + CPPAD_ASSERT_KNOWN( + ncopy <= newlen, + "TrackExtend: ncopy is greater than newlen." + ); + + // allocate the new memrory + Type *newptr = TrackNewVec(file, line, newlen, oldptr); + + // copy the data + size_t i; + for(i = 0; i < ncopy; i++) + newptr[i] = oldptr[i]; + + // delete the old vector + if( ncopy > 0 ) + TrackDelVec(file, line, oldptr); + + return newptr; +} + +// TrackCount -------------------------------------------------------------- +inline size_t TrackCount(const char *file, int line) +{ + CPPAD_ASSERT_KNOWN( + ! thread_alloc::in_parallel() , + "attempt to use TrackCount in parallel execution mode." + ); + size_t count = 0; + TrackElement *E = TrackElement::Root(); + while( E->next != nullptr ) + { ++count; + E = E->next; + } + return count; +} +// --------------------------------------------------------------------------- + +} // End CppAD namespace + +// preprocessor symbols local to this file +# undef CPPAD_TRACK_DEBUG + +# endif diff --git a/build-config/cppad/include/cppad/utility/vector.hpp b/build-config/cppad/include/cppad/utility/vector.hpp new file mode 100644 index 00000000..1b55b1c6 --- /dev/null +++ b/build-config/cppad/include/cppad/utility/vector.hpp @@ -0,0 +1,543 @@ +# ifndef CPPAD_UTILITY_VECTOR_HPP +# define CPPAD_UTILITY_VECTOR_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + + +# include +# include +# include +# include +# include + +// Note that CPPAD_CONST is undefined by cppad_vector_itr.hpp +# define CPPAD_CONST 0 +# include +# undef CPPAD_LOCAL_UTILITY_CPPAD_VECTOR_ITR_HPP +# define CPPAD_CONST 1 +# include + +namespace CppAD { // BEGIN_CPPAD_NAMESPACE + +// ========================================================================== +template class vector { +// ========================================================================== +/* +$begin cppad_vector_member$$ +$spell + vec +$$ + +$section Vector Class: Member Data$$ + +$head Syntax$$ +$icode%vec%.capacity() +%$$ +$icode%vec%.size() +%$$ +$icode%vec%.data() +%$$ + +$head Type$$ +is the type of the elements in the array. + +$head capacity_$$ +Number of $icode Type$$ elements in $code data_$$ that have been allocated +(and constructor has been called). + +$head length_$$ +Number of $icode Type$$ elements currently in this vector. + +$head data_$$ +Pointer to the first element of the vector +(not defined and should not be used when $code capacity_$$ is 0). + +$head Source$$ +$srccode%hpp% */ +private: + size_t capacity_; + size_t length_; + Type* data_; +public: + size_t capacity(void) const noexcept + { return capacity_; } + size_t size(void) const noexcept + { return length_; } + const Type* data(void) const noexcept + { return data_; } + Type* data(void) noexcept + { return data_; } +/* %$$ +$end +----------------------------------------------------------------------------- +$begin cppad_vector_typedef$$ +$spell + const_iterator +$$ + +$section Vector Class: Type Definitions$$ + +$head value_type$$ +type corresponding to an element of a vector. + +$head iterator$$ +type corresponding to an iterator for a vector. + +$head const_iterator$$ +type corresponding to an iterator for a vector when +the vector is $code const$$. + +$srccode%hpp% */ +public: + typedef Type value_type; + typedef local::utility::cppad_vector_itr iterator; + typedef local::utility::const_cppad_vector_itr const_iterator; +/* %$$ +$end +----------------------------------------------------------------------------- +$begin cppad_vector_ctor$$ +$spell + vec +$$ + +$section Vector Class: Constructors and Destructor$$ + +$head Default$$ +$codei%vector<%Type%> %vec% +%$$ +creates an empty vector no elements and capacity zero. + +$head Sizing$$ +$codei%vector<%Type%> %vec%(%n%) +%$$ +where $icode n$$ is a $code size_t$$ or $code int$$, +creates the vector $icode vec$$ with $icode n$$ elements and capacity +greater than or equal $icode n$$. + +$head Copy$$ +$codei%vector<%Type%> %vec%(%other%) +%$$ +where $icode other$$ is a $codei%vector<%Type%>%$$, +creates the vector $icode vec$$ +with $icode%n% = %other%.size()%$$ elements and capacity +greater than or equal $icode n$$. + +$head Move Semantics$$ +A move semantics version of the copy operator +is implemented using $code swap$$. + +$head Destructor$$ +If $code capacity_$$ is non-zero, call the destructor +for all the corresponding elements and then frees the corresponding memory. + +$head delete_data$$ +Call destructor and free all the allocated elements +(there are $code capacity_$$ such elements). + +$head Source$$ +$srccode%hpp% */ +public: + vector(void) noexcept + : capacity_(0), length_(0), data_(nullptr) + { } + vector(size_t n) : capacity_(0), length_(0), data_(nullptr) + { resize(n); } + vector(int n) : capacity_(0), length_(0), data_(nullptr) + { CPPAD_ASSERT_KNOWN( + n >= 0, + "CppAD::vector: attempt to create a vector with a negative size." + ); + resize( size_t(n) ); + } + vector(const vector& other) : capacity_(0), length_(0), data_(nullptr) + { resize(other.length_); + for(size_t i = 0; i < length_; i++) + data_[i] = other.data_[i]; + } + // capacity_ is only value required to make destructor work for other + // after this move semantics constuctor + vector(vector&& other) : capacity_(0), length_(0), data_(nullptr) + { swap(other); } + ~vector(void) + { if( capacity_ > 0 ) delete_data(data_); } +private: + void delete_data(Type* data_ptr) + { thread_alloc::delete_array(data_ptr); } +/* %$$ +$end +----------------------------------------------------------------------------- +$begin cppad_vector_size$$ +$spell + resize + vec +$$ + +$section Vector Class: Change Size$$ + +$head Syntax$$ +$icode%vec%.resize(%n%) +%$$ +$icode%vec%.clear()%$$ + +$head Prototype$$ +$srcthisfile% + 0%// BEGIN_RESIZE%// END_RESIZE%1 +%$$ +$srcthisfile% + 0%// BEGIN_CLEAR%// END_CLEAR%1 +%$$ + +$head n$$ +is the number of elements in the new version of the vector. + +$head resize$$ +If $icode n$$ is less than or equal the input value of +$icode%vec%.capacity_%$$, +the only change is that $icode%vec%.length_%$$ is set to $icode n$$. +Otherwise, new memory is allocated for the vector and +$icode%vec%.length_%$$ elements are copied from the old vector +to the new one. I you do not need the old elements, you can first resize +to zero and then the $icode n$$ to avoid copying the elements. + +$head clear$$ +The destructor is called for all the elements of $icode vec$$ +and then $icode%vec.length_%$$ and $icode%vec%.capacity_%$$ are set to zero. + +$end +------------------------------------------------------------------------------ +*/ +// BEGIN_RESIZE +public: + void resize(size_t n) +// END_RESIZE + { if( capacity_ < n ) + { if( capacity_ == 0 ) + { // get new memory and set capacity + data_ = thread_alloc::create_array(n, capacity_); + } + else + { // save old information + Type* old_data = data_; + + // get new memory and set capacity + data_ = thread_alloc::create_array(n, capacity_); + + // copy old data + for(size_t i = 0; i < length_; ++i) + data_[i] = old_data[i]; + + // free old memory + thread_alloc::delete_array(old_data); + } + } + length_ = n; + } +// BEGIN_CLEAR + void clear(void) +// END_CLEAR + { length_ = 0; + // check if there is old memory to be freed + if( capacity_ > 0 ) + delete_data(data_); + capacity_ = 0; + } +/* +------------------------------------------------------------------------------- +$begin cppad_vector_assign$$ +$spell + resize + vec + cppad +$$ + +$section Vector Class: Assignment Operators$$ + +$head Syntax$$ +$icode%vec%.swap(%other%) +%$$ +$icode%vec% = %other%$$ + +$head Prototype$$ +$srcthisfile% + 0%// BEGIN_SWAP%// END_SWAP%1 +%$$ +$srcthisfile% + 0%// BEGIN_MOVE_ASSIGN%// END_MOVE_ASSIGN%1 +%$$ +$srcthisfile% + 0%// BEGIN_ASSIGN%// END_ASSIGN%1 +%$$ + +$head swap$$ +Swaps $code length_$$, $code capacity_$$ and $code data_$$ +between $icode vec$$ and $icode other$$. + +$head Assignment$$ +see $cref/user API assignment/CppAD_vector/Assignment/$$ + +$head Move Semantics$$ +A move semantics version of the assignment operator +is implemented using $code swap$$. + +$end +------------------------------------------------------------------------------- +*/ +// BEGIN_SWAP +public: + void swap(vector& other) noexcept +// END_SWAP + { // special case where vec and other are the same vector + if( this == &other ) + return; + // + std::swap(length_, other.length_ ); + std::swap(capacity_, other.capacity_ ); + std::swap(data_, other.data_ ); + return; + } + +// BEGIN_MOVE_ASSIGN + // Move semantics should not do any allocation. + // If NDEBUG is defined, this should not throw an exception. + vector& operator=(vector&& other) CPPAD_NDEBUG_NOEXCEPT +// END_MOVE_ASSIGN + { CPPAD_ASSERT_KNOWN( + length_ == other.length_ || (length_ == 0), + "vector: size miss match in assignment operation" + ); + swap(other); + return *this; + } + +// BEGIN_ASSIGN + vector& operator=(const vector& other) +// END_ASSIGN + { if( length_ == 0 ) + resize( other.length_ ); + CPPAD_ASSERT_KNOWN( + length_ == other.length_ , + "vector: size miss match in assignment operation" + ); + for(size_t i = 0; i < length_; i++) + data_[i] = other.data_[i]; + return *this; + } +/* +------------------------------------------------------------------------------- +$begin cppad_vector_subscript$$ +$spell + vec +$$ + +$section Vector Class: Subscript Operator$$ + +$head Syntax$$ +$icode%element% = %vec%[%i%] +%$$ +$icode%vec%[%i%] = %element% +%$$ + +$head Source$$ +$srccode%hpp% */ + const Type& operator[]( size_t i) const + { CPPAD_ASSERT_KNOWN( i < length_, + "vector: index greater than or equal vector size" + ); + return data_[i]; + } + Type& operator[](size_t i) + { CPPAD_ASSERT_KNOWN(i < length_, + "vector: index greater than or equal vector size" + ); + return data_[i]; + } + template const Type& operator[]( Index i) const + { return (*this)[size_t(i)]; } + template Type& operator[](Index i) + { return (*this)[size_t(i)]; } +/* %$$ +$end +------------------------------------------------------------------------------- +$begin cppad_vector_push_back$$ +$spell + vec +$$ + +$section Vector Class: push_back$$ + +$head Syntax$$ +$icode%vec%.push_back(%element%)%$$ + +$head Prototype$$ +$srcthisfile% + 0%// BEGIN_PUSH_BACK%// END_PUSH_BACK%1 +%$$ + +$head Documentation$$ +see $cref/use API push_back/cppad_vector_push_back/$$ + +$end +*/ +// BEGIN_PUSH_BACK + void push_back(const Type& element) +// END_PUSH_BACK + { // case where no allocation is necessary + if( length_ < capacity_ ) + { data_[length_++] = element; + return; + } + CPPAD_ASSERT_UNKNOWN( length_ == capacity_ ); + + // create new vector with required size + vector vec(length_ + 1); + + // copy old data values + for(size_t i = 0; i < length_; ++i) + vec.data_[i] = data_[i]; + + // put the new element in the new vector + CPPAD_ASSERT_UNKNOWN( vec.length_ == length_ + 1); + vec.data_[length_] = element; + + // swap old and new vectors + swap(vec); + } +/* %$$ +$end +------------------------------------------------------------------------------- +$begin cppad_vector_push_vector$$ +$spell + vec +$$ + +$section Vector Class: push_vector$$ + +$head Syntax$$ +$icode%vec%.push_vector(%other%)%$$ + +$head Prototype$$ +$srcthisfile% + 0%// BEGIN_PUSH_VECTOR%// END_PUSH_VECTOR%1 +%$$ + + +$head Documentation$$ +see $cref/use API push_vector/cppad_vector_push_vector/$$ + +$end +*/ +// BEGIN_PUSH_VECTOR + template void push_vector(const Vector& other) +// END_PUSH_VECTOR + { // can not use push_back because MS V++ 7.1 did not resolve + // to non-template member function when scalar is used. + // + CheckSimpleVector(); + size_t m = other.size(); + + // case where no allcoation is necessary + if( length_ + m <= capacity_ ) + { for(size_t i = 0; i < m; i++) + data_[length_++] = other[i]; + return; + } + + // create new vector with required size + vector vec(length_ + m); + + // copy old data values + for(size_t i = 0; i < length_; ++i) + vec.data_[i] = data_[i]; + + // put the new elements in the new vector + CPPAD_ASSERT_UNKNOWN( vec.length_ == length_ + m ); + for(size_t i = 0; i < m; i++) + vec.data_[length_ + i] = other[i]; + + // swap old and new vectors + swap(vec); + } +/* +------------------------------------------------------------------------------ +$begin cppad_vector_itr_fun$$ +$spell + vec + iterator +$$ + +$section Vector Class: Iterator Functions$$ + +$head Syntax$$ +$icode%os%vec%.begin() +%$$ +$icode%os%vec%.end() +%$$ + +$head Source$$ +$srccode%hpp% */ + const_iterator begin(void) const noexcept + { return const_iterator(&data_, &length_, 0); } + const_iterator end(void) const noexcept + { typedef typename const_iterator::difference_type difference_type; + difference_type index = static_cast(length_); + return const_iterator(&data_, &length_, index); + } + // + iterator begin(void) noexcept + { return iterator(&data_, &length_, 0); } + iterator end(void) noexcept + { typedef typename iterator::difference_type difference_type; + difference_type index = static_cast(length_); + return iterator(&data_, &length_, index); + } +/* %$$ +$end +*/ + +// ========================================================================= +}; // END_TEMPLATE_CLASS_VECTOR +// ========================================================================= + +/* +$begin cppad_vector_output$$ +$spell + vec +$$ + +$section Vector Class: Output$$ + +$head Syntax$$ +$icode%os% << vec%$$ + +$head Source$$ +$srccode%hpp% */ +template +std::ostream& operator << (std::ostream& os , const CppAD::vector& vec ) +{ os << "{ "; + for(size_t i = 0; i < vec.size(); ++i) + { os << vec[i]; + if( i + 1 < vec.size() ) + os << ", "; + } + os << " }"; + return os; +} +/* %$$ +$end +*/ + +} // END_CPPAD_NAMESPACE + +// user API specifies that vector_bool.hpp is included by vector.hpp +# include + +# endif diff --git a/build-config/cppad/include/cppad/utility/vector_bool.hpp b/build-config/cppad/include/cppad/utility/vector_bool.hpp new file mode 100644 index 00000000..57e4a15f --- /dev/null +++ b/build-config/cppad/include/cppad/utility/vector_bool.hpp @@ -0,0 +1,521 @@ +# ifndef CPPAD_UTILITY_VECTOR_BOOL_HPP +# define CPPAD_UTILITY_VECTOR_BOOL_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + + +# include +# include +# include +# include +# include +# include +# include + +namespace CppAD { // BEGIN_CPPAD_NAMESPACE + +// ============================================================================ +class vectorBool { +// ============================================================================ +/* +$begin vector_bool_member$$ +$spell + Bool + vec +$$ + +$section vectorBool: Member Data$$ + +$head Syntax$$ +$icode%vec%.unit_min() +%$$ +$icode%vec%.bit_per_unit() +%$$ + + +$head unit_t$$ +Type used to pack multiple boolean (bit) values into one unit. +Logical operations are preformed one unit at a time. + +$head bit_per_unit_$$ +number of bits packed into each unit value in $code data_$$. + +$head n_unit_$$ +Number of unit values in $code data_$$. + +$head length_$$ +number of bits currently stored in this vector. + +$head data_$$ +pointer to where the bits are stored. + +$head unit_min$$ +minimum number of $code unit_t$$ values that can store $code length_$$ bits. +Note that this is really a function of $code length_$$. + +$head size$$ +is the number of boolean elements in the vector. + +$head capacity$$ +is the maximum number of boolean elements that will fit in the +current allocation for $code data_$$. + +$head Source$$ +$srccode%hpp% */ +private: + typedef size_t unit_t; + static const size_t bit_per_unit_ = std::numeric_limits::digits; + size_t n_unit_; + size_t length_; + unit_t *data_; + // + size_t unit_min(void) const + { if( length_ == 0 ) + return 0; + return (length_ - 1) / bit_per_unit_ + 1; + } +public: + static size_t bit_per_unit(void) + { return bit_per_unit_; } + size_t size(void) const + { return length_; } + size_t capacity(void) const + { return n_unit_ * bit_per_unit_; } +/* %$$ +$end +------------------------------------------------------------------------------- +$begin vector_bool_typedef$$ +$spell + vec + Bool + const +$$ + +$section vectorBool Type Definitions$$ + +$head value_type$$ +type corresponding to the elements of this vector +(note that non-const elements actually use +$cref/vectorBoolElement/vector_bool_element/$$). + +$head Source$$ +$srccode%hpp% */ +public: + typedef bool value_type; +/* %$$ +$end +---------------------------------------------------------------------------- +$begin vector_bool_ctor$$ +$spell + Bool + vec + alloc +$$ +$section vectorBool: Constructors and Destructor$$ + +$head Default$$ +$codei%vectorBool %vec% +%$$ +creates an empty vector with no elements and $code n_unit_$$ zero. + +$head Sizing$$ +$codei%vectorBool %vec%(%n%) +%$$ +where $icode n$$ is a $code size_t$$, +creates the vector $icode vec$$ with $icode n$$ elements and $code n_unit_$$ +greater than or equal $code unit_min()$$. + +$head Copy$$ +$codei%vector<%Type%> %vec%(%other%) +%$$ +where $icode other$$ is a $codei%vector<%Type%>%$$, +creates the vector $icode vec$$ +with $icode%n% = %other%.size()%$$ elements and $code n_unit_$$ +greater than or equal $code unit_min()$$. + +$head Destructor$$ +If $code n_unit_$$ is non-zero, the memory corresponding to data_ +is returned to thread_alloc. + +$head Source$$ +$srccode%hpp%: +*/ + vectorBool(void) : n_unit_(0), length_(0), data_(nullptr) + { } + vectorBool(size_t n) : n_unit_(0), length_(n), data_(nullptr) + { resize(n); } + vectorBool(const vectorBool& other) + : n_unit_(0), length_(0), data_(nullptr) + { resize(other.length_); + size_t n_used = unit_min(); + CPPAD_ASSERT_UNKNOWN( n_used <= n_unit_ ); + for(size_t i = 0; i < n_used; ++i) + data_[i] = other.data_[i]; + } + // n_unit_ is the only value necessary to make destructor work + // for other after this move semantics constructor + vectorBool(vectorBool&& other) + : n_unit_(0), length_(0), data_(nullptr) + { swap(other); } + ~vectorBool(void) + { clear(); } +/* %$$ +$end +----------------------------------------------------------------------------- +$begin vector_bool_size$$ +$spell + Bool + resize + vec +$$ + +$section vectorBool: Change Size$$ + +$head Syntax$$ +$icode%vec%.resize(%n%) +%$$ +$icode%vec%.clear()%$$ + +$head Prototype$$ +$srcthisfile% + 0%// BEGIN_RESIZE%// END_RESIZE%1 +%$$ +$srcthisfile% + 0%// BEGIN_CLEAR%// END_CLEAR%1 +%$$ + +$head n$$ +is the number of elements in the new version of the vector. + +$head resize$$ +If $icode n$$ is less than or equal the input value of +$icode%vec%.n_unit_%$$ times $icode%vec%.bit_per_unit_%$$, +the only change is that $icode%vec%.length_%$$ is set to $icode n$$. +Otherwise the old elements are freed and a new vector is created +with $icode%vec%.length_%$$ equal to $icode n$$. + +$head clear$$ +the memory allocated for this vector is freed and +$icode%vec.length_%$$ and $icode%vec%.n_unit_%$$ are set to zero. + +$end +------------------------------------------------------------------------------ +*/ +// BEGIN_RESIZE +public: + void resize(size_t n) +// END_RESIZE + { length_ = n; + // check if we can use the current memory + size_t min_unit = unit_min(); + if( n_unit_ >= min_unit ) + return; + // check if there is old memory to be freed + if( n_unit_ > 0 ) + { void* v_ptr = reinterpret_cast(data_); + thread_alloc::return_memory(v_ptr); + } + // get new memory and set n_unit + size_t min_bytes = min_unit * sizeof(unit_t); + size_t cap_bytes; + void* v_ptr = thread_alloc::get_memory(min_bytes, cap_bytes); + data_ = reinterpret_cast(v_ptr); + n_unit_ = cap_bytes / sizeof(unit_t); + CPPAD_ASSERT_UNKNOWN( n_unit_ >= min_unit ); + } +// BEGIN_CLEAR + void clear(void) +// END_CLEAR + { + // check if there is old memory to be freed + if( n_unit_ > 0 ) + { void* v_ptr = reinterpret_cast(data_); + thread_alloc::return_memory(v_ptr); + } + length_ = 0; + n_unit_ = 0; + } +/* +------------------------------------------------------------------------------- +$begin vector_bool_assign$$ +$spell + Bool + resize + vec +$$ + +$section vectorBool: Assignment Operators$$ + +$head Syntax$$ +$icode%vec%.swap(%other%) +%$$ +$icode%vec% = %other%$$ + +$head Prototype$$ +$srcthisfile% + 0%// BEGIN_SWAP%// END_SWAP%1 +%$$ +$srcthisfile% + 0%// BEGIN_ASSIGN%// END_ASSIGN%1 +%$$ +$srcthisfile% + 0%// BEGIN_MOVE_SEMANTICS%// END_MOVE_SEMANTICS%1 +%$$ + +$head swap$$ +Swaps $code n_unit_$$, $code length_$$ and $code data_$$ +between $icode vec$$ and $icode other$$. + +$head Assignment$$ +If the input value of $icode%vec%.length_%$$ is zero, +$cref/resize/vector_bool_size/resize/$$ is used to change its size to +be the same as other. +The size of $icode vec$$ and $icode other$$ are then compared and if +different, an assert with a know cause is generated. +The elements of $icode vec$$ are then individually assigned +to have the value of the corresponding elements of $icode other$$. + +$head Move Semantics$$ +A move semantics version of the assignment operator, implemented using +$code swap$$, is defined. + +$end +------------------------------------------------------------------------------- +*/ +// BEGIN_SWAP + void swap(vectorBool& other) +// END_SWAP + { // swap with self case + if( this == &other ) + return; + std::swap(n_unit_, other.n_unit_ ); + std::swap(length_, other.length_ ); + std::swap(data_, other.data_ ); + return; + } +// BEGIN_ASSIGN + vectorBool& operator=(const vectorBool& other) +// END_ASSIGN + { // If original length is zero, then resize it to other. + // Otherwise a length mismatch is an error. + if( length_ == 0 ) + resize( other.length_ ); + CPPAD_ASSERT_KNOWN( + length_ == other.length_ , + "vectorBool: size miss match in assignment operation" + ); + size_t n_used = unit_min(); + CPPAD_ASSERT_UNKNOWN( n_used <= n_unit_ ); + for(size_t i = 0; i < n_used; i++) + data_[i] = other.data_[i]; + return *this; + } +// BEGIN_MOVE_SEMANTICS + vectorBool& operator=(vectorBool&& other) +// END_MOVE_SEMANTICS + { CPPAD_ASSERT_KNOWN( + length_ == other.length_ || (length_ == 0), + "vectorBool: size miss match in assignment operation" + ); + swap(other); + return *this; + } +/* +------------------------------------------------------------------------------- +$begin vector_bool_subscript$$ +$spell + vec + Bool + const +$$ + +$section vectorBool: Subscript Operator$$ + +$head Syntax$$ +$icode%target% = %vec%[%i%] +%$$ +$icode%vec%[%i%] = %source% +%$$ + +$head target$$ +In this syntax $icode vec$$ is $code const$$ +and the value $icode%vec%[%i%]%$$ is a $code bool$$. + +$head source$$ +In this syntax $icode vec$$ is not $code const$$ +and the value $icode%vec%[%i%]%$$ is a +$cref/vectorBoolElement/vector_bool_element/$$. + +$head Source$$ +$srccode%hpp% */ + bool operator[](size_t i) const + { CPPAD_ASSERT_KNOWN( i < length_, + "vectorBool: index greater than or equal vector size" + ); + size_t unit_index = i / bit_per_unit_; + size_t bit_index = i - unit_index * bit_per_unit_; + unit_t unit = data_[unit_index]; + unit_t mask = unit_t(1) << bit_index; + return (unit & mask) != 0; + } + local::utility::vectorBoolElement operator[](size_t i) + { CPPAD_ASSERT_KNOWN( i < length_, + "vectorBool: index greater than or equal vector size" + ); + size_t unit_index = i / bit_per_unit_; + size_t bit_index = i - unit_index * bit_per_unit_; + unit_t mask = unit_t(1) << bit_index; + return local::utility::vectorBoolElement(data_ + unit_index , mask); + } +/* %$$ +$end +------------------------------------------------------------------------------- +$begin vector_bool_push_back$$ +$spell + Bool + vec +$$ + +$section vectorBool: push_back$$ + +$head Syntax$$ +$icode%vec%.push_back(%element%)%$$ + +$head Prototype$$ +$srcthisfile% + 0%// BEGIN_PUSH_BACK%// END_PUSH_BACK%1 +%$$ + +$head Documentation$$ +see $cref/use API push_back/cppad_vector_push_back/$$ + +$end +*/ +// BEGIN_PUSH_BACK + void push_back(bool element) +// END_PUSH_BACK + { CPPAD_ASSERT_UNKNOWN( unit_min() <= n_unit_ ); + size_t old_length = length_; + if( length_ + 1 > n_unit_ * bit_per_unit_ ) + { CPPAD_ASSERT_UNKNOWN( unit_min() == n_unit_ ); + + // create new vector with requuired size + vectorBool vec(length_ + 1); + + // copy old data values + size_t n_used = unit_min(); + CPPAD_ASSERT_UNKNOWN( n_used <= n_unit_ ); + for(size_t i = 0; i < n_used; ++i) + vec.data_[i] = data_[i]; + + // swap old and new vectors + swap(vec); + } + else + ++length_; + CPPAD_ASSERT_UNKNOWN( length_ <= n_unit_ * bit_per_unit_ ) + size_t unit_index = old_length / bit_per_unit_; + size_t bit_index = old_length - unit_index * bit_per_unit_; + unit_t mask = unit_t(1) << bit_index; + if( element ) + data_[unit_index] |= mask; + else + data_[unit_index] &= ~mask; + } +/* %$$ +$end +------------------------------------------------------------------------------- +$begin vector_bool_push_vector$$ +$spell + Bool + vec +$$ + +$section vectorBool: push_vector$$ + +$head Syntax$$ +$icode%vec%.push_vector(%other%)%$$ + +$head Prototype$$ +$srcthisfile% + 0%// BEGIN_PUSH_VECTOR%// END_PUSH_VECTOR%1 +%$$ + + +$head Documentation$$ +see $cref/use API push_vector/cppad_vector_push_vector/$$ + +$end +*/ +// BEGIN_PUSH_VECTOR + template void push_vector(const Vector& other) +// END_PUSH_VECTOR + { CPPAD_ASSERT_UNKNOWN( unit_min() <= n_unit_ ); + CheckSimpleVector(); + size_t old_length = length_; + size_t m = other.size(); + if( length_ + m > n_unit_ * bit_per_unit_ ) + { + // create new vector with requuired size + vectorBool vec(length_ + m); + + // copy old data values + size_t n_used = unit_min(); + CPPAD_ASSERT_UNKNOWN( n_used <= n_unit_ ); + for(size_t i = 0; i < n_used; ++i) + vec.data_[i] = data_[i]; + + // swap old and new vectors + swap(vec); + } + else + length_ += m; + // + // put the new elements in this vector + CPPAD_ASSERT_UNKNOWN( length_ <= n_unit_ * bit_per_unit_ ) + for(size_t k = 0; k < m; k++) + { size_t unit_index = (old_length + k) / bit_per_unit_; + size_t bit_index = (old_length + k) - unit_index * bit_per_unit_; + unit_t mask = unit_t(1) << bit_index; + if( other[k] ) + data_[unit_index] |= mask; + else + data_[unit_index] &= ~mask; + } + } +}; + +/* +$begin vector_bool_output$$ +$spell + Bool + vec +$$ + +$section vectorBool: Output$$ + +$head Syntax$$ +$icode%os% << vec%$$ + +$head Source$$ +$srccode%hpp% */ +inline std::ostream& operator << (std::ostream& os , const vectorBool& vec ) +{ for(size_t i = 0; i < vec.size(); ++i) + os << vec[i]; + return os; +} +/* %$$ +$end +*/ + +} // END_CPPAD_NAMESPACE +# endif diff --git a/build-config/cppad/include/cppad/wno_conversion.hpp b/build-config/cppad/include/cppad/wno_conversion.hpp new file mode 100644 index 00000000..30d02d17 --- /dev/null +++ b/build-config/cppad/include/cppad/wno_conversion.hpp @@ -0,0 +1,45 @@ +# ifndef CPPAD_WNO_CONVERSION_HPP +# define CPPAD_WNO_CONVERSION_HPP +/* -------------------------------------------------------------------------- +CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-18 Bradley M. Bell + +CppAD is distributed under the terms of the + Eclipse Public License Version 2.0. + +This Source Code may also be made available under the following +Secondary License when the conditions for such availability set forth +in the Eclipse Public License, Version 2.0 are satisfied: + GNU General Public License, Version 2.0 or later. +---------------------------------------------------------------------------- */ + +/* +$begin wno_conversion$$ +$spell + cppad + wno + cpp + hpp +$$ + +$section Suppress Suspect Implicit Conversion Warnings$$ + +$head Syntax$$ +$codei%# include %$$ + +$head Purpose$$ +In many cases it is good to have warnings for implicit conversions +that may loose range or precision. +The include command above, before any other includes, suppresses +these warning for a particular compilation unit (which usually corresponds +to a $icode%*%.cpp%$$ file). + +$end +*/ + +# include +# if CPPAD_COMPILER_HAS_CONVERSION_WARN +# pragma GCC diagnostic ignored "-Wfloat-conversion" +# pragma GCC diagnostic ignored "-Wconversion" +# endif + +# endif diff --git a/build-config/cppad/include/makefile.am b/build-config/cppad/include/makefile.am new file mode 100644 index 00000000..1bb5f23c --- /dev/null +++ b/build-config/cppad/include/makefile.am @@ -0,0 +1,348 @@ +# ----------------------------------------------------------------------------- +# CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell +# +# CppAD is distributed under the terms of the +# Eclipse Public License Version 2.0. +# +# This Source Code may also be made available under the following +# Secondary License when the conditions for such availability set forth +# in the Eclipse Public License, Version 2.0 are satisfied: +# GNU General Public License, Version 2.0 or later. +# ----------------------------------------------------------------------------- +# +if CppAD_POSTFIX +postfix_dir = $(POSTFIX_DIR) +else +postfix_dir = . +endif +# +myincludedir = $(includedir)/$(postfix_dir) +# +# BEGIN_SORT_THIS_LINE_PLUS_2 +nobase_myinclude_HEADERS = \ + cppad/base_require.hpp \ + cppad/configure.hpp \ + cppad/core/abort_recording.hpp \ + cppad/core/abs.hpp \ + cppad/core/abs_normal_fun.hpp \ + cppad/core/ad.hpp \ + cppad/core/ad_assign.hpp \ + cppad/core/ad_binary.hpp \ + cppad/core/ad_ctor.hpp \ + cppad/core/ad_fun.hpp \ + cppad/core/ad_io.hpp \ + cppad/core/ad_to_string.hpp \ + cppad/core/ad_type.hpp \ + cppad/core/ad_valued.hpp \ + cppad/core/add.hpp \ + cppad/core/add_eq.hpp \ + cppad/core/arithmetic.hpp \ + cppad/core/atan2.hpp \ + cppad/core/atomic/atomic_one.hpp \ + cppad/core/atomic/atomic_three.hpp \ + cppad/core/atomic/atomic_two.hpp \ + cppad/core/atomic/three_afun.hpp \ + cppad/core/atomic/three_ctor.hpp \ + cppad/core/atomic/three_for_type.hpp \ + cppad/core/atomic/three_forward.hpp \ + cppad/core/atomic/three_hes_sparsity.hpp \ + cppad/core/atomic/three_jac_sparsity.hpp \ + cppad/core/atomic/three_rev_depend.hpp \ + cppad/core/atomic/three_reverse.hpp \ + cppad/core/atomic/two_afun.hpp \ + cppad/core/atomic/two_clear.hpp \ + cppad/core/atomic/two_ctor.hpp \ + cppad/core/atomic/two_for_sparse_hes.hpp \ + cppad/core/atomic/two_for_sparse_jac.hpp \ + cppad/core/atomic/two_forward.hpp \ + cppad/core/atomic/two_option.hpp \ + cppad/core/atomic/two_rev_depend.hpp \ + cppad/core/atomic/two_rev_sparse_hes.hpp \ + cppad/core/atomic/two_rev_sparse_jac.hpp \ + cppad/core/atomic/two_reverse.hpp \ + cppad/core/azmul.hpp \ + cppad/core/base2ad.hpp \ + cppad/core/base_complex.hpp \ + cppad/core/base_cond_exp.hpp \ + cppad/core/base_double.hpp \ + cppad/core/base_float.hpp \ + cppad/core/base_hash.hpp \ + cppad/core/base_limits.hpp \ + cppad/core/base_std_math.hpp \ + cppad/core/base_to_string.hpp \ + cppad/core/bender_quad.hpp \ + cppad/core/bool_fun.hpp \ + cppad/core/bool_valued.hpp \ + cppad/core/capacity_order.hpp \ + cppad/core/check_for_nan.hpp \ + cppad/core/chkpoint_one/chkpoint_one.hpp \ + cppad/core/chkpoint_one/ctor.hpp \ + cppad/core/chkpoint_one/for_sparse_jac.hpp \ + cppad/core/chkpoint_one/forward.hpp \ + cppad/core/chkpoint_one/rev_sparse_hes.hpp \ + cppad/core/chkpoint_one/rev_sparse_jac.hpp \ + cppad/core/chkpoint_one/reverse.hpp \ + cppad/core/chkpoint_one/set_hes_sparse_bool.hpp \ + cppad/core/chkpoint_one/set_hes_sparse_set.hpp \ + cppad/core/chkpoint_one/set_jac_sparse_bool.hpp \ + cppad/core/chkpoint_one/set_jac_sparse_set.hpp \ + cppad/core/chkpoint_two/chkpoint_two.hpp \ + cppad/core/chkpoint_two/ctor.hpp \ + cppad/core/chkpoint_two/dynamic.hpp \ + cppad/core/chkpoint_two/for_type.hpp \ + cppad/core/chkpoint_two/forward.hpp \ + cppad/core/chkpoint_two/hes_sparsity.hpp \ + cppad/core/chkpoint_two/jac_sparsity.hpp \ + cppad/core/chkpoint_two/rev_depend.hpp \ + cppad/core/chkpoint_two/reverse.hpp \ + cppad/core/compare.hpp \ + cppad/core/compound_assign.hpp \ + cppad/core/con_dyn_var.hpp \ + cppad/core/cond_exp.hpp \ + cppad/core/convert.hpp \ + cppad/core/cppad_assert.hpp \ + cppad/core/dependent.hpp \ + cppad/core/discrete/discrete.hpp \ + cppad/core/div.hpp \ + cppad/core/div_eq.hpp \ + cppad/core/drivers.hpp \ + cppad/core/epsilon.hpp \ + cppad/core/equal_op_seq.hpp \ + cppad/core/for_hes_sparsity.hpp \ + cppad/core/for_jac_sparsity.hpp \ + cppad/core/for_one.hpp \ + cppad/core/for_sparse_hes.hpp \ + cppad/core/for_sparse_jac.hpp \ + cppad/core/for_two.hpp \ + cppad/core/forward/forward.hpp \ + cppad/core/fun_check.hpp \ + cppad/core/fun_construct.hpp \ + cppad/core/fun_eval.hpp \ + cppad/core/hash_code.hpp \ + cppad/core/hessian.hpp \ + cppad/core/identical.hpp \ + cppad/core/independent/independent.hpp \ + cppad/core/integer.hpp \ + cppad/core/jacobian.hpp \ + cppad/core/graph/from_json.hpp \ + cppad/core/graph/graph_op_enum.hpp \ + cppad/core/graph/to_json.hpp \ + cppad/core/lu_ratio.hpp \ + cppad/core/mul.hpp \ + cppad/core/mul_eq.hpp \ + cppad/core/near_equal_ext.hpp \ + cppad/core/new_dynamic.hpp \ + cppad/core/num_skip.hpp \ + cppad/core/numeric_limits.hpp \ + cppad/core/omp_max_thread.hpp \ + cppad/core/opt_val_hes.hpp \ + cppad/core/optimize.hpp \ + cppad/core/ordered.hpp \ + cppad/core/parallel_ad.hpp \ + cppad/core/pow.hpp \ + cppad/core/print_for.hpp \ + cppad/core/rev_hes_sparsity.hpp \ + cppad/core/rev_jac_sparsity.hpp \ + cppad/core/rev_one.hpp \ + cppad/core/rev_sparse_hes.hpp \ + cppad/core/rev_sparse_jac.hpp \ + cppad/core/rev_two.hpp \ + cppad/core/reverse.hpp \ + cppad/core/sign.hpp \ + cppad/core/sparse.hpp \ + cppad/core/sparse_hes.hpp \ + cppad/core/sparse_hessian.hpp \ + cppad/core/sparse_jac.hpp \ + cppad/core/sparse_jacobian.hpp \ + cppad/core/standard_math.hpp \ + cppad/core/std_math_11.hpp \ + cppad/core/sub.hpp \ + cppad/core/sub_eq.hpp \ + cppad/core/subgraph_jac_rev.hpp \ + cppad/core/subgraph_reverse.hpp \ + cppad/core/subgraph_sparsity.hpp \ + cppad/core/tape_link.hpp \ + cppad/core/test_vector.hpp \ + cppad/core/testvector.hpp \ + cppad/core/unary_minus.hpp \ + cppad/core/unary_plus.hpp \ + cppad/core/undef.hpp \ + cppad/core/user_ad.hpp \ + cppad/core/value.hpp \ + cppad/core/var2par.hpp \ + cppad/core/vec_ad/vec_ad.hpp \ + cppad/core/zdouble.hpp \ + cppad/cppad.hpp \ + cppad/example/atomic_three/mat_mul.hpp \ + cppad/example/atomic_two/eigen_cholesky.hpp \ + cppad/example/atomic_two/eigen_mat_inv.hpp \ + cppad/example/atomic_two/eigen_mat_mul.hpp \ + cppad/example/base_adolc.hpp \ + cppad/example/code_gen_fun.hpp \ + cppad/example/cppad_eigen.hpp \ + cppad/example/eigen_plugin.hpp \ + cppad/ipopt/solve.hpp \ + cppad/ipopt/solve_callback.hpp \ + cppad/ipopt/solve_result.hpp \ + cppad/local/abs_op.hpp \ + cppad/local/acos_op.hpp \ + cppad/local/acosh_op.hpp \ + cppad/local/ad_tape.hpp \ + cppad/local/add_op.hpp \ + cppad/local/asin_op.hpp \ + cppad/local/asinh_op.hpp \ + cppad/local/atan_op.hpp \ + cppad/local/atanh_op.hpp \ + cppad/local/atom_state.hpp \ + cppad/local/atomic_index.hpp \ + cppad/local/color_general.hpp \ + cppad/local/color_symmetric.hpp \ + cppad/local/comp_op.hpp \ + cppad/local/cond_op.hpp \ + cppad/local/cos_op.hpp \ + cppad/local/cosh_op.hpp \ + cppad/local/cppad_colpack.hpp \ + cppad/local/cskip_op.hpp \ + cppad/local/csum_op.hpp \ + cppad/local/declare_ad.hpp \ + cppad/local/define.hpp \ + cppad/local/discrete_op.hpp \ + cppad/local/div_op.hpp \ + cppad/local/erf_op.hpp \ + cppad/local/exp_op.hpp \ + cppad/local/expm1_op.hpp \ + cppad/local/hash_code.hpp \ + cppad/local/independent.hpp \ + cppad/local/is_pod.hpp \ + cppad/core/graph/from_graph.hpp \ + cppad/local/graph/json_lexer.hpp \ + cppad/core/graph/to_graph.hpp \ + cppad/core/graph/cpp_graph.hpp \ + cppad/local/graph/cpp_graph_itr.hpp \ + cppad/local/graph/cpp_graph_op.hpp \ + cppad/local/graph/json_parser.hpp \ + cppad/local/graph/json_writer.hpp \ + cppad/local/load_op.hpp \ + cppad/local/log1p_op.hpp \ + cppad/local/log_op.hpp \ + cppad/local/mul_op.hpp \ + cppad/local/op.hpp \ + cppad/local/op_code_dyn.hpp \ + cppad/local/op_code_var.hpp \ + cppad/local/optimize/cexp_info.hpp \ + cppad/local/optimize/csum_op_info.hpp \ + cppad/local/optimize/csum_stacks.hpp \ + cppad/local/optimize/get_cexp_info.hpp \ + cppad/local/optimize/get_dyn_previous.hpp \ + cppad/local/optimize/get_op_previous.hpp \ + cppad/local/optimize/get_op_usage.hpp \ + cppad/local/optimize/get_par_usage.hpp \ + cppad/local/optimize/hash_code.hpp \ + cppad/local/optimize/match_op.hpp \ + cppad/local/optimize/optimize_run.hpp \ + cppad/local/optimize/record_csum.hpp \ + cppad/local/optimize/record_pv.hpp \ + cppad/local/optimize/record_vp.hpp \ + cppad/local/optimize/record_vv.hpp \ + cppad/local/optimize/size_pair.hpp \ + cppad/local/optimize/usage.hpp \ + cppad/local/parameter_op.hpp \ + cppad/local/play/addr_enum.hpp \ + cppad/local/play/atom_op_info.hpp \ + cppad/local/play/player.hpp \ + cppad/local/play/random_iterator.hpp \ + cppad/local/play/random_setup.hpp \ + cppad/local/play/sequential_iterator.hpp \ + cppad/local/play/subgraph_iterator.hpp \ + cppad/local/pod_vector.hpp \ + cppad/local/pow_op.hpp \ + cppad/local/print_op.hpp \ + cppad/local/prototype_op.hpp \ + cppad/local/record/cond_exp.hpp \ + cppad/local/record/comp_op.hpp \ + cppad/local/record/put_dyn_atomic.hpp \ + cppad/local/record/put_var_atomic.hpp \ + cppad/local/record/put_var_vecad.hpp \ + cppad/local/record/recorder.hpp \ + cppad/local/set_get_in_parallel.hpp \ + cppad/local/sign_op.hpp \ + cppad/local/sin_op.hpp \ + cppad/local/sinh_op.hpp \ + cppad/local/sparse/binary_op.hpp \ + cppad/local/sparse/internal.hpp \ + cppad/local/sparse/list_setvec.hpp \ + cppad/local/sparse/pack_setvec.hpp \ + cppad/local/sparse/svec_setvec.hpp \ + cppad/local/sparse/unary_op.hpp \ + cppad/local/sqrt_op.hpp \ + cppad/local/std_set.hpp \ + cppad/local/store_op.hpp \ + cppad/local/sub_op.hpp \ + cppad/local/subgraph/arg_variable.hpp \ + cppad/local/subgraph/entire_call.hpp \ + cppad/local/subgraph/get_rev.hpp \ + cppad/local/subgraph/info.hpp \ + cppad/local/subgraph/init_rev.hpp \ + cppad/local/subgraph/sparsity.hpp \ + cppad/local/sweep/call_atomic.hpp \ + cppad/local/sweep/dynamic.hpp \ + cppad/local/sweep/for_hes.hpp \ + cppad/local/sweep/for_jac.hpp \ + cppad/local/sweep/forward0.hpp \ + cppad/local/sweep/forward1.hpp \ + cppad/local/sweep/forward2.hpp \ + cppad/local/sweep/rev_hes.hpp \ + cppad/local/sweep/rev_jac.hpp \ + cppad/local/sweep/reverse.hpp \ + cppad/local/tan_op.hpp \ + cppad/local/tanh_op.hpp \ + cppad/local/utility/cppad_vector_itr.hpp \ + cppad/local/utility/vector_bool.hpp \ + cppad/local/zmul_op.hpp \ + cppad/speed/det_33.hpp \ + cppad/speed/det_by_lu.hpp \ + cppad/speed/det_by_minor.hpp \ + cppad/speed/det_grad_33.hpp \ + cppad/speed/det_of_minor.hpp \ + cppad/speed/mat_sum_sq.hpp \ + cppad/speed/ode_evaluate.hpp \ + cppad/speed/sparse_hes_fun.hpp \ + cppad/speed/sparse_jac_fun.hpp \ + cppad/speed/uniform_01.hpp \ + cppad/utility.hpp \ + cppad/utility/check_numeric_type.hpp \ + cppad/utility/check_simple_vector.hpp \ + cppad/utility/elapsed_seconds.hpp \ + cppad/utility/error_handler.hpp \ + cppad/utility/index_sort.hpp \ + cppad/utility/lu_factor.hpp \ + cppad/utility/lu_invert.hpp \ + cppad/utility/lu_solve.hpp \ + cppad/utility/memory_leak.hpp \ + cppad/utility/nan.hpp \ + cppad/utility/near_equal.hpp \ + cppad/utility/ode_err_control.hpp \ + cppad/utility/ode_gear.hpp \ + cppad/utility/ode_gear_control.hpp \ + cppad/utility/omp_alloc.hpp \ + cppad/utility/poly.hpp \ + cppad/utility/pow_int.hpp \ + cppad/utility/romberg_mul.hpp \ + cppad/utility/romberg_one.hpp \ + cppad/utility/rosen_34.hpp \ + cppad/utility/runge_45.hpp \ + cppad/utility/set_union.hpp \ + cppad/utility/sparse2eigen.hpp \ + cppad/utility/sparse_rc.hpp \ + cppad/utility/sparse_rcv.hpp \ + cppad/utility/speed_test.hpp \ + cppad/utility/test_boolofvoid.hpp \ + cppad/utility/thread_alloc.hpp \ + cppad/utility/time_test.hpp \ + cppad/utility/to_string.hpp \ + cppad/utility/track_new_del.hpp \ + cppad/utility/vector.hpp \ + cppad/utility/vector_bool.hpp \ + cppad/wno_conversion.hpp +# End nobase_myinclude_HEADERS (check_makefile.sh uses this comment) +# END_SORT_THIS_LINE_MINUS_2 diff --git a/build-config/cppad/include/makefile.in b/build-config/cppad/include/makefile.in new file mode 100644 index 00000000..7a7f349a --- /dev/null +++ b/build-config/cppad/include/makefile.in @@ -0,0 +1,941 @@ +# makefile.in generated by automake 1.16.2 from makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2020 Free Software Foundation, Inc. + +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +VPATH = @srcdir@ +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = include +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/makefile.am $(nobase_myinclude_HEADERS) \ + $(am__DIST_COMMON) +mkinstalldirs = $(install_sh) -d +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +SOURCES = +DIST_SOURCES = +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +am__uninstall_files_from_dir = { \ + test -z "$$files" \ + || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ + || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ + $(am__cd) "$$dir" && rm -f $$files; }; \ + } +am__installdirs = "$(DESTDIR)$(myincludedir)" +HEADERS = $(nobase_myinclude_HEADERS) +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +# Read a list of newline-separated strings from the standard input, +# and print each of them once, without duplicates. Input order is +# *not* preserved. +am__uniquify_input = $(AWK) '\ + BEGIN { nonempty = 0; } \ + { items[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in items) print i; }; } \ +' +# Make sure the list of sources is unique. This is necessary because, +# e.g., the same source file might be shared among _SOURCES variables +# for different programs/libraries. +am__define_uniq_tagged_files = \ + list='$(am__tagged_files)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | $(am__uniquify_input)` +ETAGS = etags +CTAGS = ctags +am__DIST_COMMON = $(srcdir)/makefile.in +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ABS_TOP_BUILDDIR = @ABS_TOP_BUILDDIR@ +ABS_TOP_SRCDIR = @ABS_TOP_SRCDIR@ +ACLOCAL = @ACLOCAL@ +ADOLC_DIR = @ADOLC_DIR@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BOOST_DIR = @BOOST_DIR@ +BOOST_INCLUDE = @BOOST_INCLUDE@ +BTHREAD_LIB = @BTHREAD_LIB@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPAD_IPOPT_LD_PATH = @CPPAD_IPOPT_LD_PATH@ +CPPAD_IPOPT_LIBS = @CPPAD_IPOPT_LIBS@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CXX_FLAGS = @CXX_FLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DL_LIB = @DL_LIB@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EIGEN_DIR = @EIGEN_DIR@ +EIGEN_INCLUDE = @EIGEN_INCLUDE@ +EXEEXT = @EXEEXT@ +FADBAD_DIR = @FADBAD_DIR@ +FC = @FC@ +FCFLAGS = @FCFLAGS@ +FCLIBS = @FCLIBS@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +IPOPT_DIR = @IPOPT_DIR@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LTLIBOBJS = @LTLIBOBJS@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MAX_NUM_THREADS = @MAX_NUM_THREADS@ +MKDIR_P = @MKDIR_P@ +OBJEXT = @OBJEXT@ +OPENMP_FLAGS = @OPENMP_FLAGS@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +POSTFIX_DIR = @POSTFIX_DIR@ +PTHREAD_LIB = @PTHREAD_LIB@ +RANLIB = @RANLIB@ +SACADO_DIR = @SACADO_DIR@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +TAPE_ADDR_TYPE = @TAPE_ADDR_TYPE@ +TAPE_ID_TYPE = @TAPE_ID_TYPE@ +VERSION = @VERSION@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_FC = @ac_ct_FC@ +adolc_prefix = @adolc_prefix@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +compiler_has_conversion_warn = @compiler_has_conversion_warn@ +cppad_boostvector = @cppad_boostvector@ +cppad_cplusplus_201100_ok = @cppad_cplusplus_201100_ok@ +cppad_cppadvector = @cppad_cppadvector@ +cppad_cxx_flags = @cppad_cxx_flags@ +cppad_description = @cppad_description@ +cppad_eigenvector = @cppad_eigenvector@ +cppad_has_adolc = @cppad_has_adolc@ +cppad_has_boost = @cppad_has_boost@ +cppad_has_colpack = @cppad_has_colpack@ +cppad_has_eigen = @cppad_has_eigen@ +cppad_has_fadbad = @cppad_has_fadbad@ +cppad_has_gettimeofday = @cppad_has_gettimeofday@ +cppad_has_ipopt = @cppad_has_ipopt@ +cppad_has_mkstemp = @cppad_has_mkstemp@ +cppad_has_sacado = @cppad_has_sacado@ +cppad_has_tmpnam_s = @cppad_has_tmpnam_s@ +cppad_max_num_threads = @cppad_max_num_threads@ +cppad_pkgconfig_cflags = @cppad_pkgconfig_cflags@ +cppad_pkgconfig_cflags_uninstalled = @cppad_pkgconfig_cflags_uninstalled@ +cppad_pkgconfig_libs = @cppad_pkgconfig_libs@ +cppad_pkgconfig_libs_uninstalled = @cppad_pkgconfig_libs_uninstalled@ +cppad_pkgconfig_requires = @cppad_pkgconfig_requires@ +cppad_pkgconfig_requires_uninstalled = @cppad_pkgconfig_requires_uninstalled@ +cppad_stdvector = @cppad_stdvector@ +cppad_tape_addr_type = @cppad_tape_addr_type@ +cppad_tape_id_type = @cppad_tape_id_type@ +cppad_url = @cppad_url@ +cppad_version = @cppad_version@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +eigen_prefix = @eigen_prefix@ +exec_prefix = @exec_prefix@ +have_pkg_config = @have_pkg_config@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +ipopt_prefix = @ipopt_prefix@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +@CppAD_POSTFIX_FALSE@postfix_dir = . + +# ----------------------------------------------------------------------------- +# CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell +# +# CppAD is distributed under the terms of the +# Eclipse Public License Version 2.0. +# +# This Source Code may also be made available under the following +# Secondary License when the conditions for such availability set forth +# in the Eclipse Public License, Version 2.0 are satisfied: +# GNU General Public License, Version 2.0 or later. +# ----------------------------------------------------------------------------- +# +@CppAD_POSTFIX_TRUE@postfix_dir = $(POSTFIX_DIR) +# +myincludedir = $(includedir)/$(postfix_dir) +# +# BEGIN_SORT_THIS_LINE_PLUS_2 +nobase_myinclude_HEADERS = \ + cppad/base_require.hpp \ + cppad/configure.hpp \ + cppad/core/abort_recording.hpp \ + cppad/core/abs.hpp \ + cppad/core/abs_normal_fun.hpp \ + cppad/core/ad.hpp \ + cppad/core/ad_assign.hpp \ + cppad/core/ad_binary.hpp \ + cppad/core/ad_ctor.hpp \ + cppad/core/ad_fun.hpp \ + cppad/core/ad_io.hpp \ + cppad/core/ad_to_string.hpp \ + cppad/core/ad_type.hpp \ + cppad/core/ad_valued.hpp \ + cppad/core/add.hpp \ + cppad/core/add_eq.hpp \ + cppad/core/arithmetic.hpp \ + cppad/core/atan2.hpp \ + cppad/core/atomic/atomic_one.hpp \ + cppad/core/atomic/atomic_three.hpp \ + cppad/core/atomic/atomic_two.hpp \ + cppad/core/atomic/three_afun.hpp \ + cppad/core/atomic/three_ctor.hpp \ + cppad/core/atomic/three_for_type.hpp \ + cppad/core/atomic/three_forward.hpp \ + cppad/core/atomic/three_hes_sparsity.hpp \ + cppad/core/atomic/three_jac_sparsity.hpp \ + cppad/core/atomic/three_rev_depend.hpp \ + cppad/core/atomic/three_reverse.hpp \ + cppad/core/atomic/two_afun.hpp \ + cppad/core/atomic/two_clear.hpp \ + cppad/core/atomic/two_ctor.hpp \ + cppad/core/atomic/two_for_sparse_hes.hpp \ + cppad/core/atomic/two_for_sparse_jac.hpp \ + cppad/core/atomic/two_forward.hpp \ + cppad/core/atomic/two_option.hpp \ + cppad/core/atomic/two_rev_depend.hpp \ + cppad/core/atomic/two_rev_sparse_hes.hpp \ + cppad/core/atomic/two_rev_sparse_jac.hpp \ + cppad/core/atomic/two_reverse.hpp \ + cppad/core/azmul.hpp \ + cppad/core/base2ad.hpp \ + cppad/core/base_complex.hpp \ + cppad/core/base_cond_exp.hpp \ + cppad/core/base_double.hpp \ + cppad/core/base_float.hpp \ + cppad/core/base_hash.hpp \ + cppad/core/base_limits.hpp \ + cppad/core/base_std_math.hpp \ + cppad/core/base_to_string.hpp \ + cppad/core/bender_quad.hpp \ + cppad/core/bool_fun.hpp \ + cppad/core/bool_valued.hpp \ + cppad/core/capacity_order.hpp \ + cppad/core/check_for_nan.hpp \ + cppad/core/chkpoint_one/chkpoint_one.hpp \ + cppad/core/chkpoint_one/ctor.hpp \ + cppad/core/chkpoint_one/for_sparse_jac.hpp \ + cppad/core/chkpoint_one/forward.hpp \ + cppad/core/chkpoint_one/rev_sparse_hes.hpp \ + cppad/core/chkpoint_one/rev_sparse_jac.hpp \ + cppad/core/chkpoint_one/reverse.hpp \ + cppad/core/chkpoint_one/set_hes_sparse_bool.hpp \ + cppad/core/chkpoint_one/set_hes_sparse_set.hpp \ + cppad/core/chkpoint_one/set_jac_sparse_bool.hpp \ + cppad/core/chkpoint_one/set_jac_sparse_set.hpp \ + cppad/core/chkpoint_two/chkpoint_two.hpp \ + cppad/core/chkpoint_two/ctor.hpp \ + cppad/core/chkpoint_two/dynamic.hpp \ + cppad/core/chkpoint_two/for_type.hpp \ + cppad/core/chkpoint_two/forward.hpp \ + cppad/core/chkpoint_two/hes_sparsity.hpp \ + cppad/core/chkpoint_two/jac_sparsity.hpp \ + cppad/core/chkpoint_two/rev_depend.hpp \ + cppad/core/chkpoint_two/reverse.hpp \ + cppad/core/compare.hpp \ + cppad/core/compound_assign.hpp \ + cppad/core/con_dyn_var.hpp \ + cppad/core/cond_exp.hpp \ + cppad/core/convert.hpp \ + cppad/core/cppad_assert.hpp \ + cppad/core/dependent.hpp \ + cppad/core/discrete/discrete.hpp \ + cppad/core/div.hpp \ + cppad/core/div_eq.hpp \ + cppad/core/drivers.hpp \ + cppad/core/epsilon.hpp \ + cppad/core/equal_op_seq.hpp \ + cppad/core/for_hes_sparsity.hpp \ + cppad/core/for_jac_sparsity.hpp \ + cppad/core/for_one.hpp \ + cppad/core/for_sparse_hes.hpp \ + cppad/core/for_sparse_jac.hpp \ + cppad/core/for_two.hpp \ + cppad/core/forward/forward.hpp \ + cppad/core/fun_check.hpp \ + cppad/core/fun_construct.hpp \ + cppad/core/fun_eval.hpp \ + cppad/core/hash_code.hpp \ + cppad/core/hessian.hpp \ + cppad/core/identical.hpp \ + cppad/core/independent/independent.hpp \ + cppad/core/integer.hpp \ + cppad/core/jacobian.hpp \ + cppad/core/graph/from_json.hpp \ + cppad/core/graph/graph_op_enum.hpp \ + cppad/core/graph/to_json.hpp \ + cppad/core/lu_ratio.hpp \ + cppad/core/mul.hpp \ + cppad/core/mul_eq.hpp \ + cppad/core/near_equal_ext.hpp \ + cppad/core/new_dynamic.hpp \ + cppad/core/num_skip.hpp \ + cppad/core/numeric_limits.hpp \ + cppad/core/omp_max_thread.hpp \ + cppad/core/opt_val_hes.hpp \ + cppad/core/optimize.hpp \ + cppad/core/ordered.hpp \ + cppad/core/parallel_ad.hpp \ + cppad/core/pow.hpp \ + cppad/core/print_for.hpp \ + cppad/core/rev_hes_sparsity.hpp \ + cppad/core/rev_jac_sparsity.hpp \ + cppad/core/rev_one.hpp \ + cppad/core/rev_sparse_hes.hpp \ + cppad/core/rev_sparse_jac.hpp \ + cppad/core/rev_two.hpp \ + cppad/core/reverse.hpp \ + cppad/core/sign.hpp \ + cppad/core/sparse.hpp \ + cppad/core/sparse_hes.hpp \ + cppad/core/sparse_hessian.hpp \ + cppad/core/sparse_jac.hpp \ + cppad/core/sparse_jacobian.hpp \ + cppad/core/standard_math.hpp \ + cppad/core/std_math_11.hpp \ + cppad/core/sub.hpp \ + cppad/core/sub_eq.hpp \ + cppad/core/subgraph_jac_rev.hpp \ + cppad/core/subgraph_reverse.hpp \ + cppad/core/subgraph_sparsity.hpp \ + cppad/core/tape_link.hpp \ + cppad/core/test_vector.hpp \ + cppad/core/testvector.hpp \ + cppad/core/unary_minus.hpp \ + cppad/core/unary_plus.hpp \ + cppad/core/undef.hpp \ + cppad/core/user_ad.hpp \ + cppad/core/value.hpp \ + cppad/core/var2par.hpp \ + cppad/core/vec_ad/vec_ad.hpp \ + cppad/core/zdouble.hpp \ + cppad/cppad.hpp \ + cppad/example/atomic_three/mat_mul.hpp \ + cppad/example/atomic_two/eigen_cholesky.hpp \ + cppad/example/atomic_two/eigen_mat_inv.hpp \ + cppad/example/atomic_two/eigen_mat_mul.hpp \ + cppad/example/base_adolc.hpp \ + cppad/example/code_gen_fun.hpp \ + cppad/example/cppad_eigen.hpp \ + cppad/example/eigen_plugin.hpp \ + cppad/ipopt/solve.hpp \ + cppad/ipopt/solve_callback.hpp \ + cppad/ipopt/solve_result.hpp \ + cppad/local/abs_op.hpp \ + cppad/local/acos_op.hpp \ + cppad/local/acosh_op.hpp \ + cppad/local/ad_tape.hpp \ + cppad/local/add_op.hpp \ + cppad/local/asin_op.hpp \ + cppad/local/asinh_op.hpp \ + cppad/local/atan_op.hpp \ + cppad/local/atanh_op.hpp \ + cppad/local/atom_state.hpp \ + cppad/local/atomic_index.hpp \ + cppad/local/color_general.hpp \ + cppad/local/color_symmetric.hpp \ + cppad/local/comp_op.hpp \ + cppad/local/cond_op.hpp \ + cppad/local/cos_op.hpp \ + cppad/local/cosh_op.hpp \ + cppad/local/cppad_colpack.hpp \ + cppad/local/cskip_op.hpp \ + cppad/local/csum_op.hpp \ + cppad/local/declare_ad.hpp \ + cppad/local/define.hpp \ + cppad/local/discrete_op.hpp \ + cppad/local/div_op.hpp \ + cppad/local/erf_op.hpp \ + cppad/local/exp_op.hpp \ + cppad/local/expm1_op.hpp \ + cppad/local/hash_code.hpp \ + cppad/local/independent.hpp \ + cppad/local/is_pod.hpp \ + cppad/core/graph/from_graph.hpp \ + cppad/local/graph/json_lexer.hpp \ + cppad/core/graph/to_graph.hpp \ + cppad/core/graph/cpp_graph.hpp \ + cppad/local/graph/cpp_graph_itr.hpp \ + cppad/local/graph/cpp_graph_op.hpp \ + cppad/local/graph/json_parser.hpp \ + cppad/local/graph/json_writer.hpp \ + cppad/local/load_op.hpp \ + cppad/local/log1p_op.hpp \ + cppad/local/log_op.hpp \ + cppad/local/mul_op.hpp \ + cppad/local/op.hpp \ + cppad/local/op_code_dyn.hpp \ + cppad/local/op_code_var.hpp \ + cppad/local/optimize/cexp_info.hpp \ + cppad/local/optimize/csum_op_info.hpp \ + cppad/local/optimize/csum_stacks.hpp \ + cppad/local/optimize/get_cexp_info.hpp \ + cppad/local/optimize/get_dyn_previous.hpp \ + cppad/local/optimize/get_op_previous.hpp \ + cppad/local/optimize/get_op_usage.hpp \ + cppad/local/optimize/get_par_usage.hpp \ + cppad/local/optimize/hash_code.hpp \ + cppad/local/optimize/match_op.hpp \ + cppad/local/optimize/optimize_run.hpp \ + cppad/local/optimize/record_csum.hpp \ + cppad/local/optimize/record_pv.hpp \ + cppad/local/optimize/record_vp.hpp \ + cppad/local/optimize/record_vv.hpp \ + cppad/local/optimize/size_pair.hpp \ + cppad/local/optimize/usage.hpp \ + cppad/local/parameter_op.hpp \ + cppad/local/play/addr_enum.hpp \ + cppad/local/play/atom_op_info.hpp \ + cppad/local/play/player.hpp \ + cppad/local/play/random_iterator.hpp \ + cppad/local/play/random_setup.hpp \ + cppad/local/play/sequential_iterator.hpp \ + cppad/local/play/subgraph_iterator.hpp \ + cppad/local/pod_vector.hpp \ + cppad/local/pow_op.hpp \ + cppad/local/print_op.hpp \ + cppad/local/prototype_op.hpp \ + cppad/local/record/cond_exp.hpp \ + cppad/local/record/comp_op.hpp \ + cppad/local/record/put_dyn_atomic.hpp \ + cppad/local/record/put_var_atomic.hpp \ + cppad/local/record/put_var_vecad.hpp \ + cppad/local/record/recorder.hpp \ + cppad/local/set_get_in_parallel.hpp \ + cppad/local/sign_op.hpp \ + cppad/local/sin_op.hpp \ + cppad/local/sinh_op.hpp \ + cppad/local/sparse/binary_op.hpp \ + cppad/local/sparse/internal.hpp \ + cppad/local/sparse/list_setvec.hpp \ + cppad/local/sparse/pack_setvec.hpp \ + cppad/local/sparse/svec_setvec.hpp \ + cppad/local/sparse/unary_op.hpp \ + cppad/local/sqrt_op.hpp \ + cppad/local/std_set.hpp \ + cppad/local/store_op.hpp \ + cppad/local/sub_op.hpp \ + cppad/local/subgraph/arg_variable.hpp \ + cppad/local/subgraph/entire_call.hpp \ + cppad/local/subgraph/get_rev.hpp \ + cppad/local/subgraph/info.hpp \ + cppad/local/subgraph/init_rev.hpp \ + cppad/local/subgraph/sparsity.hpp \ + cppad/local/sweep/call_atomic.hpp \ + cppad/local/sweep/dynamic.hpp \ + cppad/local/sweep/for_hes.hpp \ + cppad/local/sweep/for_jac.hpp \ + cppad/local/sweep/forward0.hpp \ + cppad/local/sweep/forward1.hpp \ + cppad/local/sweep/forward2.hpp \ + cppad/local/sweep/rev_hes.hpp \ + cppad/local/sweep/rev_jac.hpp \ + cppad/local/sweep/reverse.hpp \ + cppad/local/tan_op.hpp \ + cppad/local/tanh_op.hpp \ + cppad/local/utility/cppad_vector_itr.hpp \ + cppad/local/utility/vector_bool.hpp \ + cppad/local/zmul_op.hpp \ + cppad/speed/det_33.hpp \ + cppad/speed/det_by_lu.hpp \ + cppad/speed/det_by_minor.hpp \ + cppad/speed/det_grad_33.hpp \ + cppad/speed/det_of_minor.hpp \ + cppad/speed/mat_sum_sq.hpp \ + cppad/speed/ode_evaluate.hpp \ + cppad/speed/sparse_hes_fun.hpp \ + cppad/speed/sparse_jac_fun.hpp \ + cppad/speed/uniform_01.hpp \ + cppad/utility.hpp \ + cppad/utility/check_numeric_type.hpp \ + cppad/utility/check_simple_vector.hpp \ + cppad/utility/elapsed_seconds.hpp \ + cppad/utility/error_handler.hpp \ + cppad/utility/index_sort.hpp \ + cppad/utility/lu_factor.hpp \ + cppad/utility/lu_invert.hpp \ + cppad/utility/lu_solve.hpp \ + cppad/utility/memory_leak.hpp \ + cppad/utility/nan.hpp \ + cppad/utility/near_equal.hpp \ + cppad/utility/ode_err_control.hpp \ + cppad/utility/ode_gear.hpp \ + cppad/utility/ode_gear_control.hpp \ + cppad/utility/omp_alloc.hpp \ + cppad/utility/poly.hpp \ + cppad/utility/pow_int.hpp \ + cppad/utility/romberg_mul.hpp \ + cppad/utility/romberg_one.hpp \ + cppad/utility/rosen_34.hpp \ + cppad/utility/runge_45.hpp \ + cppad/utility/set_union.hpp \ + cppad/utility/sparse2eigen.hpp \ + cppad/utility/sparse_rc.hpp \ + cppad/utility/sparse_rcv.hpp \ + cppad/utility/speed_test.hpp \ + cppad/utility/test_boolofvoid.hpp \ + cppad/utility/thread_alloc.hpp \ + cppad/utility/time_test.hpp \ + cppad/utility/to_string.hpp \ + cppad/utility/track_new_del.hpp \ + cppad/utility/vector.hpp \ + cppad/utility/vector_bool.hpp \ + cppad/wno_conversion.hpp + +all: all-am + +.SUFFIXES: +$(srcdir)/makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign include/makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign include/makefile +makefile: $(srcdir)/makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): +install-nobase_myincludeHEADERS: $(nobase_myinclude_HEADERS) + @$(NORMAL_INSTALL) + @list='$(nobase_myinclude_HEADERS)'; test -n "$(myincludedir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(myincludedir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(myincludedir)" || exit 1; \ + fi; \ + $(am__nobase_list) | while read dir files; do \ + xfiles=; for file in $$files; do \ + if test -f "$$file"; then xfiles="$$xfiles $$file"; \ + else xfiles="$$xfiles $(srcdir)/$$file"; fi; done; \ + test -z "$$xfiles" || { \ + test "x$$dir" = x. || { \ + echo " $(MKDIR_P) '$(DESTDIR)$(myincludedir)/$$dir'"; \ + $(MKDIR_P) "$(DESTDIR)$(myincludedir)/$$dir"; }; \ + echo " $(INSTALL_HEADER) $$xfiles '$(DESTDIR)$(myincludedir)/$$dir'"; \ + $(INSTALL_HEADER) $$xfiles "$(DESTDIR)$(myincludedir)/$$dir" || exit $$?; }; \ + done + +uninstall-nobase_myincludeHEADERS: + @$(NORMAL_UNINSTALL) + @list='$(nobase_myinclude_HEADERS)'; test -n "$(myincludedir)" || list=; \ + $(am__nobase_strip_setup); files=`$(am__nobase_strip)`; \ + dir='$(DESTDIR)$(myincludedir)'; $(am__uninstall_files_from_dir) + +ID: $(am__tagged_files) + $(am__define_uniq_tagged_files); mkid -fID $$unique +tags: tags-am +TAGS: tags + +tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + set x; \ + here=`pwd`; \ + $(am__define_uniq_tagged_files); \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: ctags-am + +CTAGS: ctags +ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + $(am__define_uniq_tagged_files); \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" +cscopelist: cscopelist-am + +cscopelist-am: $(am__tagged_files) + list='$(am__tagged_files)'; \ + case "$(srcdir)" in \ + [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ + *) sdir=$(subdir)/$(srcdir) ;; \ + esac; \ + for i in $$list; do \ + if test -f "$$i"; then \ + echo "$(subdir)/$$i"; \ + else \ + echo "$$sdir/$$i"; \ + fi; \ + done >> $(top_builddir)/cscope.files + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) distdir-am + +distdir-am: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: makefile $(HEADERS) +installdirs: + for dir in "$(DESTDIR)$(myincludedir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic mostlyclean-am + +distclean: distclean-am + -rm -f makefile +distclean-am: clean-am distclean-generic distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: install-nobase_myincludeHEADERS + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-generic + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-nobase_myincludeHEADERS + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \ + cscopelist-am ctags ctags-am distclean distclean-generic \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-nobase_myincludeHEADERS install-pdf install-pdf-am \ + install-ps install-ps-am install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-generic pdf \ + pdf-am ps ps-am tags tags-am uninstall uninstall-am \ + uninstall-nobase_myincludeHEADERS + +.PRECIOUS: makefile + +# End nobase_myinclude_HEADERS (check_makefile.sh uses this comment) +# END_SORT_THIS_LINE_MINUS_2 + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/build-config/cppad/meson.build b/build-config/cppad/meson.build new file mode 100644 index 00000000..1101b549 --- /dev/null +++ b/build-config/cppad/meson.build @@ -0,0 +1,5 @@ +cppad_dep = declare_dependency( + include_directories: include_directories('include'), +) + + diff --git a/build-config/cppad/readme.md b/build-config/cppad/readme.md new file mode 100644 index 00000000..d10a83ba --- /dev/null +++ b/build-config/cppad/readme.md @@ -0,0 +1,50 @@ +# Title +CppAD: A Package for Differentiation of C++ Algorithms + +# Links + +- [docmentation](https://coin-or.github.io/CppAD/doc) + +- [News](https://coin-or.github.io/CppAD/doc/whats_new.htm) + +- [Install](https://coin-or.github.io/CppAD/doc/install.htm) + +- [Directories](https://coin-or.github.io/CppAD/doc/directory.htm) + +- [Coin-OR Download](https://www.coin-or.org/download/source/CppAD/) + + +# License +
+CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-18 Bradley M. Bell
+
+CppAD is distributed under the terms of the
+             Eclipse Public License Version 2.0.
+
+This Source Code may also be made available under the following
+Secondary License when the conditions for such availability set forth
+in the Eclipse Public License, Version 2.0 are satisfied:
+      GNU General Public License, Version 2.0 or later.
+
+ + +# Autotools +The preferred method to test and install CppAD uses cmake. +The deprecated autotools procedure can be used for this purpose, +but it will eventually be removed. +For any sub-directory *dir*, +files of the form *dir*/`makefile.am` and *dir*/`makefile.in` +are used to support the autotools test and install procedure. +In addition, +the following files, in this directory, are also for this purpose: +`compile`, +`config.guess`, +`config.sub`, +`configure.ac`, +`depcomp`, +`install-sh`, +`missing`. + + +# Copyright: +See the file `authors` in this directory. diff --git a/build-config/cppad/version b/build-config/cppad/version new file mode 100644 index 00000000..ca03bea3 --- /dev/null +++ b/build-config/cppad/version @@ -0,0 +1,2 @@ +checked out on June 19th, 2025 +Tag: stable/20210000