----------------------------------------------------- lines 11-236 of file: include/cppad/core/optimize.hpp ----------------------------------------------------- {xrst_begin optimize} {xrst_spell onetape substring } Optimize an ADFun Object Tape ############################# Syntax ****** | *f* . ``optimize`` () | *f* . ``optimize`` ( *options* ) | *flag* = *f* . ``exceed_collision_limit`` () Purpose ******* The operation sequence corresponding to an :ref:`ADFun-name` object can be very large and involve many operations; see the size functions in :ref:`fun_property-name` . The *f* . ``optimize`` procedure reduces the number of operations, and thereby the time and the memory, required to compute function and derivative values. f * The object *f* has prototype ``ADFun`` < *Base* > *f* options ******* This argument has prototype ``const std::string&`` *options* The default for *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. no_conditional_skip =================== The ``optimize`` function can create conditional skip operators to improve the speed of conditional expressions; see :ref:`CondExp@Optimize` . If the sub-string ``no_conditional_skip`` appears in *options* , conditional skip operations are not be generated. This may make the optimize routine use significantly less memory and take less time to optimize *f* . If conditional skip operations are generated, it may save a significant amount of time when using *f* for :ref:`forward-name` or :ref:`reverse-name` mode calculations; see :ref:`number_skip-name` . no_compare_op ============= If the sub-string ``no_compare_op`` appears in *options* , comparison operators will be removed from the optimized function. These operators are necessary for the :ref:`compare_change-name` functions to be meaningful. On the other hand, they are not necessary, and take extra time, when the compare_change functions are not used. no_print_for_op =============== If the sub-string ``no_compare_op`` appears in *options* , :ref:`PrintFor-name` 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. no_cumulative_sum_op ==================== If this sub-string appears, no cumulative sum operations will be generated during the optimization; see :ref:`optimize_cumulative_sum.cpp-name` . collision_limit=value ===================== If this substring appears, where *value* is a sequence of decimal digits, the optimizer's hash code collision limit will be set to *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 *value* , the more identical expressions the optimizer can recognize, but the slower the optimizer may run. The default for *value* is ``10`` . val_graph ========= If the sub-string ``val_graph`` appears in *options* , the value graph optimizer is used. This is a new (experimental) CppAD operation sequence optimizer. #. The val_graph optimizer has a much simpler implementation. #. It has better developer documentation #. It has examples and tests at the val_graph level. This makes it easy to change the val_graph optimizer. #. The optimized tape has very similar speed to the old optimizer; i.e., when the :ref:`speed_main@Global Options@onetape` option is present. For some of the :ref:`speed-name` test case the val_graph optimized tape is significantly faster. #. The val_graph optimizer take much longer to run. This is probably due to the conversion to and from a val_graph. no_conditional_skip ------------------- If the sub-string ``val_graph`` is present, the ``no_conditional_skip`` sub-string must also appear. collision_limit=value --------------------- If the sub-string ``val_graph`` is present, the ``collision_limit=value`` sub-string must **not** appear. Currently, there is no collision limit for the new optimizer. 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. Efficiency ********** If a :ref:`zero order forward` calculation is done during the construction of *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 | |tab| ``ADFun`` < *Base* > *f* ; | |tab| *f* . ``Dependent`` ( *x* , *y* ); | |tab| *f* . ``optimize`` (); instead of | |tab| ``ADFun`` < *Base* > *f* ( *x* , *y* ) | |tab| *f* . ``optimize`` (); See the discussion about :ref:`sequence constructors` . Taylor Coefficients ******************* Any Taylor coefficients in the function object are lost; i.e., :ref:`f.size_order()` after the optimization is zero. (See the discussion about efficiency above.) Speed Testing ************* You can run the CppAD :ref:`speed` tests and see the corresponding changes in number of variables and execution time. Note that there is an interaction between using :ref:`speed_main@Global Options@optimize` and :ref:`speed_main@Global Options@onetape` . If *onetape* is true and *optimize* is true, the optimized tape will be reused many times. If *onetape* is false and *optimize* is true, the tape will be re-optimized for each test. Atomic Functions **************** There are some subtitle issue with optimized :ref:`atomic-name` functions :math:`v = g(u)`: rev_sparse_jac ============== The :ref:`atomic_two_rev_sparse_jac-name` function is be used to determine which components of *u* affect the dependent variables of *f* . For each atomic operation, the current :ref:`atomic_two_option@atomic_sparsity` setting is used to determine if ``pack_sparsity_enum`` , ``bool_sparsity_enum`` , or ``set_sparsity_enum`` is used to determine dependency relations between argument and result variables. nan === If *u* [ *i* ] does not affect the value of the dependent variables for *f* , the value of *u* [ *i* ] is set to :ref:`nan-name` . Checking Optimization ********************* If :ref:`Faq@Speed@NDEBUG` is not defined, and :ref:`f.size_order()` is greater than zero, a :ref:`forward_zero-name` calculation is done using the optimized version of *f* and the results are checked to see that they are the same as before. If they are not the same, the :ref:`ErrorHandler-name` is called with a known error message related to *f* . ``optimize`` () . exceed_collision_limit ********************** If the return value *flag* is true (false), the previous call to *f* . ``optimize`` exceed the :ref:`collision_limit` . Examples ******** {xrst_comment childtable without Example instead of Contents for header} {xrst_toc_hidden 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 } .. csv-table:: :widths: auto optimize_twice.cpp,:ref:`optimize_twice.cpp-title` optimize_forward_active.cpp,:ref:`optimize_forward_active.cpp-title` optimize_reverse_active.cpp,:ref:`optimize_reverse_active.cpp-title` optimize_compare_op.cpp,:ref:`optimize_compare_op.cpp-title` optimize_print_for.cpp,:ref:`optimize_print_for.cpp-title` optimize_conditional_skip.cpp,:ref:`optimize_conditional_skip.cpp-title` optimize_nest_conditional.cpp,:ref:`optimize_nest_conditional.cpp-title` optimize_cumulative_sum.cpp,:ref:`optimize_cumulative_sum.cpp-title` {xrst_end optimize}