diff --git a/.circleci/config.yml b/.circleci/config.yml
new file mode 100644
index 000000000..6554e1f4e
--- /dev/null
+++ b/.circleci/config.yml
@@ -0,0 +1,26 @@
+# Use the latest 2.1 version of CircleCI pipeline process engine.
+# See: https://circleci.com/docs/2.0/configuration-reference
+version: 2.1
+
+# Define a job to be invoked later in a workflow.
+# See: https://circleci.com/docs/2.0/configuration-reference/#jobs
+jobs:
+  say-hello:
+    # Specify the execution environment. You can specify an image from Dockerhub or use one of our Convenience Images from CircleCI's Developer Hub.
+    # See: https://circleci.com/docs/2.0/configuration-reference/#docker-machine-macos-windows-executor
+    docker:
+      - image: cimg/base:stable
+    # Add steps to the job
+    # See: https://circleci.com/docs/2.0/configuration-reference/#steps
+    steps:
+      - checkout
+      - run:
+          name: "Say hello"
+          command: "echo Hello, World!"
+
+# Invoke jobs via workflows
+# See: https://circleci.com/docs/2.0/configuration-reference/#workflows
+workflows:
+  say-hello-workflow:
+    jobs:
+      - say-hello
diff --git a/.coin-or/projDesc.xml b/.coin-or/projDesc.xml
index 7c00a63dd..149cadaba 100644
--- a/.coin-or/projDesc.xml
+++ b/.coin-or/projDesc.xml
@@ -299,8 +299,8 @@ https://opensource.org/licenses/EPL-2.0
       <!-- appear. These must *NOT* be uncommented unless    -->
       <!-- needed.                                           -->
 
-<stableVersionNumber>20210000</stableVersionNumber>
-<releaseNumber>20210000.0</releaseNumber>
+<stableVersionNumber>20220000</stableVersionNumber>
+<releaseNumber>20220000.2</releaseNumber>
 
       </developmentStatus>
 
diff --git a/.github/workflows/github_linux.yml b/.github/workflows/github_linux.yml
new file mode 100644
index 000000000..46a92df43
--- /dev/null
+++ b/.github/workflows/github_linux.yml
@@ -0,0 +1,52 @@
+name: github_linux
+on:
+  pull_request:
+  push:
+    branches:
+      # comment out becasue not working
+      # - master
+jobs:
+  run_tests:
+    runs-on: ${{ matrix.os }}
+    strategy:
+      matrix:
+        os: [ ubuntu-latest, macos-latest ]
+    steps:
+      - name: Check out repository code
+        uses: actions/checkout@v2
+      - name: set debug_which
+        run: |
+          mkdir build
+          cd build
+          set +e
+          random_03=$(expr $RANDOM % 4)
+          set -e
+          case $random_03 in
+            0) debug_which='debug_all'
+            ;;
+            1) debug_which='debug_even'
+            ;;
+            2) debug_which='debug_odd'
+            ;;
+            3) debug_which='debug_none'
+            ;;
+          esac
+          echo "$debug_which" > debug_which
+      - name: run cmake
+        run: |
+          cd build
+          debug_which=$(cat debug_which)
+          echo "cmake -D cppad_debug_which=$debug_which" ..
+          cmake -D cppad_debug_which=$debug_which ..
+      - name: run make check
+        run: |
+          cd build
+          if which nproc >& /dev/null
+          then
+              n_job=$(nproc)
+          else
+              n_job=$(sysctl -n hw.ncpu)
+          fi
+          echo "make -j $n_job check"
+          make -j $(nproc) check
+      - run: echo "job.status = ${{ job.status }}"
diff --git a/.github/workflows/uraimo_linux.yml b/.github/workflows/uraimo_linux.yml
new file mode 100644
index 000000000..9f1ddf6d7
--- /dev/null
+++ b/.github/workflows/uraimo_linux.yml
@@ -0,0 +1,61 @@
+# see https://github.com/uraimo/run-on-arch-action
+name: uraimo_linux
+#
+# This workflow has been disabled using github actions settins; see
+# https://github.com/coin-or/CppAD/discussions/119#discussioncomment-2041373
+on:
+  pull_request:
+  push:
+    branches:
+      - master
+jobs:
+  run_tests:
+    runs-on: ubuntu-10.04
+    name: Build on ${{ matrix.distro }} ${{ matrix.arch }}
+
+    strategy:
+      matrix:
+        include:
+          - arch: ppc64le
+            distro: alpine_latest
+    steps:
+      - name: Check out repository code
+        uses: actions/checkout@v2
+      - name: Checkout uraimo
+        uses: uraimo/run-on-arch-action@v2
+      - name: set debug_which
+        run: |
+          mkdir build
+          cd build
+          set +e
+          random_03=$(expr $RANDOM % 4)
+          set -e
+          case $random_03 in
+            0) debug_which='debug_all'
+            ;;
+            1) debug_which='debug_even'
+            ;;
+            2) debug_which='debug_odd'
+            ;;
+            3) debug_which='debug_none'
+            ;;
+          esac
+          echo "$debug_which" > debug_which
+      - name: run cmake
+        run: |
+          cd build
+          debug_which=$(cat debug_which)
+          echo "cmake -D cppad_debug_which=$debug_which" ..
+          cmake -D cppad_debug_which=$debug_which ..
+      - name: run make check
+        run: |
+          cd build
+          if which nproc >& /dev/null
+          then
+              n_job=$(nproc)
+          else
+              n_job=$(sysctl -n hw.ncpu)
+          fi
+          echo "make -j $n_job check"
+          make -j $(nproc) check
+      - run: echo "job.status = ${{ job.status }}"
diff --git a/.gitignore b/.gitignore
index 2ff65b0df..466c2861c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -28,8 +28,6 @@
 # vim swap files in any directory
 *.swp
 # ----------------------------------------------------------------------------
-# junk and temp files in any directory
-junk
-junk.*
+# temp files in any directory
 temp
 temp.*
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 633ae2d1c..37d19e465 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,5 +1,5 @@
 # -----------------------------------------------------------------------------
-# CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-21 Bradley M. Bell
+# CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
 #
 # CppAD is distributed under the terms of the
 #              Eclipse Public License Version 2.0.
@@ -12,20 +12,18 @@
 # =============================================================================
 # Some constants
 # =============================================================================
-# Suppress warnging that WIN32 not defined on cygwin
-SET(CMAKE_LEGACY_CYGWIN_WIN32 0) # remove when version below >= 2.8.4
 #
 # Set the minimum required version of cmake for this project.
 # see http://www.cmake.org/pipermail/cmake/2013-January/053213.html
-CMAKE_MINIMUM_REQUIRED(VERSION 2.8.4)
+CMAKE_MINIMUM_REQUIRED(VERSION 3.0)
 #
-# https://gitlab.kitware.com/cmake/cmake/issues/17292
-if(POLICY CMP0054)
-  cmake_policy(SET CMP0054 NEW)
-endif()
+# Only interpret if() arguments as variables or keywords when unquoted.
+IF( POLICY CMP0054 )
+  CMAKE_POLICY(SET CMP0054 NEW)
+ENDIF( POLICY CMP0054 )
 #
 # cppad_version is used by version.sh to get the version number.
-SET(cppad_version "20210000.8")
+SET(cppad_version "20220327")
 SET(cppad_url          "https://coin-or.github.io/CppAD" )
 SET(cppad_description  "Differentiation of C++ Algorithms" )
 #
@@ -47,8 +45,7 @@ INCLUDE_DIRECTORIES( ${cppad_SOURCE_DIR}/include )
 # return zero status. You can set
 # CMAKE_REQUIRED_LIBRARIES, CMAKE_REQUIRED_FLAGS and CMAKE_REQUIRED_INCLUDES
 # accordingly if additional libraries or compiler flags are required.
-INCLUDE(CheckCXXSourceRuns)
-
+INCLUDE(CheckCXXSourceCompiles)
 # ============================================================================
 # Some local cmake language
 # ============================================================================
@@ -67,8 +64,8 @@ INCLUDE(cmake/command_line_arg.cmake)
 # optional_package(package description)
 INCLUDE(cmake/optional_package.cmake)
 #
-# run_source_test(source variable)
-INCLUDE(cmake/run_source_test.cmake)
+# compile_source_test(source variable)
+INCLUDE(cmake/compile_source_test.cmake)
 #
 # assert(variable)
 INCLUDE(cmake/assert.cmake)
@@ -82,23 +79,32 @@ INCLUDE(cmake/set_compile_flags.cmake)
 # pkgconfig_info(name, system)
 INCLUDE(cmake/pkgconfig_info.cmake)
 # ============================================================================
-# Check for c++11
+# Ensure c++11 support
+SET(CMAKE_REQUIRED_DEFINITIONS "")
+SET(CMAKE_REQUIRED_FLAGS       "")
+SET(CMAKE_REQUIRED_INCLUDES    "")
+SET(CMAKE_REQUIRED_LIBRARIES   "")
 SET(source "
 int main(void)
-{   if( __cplusplus < 201103 )
-        return 1;
+{   static_assert( __cplusplus >= 201103 , \"c++11 or higher required\" );
     return 0;
 }"
 )
-run_source_test("${source}" cppad_cplusplus_201100_ok )
-IF( NOT cppad_cplusplus_201100_ok  )
+compile_source_test("${source}" cplusplus_201100_ok )
+IF( NOT cplusplus_201100_ok  )
     SET(CMAKE_CXX_STANDARD 11)
     SET(CMAKE_CXX_STANDARD_REQUIRED ON)
-ENDIF( NOT cppad_cplusplus_201100_ok  )
+ENDIF( NOT cplusplus_201100_ok  )
 # =============================================================================
 # command line arguments
 # =============================================================================
-# Argumentd that are no longer used
+# Arguments that are no longer used
+#
+IF( debug_which )
+    MESSAGE(FATAL_ERROR
+        "Using debug_which, use cppad_debug_which or CMAKE_BUILD_TYPE instead"
+    )
+ENDIF( debug_which )
 #
 IF( cppad_sparse_list )
     MESSAGE(FATAL_ERROR
@@ -182,6 +188,11 @@ assert_value_in_set(cppad_testvector boost cppad eigen std)
 command_line_arg(cppad_max_num_threads 48 STRING
     "maximum number of threads that CppAD can use use"
 )
+IF( "${cppad_max_num_threads}" LESS "4" )
+    MESSAGE(FATAL_ERROR
+        "cppad_max_num_threads is not an integer greater than or equal 4"
+    )
+ENDIF( "${cppad_max_num_threads}" LESS "4" )
 #
 # cppad_tape_id_type
 command_line_arg(cppad_tape_id_type "unsigned int" STRING
@@ -194,10 +205,34 @@ command_line_arg(cppad_tape_addr_type "unsigned int" STRING
 )
 #
 # cppad_debug_which
-command_line_arg(cppad_debug_which "debug_all" STRING
-    "debug_even, debug_odd, debug_all, or debug_none"
-)
-assert_value_in_set(cppad_debug_which debug_even debug_odd debug_all debug_none)
+# CMAKE_BUILD_TYPE
+IF( NOT ${cppad_debug_which} STREQUAL "" )
+    assert_value_in_set(
+        cppad_debug_which debug_even debug_odd debug_all debug_none
+    )
+ENDIF( NOT ${cppad_debug_which} STREQUAL "" )
+IF( CMAKE_BUILD_TYPE )
+    IF( NOT ${cppad_debug_which} STREQUAL "" )
+        print_variable(CMAKE_BUILD_TYPE)
+        print_variable(cppad_debug_which)
+        MESSAGE(FATAL_ERROR
+            "Both CMAKE_BUILD_TYPE and cppad_debug_which specified"
+        )
+    ENDIF( NOT ${cppad_debug_which} STREQUAL "" )
+ELSE( CMAKE_BUILD_TYPE )
+    IF( "${cppad_debug_which}" STREQUAL debug_all)
+        SET(CMAKE_BUILD_TYPE Debug)
+    ELSEIF( "${cppad_debug_which}" STREQUAL debug_none)
+        SET(CMAKE_BUILD_TYPE Release)
+    ELSEIF( "${cppad_debug_which}" STREQUAL debug_odd)
+        SET(CMAKE_BUILD_TYPE Debug)
+    ELSEIF( "${cppad_debug_which}" STREQUAL debug_even)
+        SET(CMAKE_BUILD_TYPE Release)
+    ENDIF( "${cppad_debug_which}" STREQUAL debug_all)
+ENDIF( CMAKE_BUILD_TYPE )
+print_variable(cppad_debug_which)
+print_variable(CMAKE_BUILD_TYPE)
+MESSAGE(STATUS "make check: avialable")
 #
 # include_eigen
 # include_adolc
@@ -216,10 +251,11 @@ SET(CMAKE_INSTALL_PREFIX "${cppad_prefix}"
 # -----------------------------------------------------------------------------
 # External package information
 SET(system_include TRUE)
+SET(remove_coin_or FALSE)
 #
 # eigen
 IF( include_eigen )
-    pkgconfig_info(eigen3 ${system_include})
+    pkgconfig_info(eigen3 ${system_include} ${remove_coin_or})
     SET(eigen_LIBRARIES "${eigen3_LIBRARIES}")
     SET(cppad_has_eigen 1)
 ELSE( include_eigen )
@@ -228,7 +264,7 @@ ENDIF( include_eigen )
 #
 # adolc
 IF( include_adolc )
-    pkgconfig_info(adolc ${system_include})
+    pkgconfig_info(adolc ${system_include} ${remove_coin_or})
     SET(cppad_has_adolc 1)
 ELSE( include_adolc )
     SET(cppad_has_adolc 0)
@@ -236,31 +272,37 @@ ENDIF( include_adolc )
 #
 # ipopt
 IF( include_ipopt )
-    pkgconfig_info(ipopt ${system_include})
+    SET(remove_coin_or TRUE)
+    pkgconfig_info(ipopt ${system_include} ${remove_coin_or})
     SET(cppad_has_ipopt 1)
+    SET(remove_coin_or FALSE)
 ELSE( include_ipopt )
     SET(cppad_has_ipopt 0)
 ENDIF( include_ipopt )
 #
 # cppadcg
 IF( include_cppadcg )
+    # Assume bin/get_cppadcg.sh puts include files in this directory
+    SET(cppadcg_include_dir "${CMAKE_BINARY_DIR}/prefix/include" )
+    print_variable(cppadcg_include_dir)
+    INCLUDE_DIRECTORIES( SYSTEM ${cppadcg_include_dir})
     SET(cppad_has_cppadcg 1)
 ELSE( include_cppadcg )
     SET(cppad_has_cppadcg 0)
 ENDIF( include_cppadcg )
+MESSAGE(STATUS "prefix 1 =${prefix}" )
 #
 # colpack_prefix
 optional_package(colpack ${system_include} "colpack install prefix")
+MESSAGE(STATUS "prefix 2 =${prefix}" )
 #
 # sacado_prefix
 optional_package(sacado ${system_include} "sacado install prefix")
+MESSAGE(STATUS "prefix 3 =${prefix}" )
 #
 # fadbad_prefix
 optional_package(fadbad ${system_include} "fadbad install prefix")
 #
-# xpackage_prefix is an example package prefix that is not really used
-SET(xpackage_prefix "/usr")
-# -----------------------------------------------------------------------------
 # =============================================================================
 # cppad_lib
 # Perhaps in the future cppad_lib will depend on cmake header only flag ?
@@ -278,14 +320,14 @@ ENDIF( cppad_has_colpack )
 # automated system configuration
 # =============================================================================
 # CMAKE_CXX_FLAGS
-IF( "${debug_which}" STREQUAL "debug_all" )
+IF( "${cppad_debug_which}" STREQUAL "debug_all" )
     print_variable(CMAKE_CXX_FLAGS_DEBUG)
-ELSEIF( "${debug_which}" STREQUAL "debug_none" )
+ELSEIF( "${cppad_debug_which}" STREQUAL "debug_none" )
     print_variable(CMAKE_CXX_FLAGS_RELEASE)
-ELSE( "${debug_which}" )
+ELSE( "${cppad_debug_which}" )
     print_variable(CMAKE_CXX_FLAGS_DEBUG)
     print_variable(CMAKE_CXX_FLAGS_RELEASE)
-ENDIF( "${debug_which}" STREQUAL "debug_all" )
+ENDIF( "${cppad_debug_which}" STREQUAL "debug_all" )
 # -----------------------------------------------------------------------------
 # cppad_abs_includedir, cppad_abs_libdir, cppad_abs_datadir, cppad_abs_docdir
 #
@@ -410,7 +452,6 @@ IF( cppad_has_ipopt )
 ENDIF( cppad_has_ipopt )
 #
 ADD_CUSTOM_TARGET(check DEPENDS ${check_depends})
-MESSAGE(STATUS "make check: avialable")
 # ============================================================================
 # Copy a file to another location and modify its contents.
 # configure_file(InputFile OutputFile [COPYONLY] [ESCAPE_QUOTES] [@ONLY])
@@ -436,7 +477,7 @@ CONFIGURE_FILE(
 # During install copy all the cppad include files to
 # ${cppad_abs_includedir}/cppad
 INSTALL(
-    DIRECTORY "${CMAKE_SOURCE_DIR}/include/cppad/"
+    DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/include/cppad/"
     DESTINATION ${cppad_abs_includedir}/cppad
     FILES_MATCHING PATTERN "*.hpp" PATTERN "omh" EXCLUDE
 )
diff --git a/appveyor.yml b/appveyor.yml
index a770e184f..a66df049a 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -1,5 +1,5 @@
 # -----------------------------------------------------------------------------
-# CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
+# 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.
@@ -14,6 +14,11 @@
 platform:
   - x64
 
+# branches to build on push
+branches:
+  only:
+    - master
+
 # msys2 environment
 environment:
   matrix:
diff --git a/batch_edit.sed b/batch_edit.sed
index 91f5fde86..b108dae3a 100644
--- a/batch_edit.sed
+++ b/batch_edit.sed
@@ -17,14 +17,10 @@
 # '
 # list of files and or directories that are moved to new names
 # move_paths='
-#   cppad_lib/compiled_fun.cpp
-#   example/compiled_fun
-#   include/cppad/example/compiled_fun.hpp
 # '
 # list of sed commands that map old file and directory names to new names.
 # The characters @s, @d, @n get converted to a space, dollar sign, new line.
 # move_seds='
-#   s|compiled_fun|code_gen_fun|g
 # '
 # list of files that get edited by the extra_seds command
 # extra_files='
@@ -35,6 +31,7 @@
 # extra_seds='
 # '
 # ----------------------------------------------------------------------------
-# Put other sed commands below here and without # at start of line
-s|compiled_fun|code_gen_fun|g
-s|COMPILED_FUN|CODE_GEN_FUN|g
+# Put other sed commands below here and without # at start of linei
+s|begin atomic_mat_mul\([_.$]\)|begin atomic_four_mat_mul\1|
+s|ref atomic_mat_mul\([_.$]\)|ref atomic_four_mat_mul\1|
+s|/atomic_mat_mul/|/atomic_four_mat_mul/|
diff --git a/bin/appveyor.sh b/bin/appveyor.sh
index de198be92..91799c4ce 100755
--- a/bin/appveyor.sh
+++ b/bin/appveyor.sh
@@ -1,6 +1,6 @@
 #! /bin/bash -e
 # -----------------------------------------------------------------------------
-# CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
+# 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.
@@ -17,7 +17,7 @@ then
 fi
 if [ "$1" != 'make' ] && [ "$1" != 'test_one' ]
 then
-    echo 'usage: bin/travis.sh (make|test_one) target1 target2 ...'
+    echo 'usage: bin/appveyor.sh (make|test_one) target1 target2 ...'
     echo 'target: if make specified, is one of the available make commands'
     echo          if test_one, specified, is the path to a test file.
     exit 1
@@ -43,6 +43,10 @@ echo_eval cmake \
     -D CMAKE_CXX_COMPILER=g++ \
     ..
 # -----------------------------------------------------------------------------
+# Microsoft DLLs must be in current directory or execution path
+PATH="$PATH:$(pwd)/cppad_lib"
+# -----------------------------------------------------------------------------
+# build target1, target2, ...
 if [ "$cmd" == 'make' ]
 then
     shift
diff --git a/bin/check_addon.sh b/bin/check_addon.sh
index 0da5a086d..56f0cd0d5 100755
--- a/bin/check_addon.sh
+++ b/bin/check_addon.sh
@@ -1,6 +1,6 @@
 #! /bin/bash -e
 # -----------------------------------------------------------------------------
-# CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-18 Bradley M. Bell
+# 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.
@@ -12,7 +12,7 @@
 # -----------------------------------------------------------------------------
 if [  "$0" != 'bin/check_addon.sh' ]
 then
-    echo "bin/check_addon: must be executed from its parent directory"
+    echo "bin/check_addon.sh: must be executed from its parent directory"
     exit 1
 fi
 # -----------------------------------------------------------------------------
diff --git a/bin/check_all.sh b/bin/check_all.sh
index 58b38d336..f6c5aae10 100755
--- a/bin/check_all.sh
+++ b/bin/check_all.sh
@@ -1,6 +1,6 @@
 #! /bin/bash -e
 # -----------------------------------------------------------------------------
-# CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-21 Bradley M. Bell
+# CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
 #
 # CppAD is distributed under the terms of the
 #              Eclipse Public License Version 2.0.
@@ -72,11 +72,7 @@ echo_log_eval() {
         exit 1
     fi
     check_all_warn
-    # ignore CMake Warning about old CMAKE_MINIMUM_REQUIRED
-    count=$( sed -e '/^CMake Deprecation Warning/d' -e '/^ *$/d' \
-        $top_srcdir/check_all.warn | \
-        wc -l | sed -e 's|^\([0-9]*\) .*|\1|'
-    )
+    count=`wc -l $top_srcdir/check_all.warn | sed -e 's|^\([0-9]*\) .*|\1|'`
     if [ "$count" != '0' ]
     then
         head "$top_srcdir/check_all.warn"
@@ -206,10 +202,13 @@ then
 fi
 # ---------------------------------------------------------------------------
 # Run automated checks for the form bin/check_*.sh with a few exceptions.
-list=`ls bin/check_* | sed \
+list=$(
+    ls bin/check_* | sed \
     -e '/check_all.sh/d' \
     -e '/check_jenkins.sh/d' \
-    -e '/check_doxygen.sh/d'`
+    -e '/check_doxygen.sh/d' \
+    -e '/check_install.sh/d'
+)
 # ~/devel/check_copyright.sh not included in batch_edit branch
 for check in $list
 do
@@ -224,11 +223,13 @@ echo_log_eval cd build
 echo_log_eval rm -rf cppad-$version
 echo_log_eval tar -xzf $tarball
 echo_log_eval cd cppad-$version
+mkdir build
+echo_log_eval cp -r ../prefix build/prefix
 # -----------------------------------------------------------------------------
-# run_cmake.sh with proper prefix
-echo_log "sed -i bin/get_optional.sh -e 's|^prefix=.*|prefix=$prefix|'"
-sed -i bin/get_optional.sh -e "s|^prefix=.*|prefix=$prefix|"
+# run_cmake.sh
+# prefix is extracted from bin/get_optional
 echo_log_eval bin/run_cmake.sh \
+    --verbose \
     --profile_speed \
     $compiler \
     $standard \
@@ -326,7 +327,12 @@ else
     exit 1
 fi
 #
+# ---------------------------------------------------------------------------
+# check install
 echo_log_eval make install
+echo_log_eval cd ..
+echo_log_eval bin/check_install.sh
+# ---------------------------------------------------------------------------
 #
 echo "date >> check_all.log"
 date  | sed -e 's|^|date: |' >> $top_srcdir/check_all.log
diff --git a/bin/check_if.sh b/bin/check_if.sh
index 808b94f3b..be8f35b85 100755
--- a/bin/check_if.sh
+++ b/bin/check_if.sh
@@ -1,6 +1,6 @@
 #! /bin/bash -e
 # -----------------------------------------------------------------------------
-# CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-18 Bradley M. Bell
+# 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.
@@ -12,7 +12,7 @@
 # -----------------------------------------------------------------------------
 if [  "$0" != 'bin/check_if.sh' ]
 then
-    echo "bin/check_if: must be executed from its parent directory"
+    echo "bin/check_if.sh: must be executed from its parent directory"
     exit 1
 fi
 # -----------------------------------------------------------------------------
diff --git a/bin/check_include_file.sh b/bin/check_include_file.sh
index d9c7765e4..c1cb40716 100755
--- a/bin/check_include_file.sh
+++ b/bin/check_include_file.sh
@@ -1,6 +1,6 @@
 #! /bin/bash -e
 # -----------------------------------------------------------------------------
-# CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
+# 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.
@@ -51,8 +51,7 @@ git ls-files | sed -n -e '/include\/cppad\/.*\.hpp$/p' | \
     sed \
         -e '1,1s|^|include/cppad/configure.hpp\n|' \
         -e '1,1s|^|include/cppad/local/is_pod.hpp\n|' \
-        -e '/include\/cppad\/local\/prototype_op.hpp/d' \
-        -e '/include\/cppad\/local\/optimize\/define_prototype.hpp/d' \
+        -e '/include\/cppad\/local\/op\/prototype_op.hpp/d' \
         -e '/include\/cppad\/example\/eigen_plugin.hpp/d' | \
     sed -e 's|^include/||' | \
     sort -u > check_include_file.3.$$
diff --git a/bin/check_install.sh b/bin/check_install.sh
new file mode 100755
index 000000000..37e8ed99f
--- /dev/null
+++ b/bin/check_install.sh
@@ -0,0 +1,81 @@
+#! /bin/bash -e
+# -----------------------------------------------------------------------------
+# 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.
+# -----------------------------------------------------------------------------
+if [ $0 != 'bin/check_install.sh' ]
+then
+    echo 'bin/check_install.sh: must be executed from its parent directory'
+    exit 1
+fi
+# -----------------------------------------------------------------------------
+# bash function that echos and executes a command
+echo_eval() {
+    echo $*
+    eval $*
+}
+# -----------------------------------------------------------------------------
+# prefix
+eval `grep '^prefix=' bin/get_optional.sh`
+if [[ "$prefix" =~ ^[^/] ]]
+then
+    prefix="$(pwd)/$prefix"
+fi
+# -----------------------------------------------------------------------------
+PKG_CONFIG_PATH="$prefix/share/pkgconfig"
+LD_LIBRARY_PATH=""
+for dir in lib lib64
+do
+    PKG_CONFIG_PATH="$PKG_CONFIG_PATH:$prefix/$dir/pkgconfig"
+    LD_LIBRARY_PATH="$LD_LIBRARY_PATH:$prefix/$dir"
+done
+# dir=$(pkg-config cppad --variable pcfiledir)
+# cat $dir/cppad.pc
+# -----------------------------------------------------------------------------
+# cflags
+# libs
+cflags=$(pkg-config cppad --cflags)
+libs=$(pkg-config cppad --libs)
+# -----------------------------------------------------------------------------
+if [ ! -e build/check_install ]
+then
+    mkdir build/check_install
+fi
+cd build/check_install
+# -----------------------------------------------------------------------------
+# CppAD get_started
+cp ../../example/get_started/get_started.cpp get_started.cpp
+echo_eval g++ $cflags $libs get_started.cpp -o get_started
+echo 'CppAD: ./get_started'
+if ! ./get_started
+then
+    echo "check_install.sh: $(pwd)/get_started test failed."
+    exit 1
+fi
+# -----------------------------------------------------------------------------
+# ipopt_solve get_started
+cp ../../example/ipopt_solve/get_started.cpp get_started.cpp
+cat << EOF >> get_started.cpp
+int main(void)
+{   if( ! get_started() )
+        return 1;
+    return 0;
+}
+EOF
+echo_eval g++ $cflags $libs get_started.cpp -o get_started
+echo 'ipopt_solve: ./get_started'
+if ! ./get_started
+then
+    echo "check_install.sh: $(pwd)/get_started test failed."
+    exit 1
+fi
+# -----------------------------------------------------------------------------
+echo 'check_install.sh: OK'
+exit 0
diff --git a/bin/check_tab.sh b/bin/check_tab.sh
index 8398e30e7..fcd08a231 100755
--- a/bin/check_tab.sh
+++ b/bin/check_tab.sh
@@ -1,6 +1,6 @@
 #! /bin/bash -e
 # -----------------------------------------------------------------------------
-# CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
+# 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.
@@ -12,7 +12,7 @@
 # -----------------------------------------------------------------------------
 if [  "$0" != 'bin/check_tab.sh' ]
 then
-    echo "bin/check_tab: must be executed from its parent directory"
+    echo "bin/check_tab.sh: must be executed from its parent directory"
     exit 1
 fi
 echo "-------------------------------------------------------"
diff --git a/bin/check_tempfile.sh b/bin/check_tempfile.sh
index f50729cfe..5613c2915 100755
--- a/bin/check_tempfile.sh
+++ b/bin/check_tempfile.sh
@@ -1,6 +1,6 @@
 #! /bin/bash -e
 # -----------------------------------------------------------------------------
-# CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 Bradley M. Bell
+# CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
 #
 # CppAD is distributed under the terms of the
 #              Eclipse Public License Version 2.0.
@@ -18,8 +18,8 @@ fi
 # -----------------------------------------------------------------------------
 list=`ls | sed -n \
     -e '/^new.[0-9]*$/d' \
-    -e '/^junk.[0-9]*$/d' \
-    -e '/\/junk.[0-9]*$/d' \
+    -e '/^temp.[0-9]*$/d' \
+    -e '/\/temp.[0-9]*$/d' \
     -e '/\.[0-9]*$/p'`
 if [ "$list" != '' ]
 then
diff --git a/bin/devel.sh b/bin/devel.sh
index 346d74785..1c4eae1c0 100755
--- a/bin/devel.sh
+++ b/bin/devel.sh
@@ -23,6 +23,8 @@ version_files='
 # Names that begin with a / are relative to top source directroy.
 # All other names are relavie paths somewhere below the top source directory.
 ignore_files='
+    /.circleci/
+    /.github/workflows/
     /.gitignore
     /.coin-or/projDesc.xml
 
diff --git a/bin/get_adolc.sh b/bin/get_adolc.sh
index 0b862de82..91095ecd0 100755
--- a/bin/get_adolc.sh
+++ b/bin/get_adolc.sh
@@ -1,6 +1,6 @@
 #! /bin/bash -e
 # -----------------------------------------------------------------------------
-# CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
+# 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.
@@ -79,6 +79,14 @@ echo_eval() {
 web_page='https://github.com/coin-or/ADOL-C.git'
 cppad_dir=`pwd`
 # -----------------------------------------------------------------------------
+# n_job
+if which nproc > /dev/null
+then
+    n_job=$(nproc)
+else
+    n_job=$(sysctl -n hw.ncpu)
+fi
+# ----------------------------------------------------------------------------
 # prefix
 eval `grep '^prefix=' bin/get_optional.sh`
 if [[ "$prefix" =~ ^[^/] ]]
@@ -93,7 +101,7 @@ if [ -e "$configured_flag" ]
 then
     echo "Skipping configuration because $configured_flag exits"
     echo_eval cd external/$package.git/build
-    echo_eval make install
+    echo_eval make -j $n_job install
     echo "get_$package.sh: OK"
     exit 0
 fi
@@ -136,7 +144,7 @@ flags="--prefix=$prefix --with-colpack=$prefix --libdir=$prefix/$libdir"
 flags="$flags --enable-static --enable-shared --enable-atrig-erf"
 #
 echo_eval ../configure $flags
-echo_eval make install
+echo_eval make -j $n_job install
 # -----------------------------------------------------------------------------
 echo_eval touch $cppad_dir/$configured_flag
 echo "get_$package: OK"
diff --git a/bin/get_colpack.sh b/bin/get_colpack.sh
index b04d1a68a..c66124142 100755
--- a/bin/get_colpack.sh
+++ b/bin/get_colpack.sh
@@ -1,6 +1,6 @@
 #! /bin/bash -e
 # -----------------------------------------------------------------------------
-# CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
+# 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.
@@ -72,6 +72,24 @@ echo_eval() {
 web_page='https://github.com/CSCsw/ColPack.git'
 cppad_dir=`pwd`
 # -----------------------------------------------------------------------------
+# libtoolize is brain dead and puts these files in cppad_dir
+for file in ltmain.sh test-driver
+do
+    if [ -e $cppad_dir/$file ]
+    then
+        echo "get_colpack.sh: did not expect $file in $cppad_dir"
+        exit 1
+    fi
+done
+# -----------------------------------------------------------------------------
+# n_job
+if which nproc > /dev/null
+then
+    n_job=$(nproc)
+else
+    n_job=$(sysctl -n hw.ncpu)
+fi
+# ----------------------------------------------------------------------------
 # prefix
 eval `grep '^prefix=' bin/get_optional.sh`
 if [[ "$prefix" =~ ^[^/] ]]
@@ -86,7 +104,7 @@ if [ -e "$configured_flag" ]
 then
     echo "Skipping configuration because $configured_flag exits"
     echo_eval cd external/$package.git
-    echo_eval make install
+    echo_eval make -j $n_job install
     echo "get_$package.sh: OK"
     exit 0
 fi
@@ -133,6 +151,17 @@ echo_eval ./configure \
     $lib_type
 #
 echo_eval touch $cppad_dir/$configured_flag
-echo_eval make install
+echo_eval make -j $n_job install
+# -----------------------------------------------------------------------------
+# libtoolize is brain dead and puts these files in cppad_dir
+for file in ltmain.sh test-driver
+do
+    if [ ! -e $cppad_dir/$file ]
+    then
+        echo "get_colpack.sh: expected libtooize to create $cppad_dir/$file"
+        exit 1
+    fi
+    rm $cppad_dir/$file
+done
 # -----------------------------------------------------------------------------
 echo "get_$package: OK"
diff --git a/bin/get_cppadcg.sh b/bin/get_cppadcg.sh
index 57393918d..100be39c1 100755
--- a/bin/get_cppadcg.sh
+++ b/bin/get_cppadcg.sh
@@ -1,6 +1,6 @@
 #! /bin/bash -e
 # -----------------------------------------------------------------------------
-# CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
+# 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.
@@ -87,6 +87,14 @@ echo_eval() {
 web_page='https://github.com/joaoleal/CppADCodeGen.git'
 cppad_repo=$(pwd)
 # -----------------------------------------------------------------------------
+# n_job
+if which nproc > /dev/null
+then
+    n_job=$(nproc)
+else
+    n_job=$(sysctl -n hw.ncpu)
+fi
+# ----------------------------------------------------------------------------
 # prefix
 eval `grep '^prefix=' bin/get_optional.sh`
 if [[ "$prefix" =~ ^[^/] ]]
@@ -101,7 +109,7 @@ if [ -e "$configured_flag" ]
 then
     echo "Skipping configuration because $configured_flag exits"
     echo_eval cd external/$package.git/build
-    echo_eval make install
+    echo_eval make -j $n_job install
     echo "get_$package.sh: OK"
     exit 0
 fi
@@ -134,8 +142,7 @@ then
 fi
 echo_eval cd $package.git
 # -----------------------------------------------------------------------------
-# 2DO: get following code into CppADCodeGen
-# Must modify FindCppAD.cmake so can used git repository
+# Modify FindCppAD.cmake so can use git repository
 # version of CppAD (not yet installed).
 cat << EOF > get_cppadcg.sed
 s|IF *( *DEFINED *CPPAD_HOME *)|IF (DEFINED CPPAD_GIT_REPO)\\
@@ -195,7 +202,7 @@ echo_eval cmake \
     -D GOOGLETEST_GIT=ON \
     -D CREATE_DOXYGEN_DOC=OFF \
     ..
-echo_eval make install
+echo_eval make -j $n_job install
 # -----------------------------------------------------------------------------
 echo_eval touch $cppad_repo/$configured_flag
 echo "get_$package.sh: OK"
diff --git a/bin/get_eigen.sh b/bin/get_eigen.sh
index 205715a48..1d16f50a5 100755
--- a/bin/get_eigen.sh
+++ b/bin/get_eigen.sh
@@ -1,5 +1,5 @@
 # -----------------------------------------------------------------------------
-# CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
+# 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.
@@ -70,6 +70,14 @@ echo_eval() {
 web_page='https://gitlab.com/libeigen/$package.git'
 cppad_dir=`pwd`
 # -----------------------------------------------------------------------------
+# n_job
+if which nproc > /dev/null
+then
+    n_job=$(nproc)
+else
+    n_job=$(sysctl -n hw.ncpu)
+fi
+# ----------------------------------------------------------------------------
 # prefix
 eval `grep '^prefix=' bin/get_optional.sh`
 if [[ "$prefix" =~ ^[^/] ]]
@@ -84,7 +92,7 @@ if [ -e "$configured_flag" ]
 then
     echo "Skipping configuration because $configured_flag exits"
     echo_eval cd external/$package.git/build
-    echo_eval make install
+    echo_eval make -j $n_job install
     if [ -e $prefix/include/Eigen ]
     then
         echo_eval rm $prefix/include/Eigen
@@ -114,7 +122,7 @@ then
 fi
 echo_eval cd build
 echo_eval cmake .. -DCMAKE_INSTALL_PREFIX=$prefix
-echo_eval make install
+echo_eval make -j $n_job install
 if [ -e $prefix/include/Eigen ]
 then
     echo_eval rm $prefix/include/Eigen
diff --git a/bin/get_highlight.sh b/bin/get_highlight.sh
index 030085837..997a36c6b 100755
--- a/bin/get_highlight.sh
+++ b/bin/get_highlight.sh
@@ -15,11 +15,19 @@ echo_eval() {
 name='highlight'
 if [ "$0" != "bin/get_$name.sh" ]
 then
-    echo "get_$name.sh should be in the ./bin directory and executed using" 
+    echo "get_$name.sh should be in the ./bin directory and executed using"
     echo "bin/get_$name.sh"
     exit 1
 fi
 # -----------------------------------------------------------------------------
+# n_proc
+if which nproc >& /dev/null
+then
+    n_job=$(nproc)
+else
+    n_job=$(sysctl -n hw.ncpu)
+fi
+# -----------------------------------------------------------------------------
 if [ ! -e build ]
 then
     mkdir build
@@ -42,7 +50,7 @@ fi
 echo_eval cd build
 #
 echo_eval ../configure --prefix="$start_dir/build/prefix"
-echo_eval make install
+echo_eval make -j $n_job install
 # -----------------------------------------------------------------------------
 echo "get_$name.sh: OK"
 exit 1
diff --git a/bin/get_ipopt.sh b/bin/get_ipopt.sh
index a50fdc33c..93d9a55dc 100755
--- a/bin/get_ipopt.sh
+++ b/bin/get_ipopt.sh
@@ -1,6 +1,6 @@
 #! /bin/bash -e
 # -----------------------------------------------------------------------------
-# CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
+# 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.
@@ -77,6 +77,14 @@ echo_eval() {
 coinbrew='https://raw.githubusercontent.com/coin-or/coinbrew/master/coinbrew'
 cppad_dir=`pwd`
 # -----------------------------------------------------------------------------
+# n_proc
+if which nproc >& /dev/null
+then
+    n_job=$(nproc)
+else
+    n_job=$(sysctl -n hw.ncpu)
+fi
+# -----------------------------------------------------------------------------
 # prefix
 eval `grep '^prefix=' bin/get_optional.sh`
 if [[ "$prefix" =~ ^[^/] ]]
@@ -91,7 +99,7 @@ if [ -e "$configured_flag" ]
 then
     echo "Skipping configuration because $configured_flag exits"
     echo_eval cd external
-    ./coinbrew install Ipopt --no-prompt
+    ./coinbrew -j $n_job install Ipopt --no-prompt
     echo "get_$package.sh: OK"
     exit 0
 fi
@@ -126,9 +134,9 @@ else
     ADD_FCFLAGS=''
 fi
 # -----------------------------------------------------------------------------
-echo_eval ./coinbrew build Ipopt@$version \
+echo_eval ./coinbrew -j $n_job build Ipopt@$version \
     --prefix=$prefix --test --no-prompt --verbosity=3 $ADD_FCFLAGS
-echo_eval ./coinbrew install Ipopt@$version \
+echo_eval ./coinbrew -j $n_job install Ipopt@$version \
     --no-prompt
 # -----------------------------------------------------------------------------
 echo_eval touch $cppad_dir/$configured_flag
diff --git a/bin/get_omhelp.sh b/bin/get_omhelp.sh
index 16662ec23..910c08797 100755
--- a/bin/get_omhelp.sh
+++ b/bin/get_omhelp.sh
@@ -15,11 +15,19 @@ echo_eval() {
 name='omhelp'
 if [ "$0" != "bin/get_$name.sh" ]
 then
-    echo "get_$name.sh should be in the ./bin directory and executed using" 
+    echo "get_$name.sh should be in the ./bin directory and executed using"
     echo "bin/get_$name.sh"
     exit 1
 fi
 # -----------------------------------------------------------------------------
+# n_proc
+if which nproc >& /dev/null
+then
+    n_job=$(nproc)
+else
+    n_job=$(sysctl -n hw.ncpu)
+fi
+# -----------------------------------------------------------------------------
 if [ ! -e build ]
 then
     mkdir build
@@ -52,7 +60,7 @@ then
     echo "get_$name.sh: aborting due to cmake command warnings"
     exit 1
 fi
-echo_eval make install
+echo_eval make -j $n_job install
 # -----------------------------------------------------------------------------
 echo "get_$name.sh: OK"
 exit 1
diff --git a/bin/get_sacado.sh b/bin/get_sacado.sh
index 36fc54778..da40d83bf 100755
--- a/bin/get_sacado.sh
+++ b/bin/get_sacado.sh
@@ -1,6 +1,6 @@
 #! /bin/bash -e
 # -----------------------------------------------------------------------------
-# CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
+# 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.
@@ -74,6 +74,14 @@ echo_eval() {
 web_page='https://github.com/trilinos/Trilinos.git'
 cppad_dir=`pwd`
 # -----------------------------------------------------------------------------
+# n_job
+if which nproc > /dev/null
+then
+    n_job=$(nproc)
+else
+    n_job=$(sysctl -n hw.ncpu)
+fi
+# ----------------------------------------------------------------------------
 # prefix
 eval `grep '^prefix=' bin/get_optional.sh`
 if [[ "$prefix" =~ ^[^/] ]]
@@ -88,7 +96,7 @@ if [ -e "$configured_flag" ]
 then
     echo "Skipping configuration because $configured_flag exits"
     echo_eval cd external/trilinos.git/build
-    echo_eval make install
+    echo_eval make -j $n_job install
     echo "get_$package.sh: OK"
     exit 0
 fi
@@ -132,7 +140,7 @@ echo_eval cmake \
     -D CMAKE_INSTALL_PREFIX:PATH=$prefix \
     -D Trilinos_INSTALL_LIB_DIR=$prefix/$libdir \
     ..
-echo_eval make install
+echo_eval make -j $n_job install
 # -----------------------------------------------------------------------------
 echo_eval touch $cppad_dir/$configured_flag
 echo "get_$package.sh: OK"
diff --git a/bin/master_revert.sh b/bin/master_revert.sh
new file mode 100644
index 000000000..af6b3557e
--- /dev/null
+++ b/bin/master_revert.sh
@@ -0,0 +1,39 @@
+#! /bin/bash -e
+# -----------------------------------------------------------------------------
+# 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.
+# -----------------------------------------------------------------------------
+if [ "$0" != 'bin/master_revert.sh' ]
+then
+    echo "bin/master_revert.sh: must be executed from its parent directory"
+    exit 1
+fi
+# -----------------------------------------------------------------------------
+branch=$(git branch | sed -n '/^[*]/p' | sed -e 's/[*] *//')
+list=$(
+    git diff master $branch | \
+    sed -n -e '/^diff --git/p' | \
+    sed -e 's|^diff --git a/||' -e 's| b/|@|'
+)
+for pair in $list
+do
+    master_file=$(echo $pair | sed -e 's|@.*||')
+    branch_file=$(echo $pair | sed -e 's|[^@]*@||')
+    if [ "$master_file" == "$branch_file" ]
+    then
+        echo "reverting $master_file"
+        git show master:$master_file > $branch_file
+    else
+        echo 'skipping move of'
+        echo "$master_file -> $branch_file"
+    fi
+done
+echo 'master_revert.sh: OK'
+exit 0
diff --git a/bin/new_release.sh b/bin/new_release.sh
index 9fac6483d..862abf883 100755
--- a/bin/new_release.sh
+++ b/bin/new_release.sh
@@ -1,6 +1,6 @@
 #! /bin/bash -e
 # -----------------------------------------------------------------------------
-# CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
+# CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
 #
 # CppAD is distributed under the terms of the
 #              Eclipse Public License Version 2.0.
@@ -10,8 +10,8 @@
 # in the Eclipse Public License, Version 2.0 are satisfied:
 #       GNU General Public License, Version 2.0 or later.
 # -----------------------------------------------------------------------------
-stable_version='20210000' # date at which this stable branch started
-release='1'               # first release for each stable version is 0
+stable_version='20220000' # date at which this stable branch started
+release='2'               # first release for each stable version is 0
 # -----------------------------------------------------------------------------
 # bash function that echos and executes a command
 echo_eval() {
@@ -145,12 +145,11 @@ if [ "$ok" != 'yes' ]
 then
 cat << EOF
 bin/new_release.sh: version number is not correct in $stable_branch.
-Use the following commands in $stable_branch to fix it ?
+Currently in $stable_branch branch, use following to fix it ?
     git fetch
     version.sh set $stable_version.$release
     version.sh copy
     version.sh check
-    bin/autotools.sh automake
     Then check the chages to the $stable_branch branch and commit
 EOF
     exit 1
diff --git a/bin/run_cmake.sh b/bin/run_cmake.sh
index a6bb2308c..29783a481 100755
--- a/bin/run_cmake.sh
+++ b/bin/run_cmake.sh
@@ -15,14 +15,13 @@ then
     echo "bin/run_cmake.sh: must be executed from its parent directory"
     exit 1
 fi
-# prefix
 # -----------------------------------------------------------------------------
 # bash function that echos and executes a command
 echo_eval() {
     echo $*
     eval $*
 }
-#
+# -----------------------------------------------------------------------------
 # prefix
 eval `grep '^prefix=' bin/get_optional.sh`
 if [[ "$prefix" =~ ^[^/] ]]
@@ -30,7 +29,7 @@ then
     prefix="$(pwd)/$prefix"
 fi
 echo "prefix=$prefix"
-#
+# -----------------------------------------------------------------------------
 # PKG_CONFIG_PATH
 PKG_CONFIG_PATH="$prefix/lib64/pkgconfig:$prefix/lib/pkgconfig"
 PKG_CONFIG_PATH="$prefix/share/pkgconfig:$PKG_CONFIG_PATH"
@@ -71,6 +70,7 @@ usage: bin/run_cmake.sh: \\
     [--no_fadbad] \\
     [--no_cppadcg] \\
     [--no_sacado] \\
+    [--no_optional] \\
     [--no_documentation] \\
     [--<package>_vector] \\
     [--debug_<which>]
@@ -135,6 +135,17 @@ EOF
         yes_sacado='no'
         ;;
 
+        --no_optional)
+        yes_adolc='no'
+        yes_colpack='no'
+        yes_eigen='no'
+        yes_ipopt='no'
+        yes_cppadcg='no'
+        yes_fadbad='no'
+        yes_sacado='no'
+        testvector='cppad'
+        ;;
+
         --no_documentation)
         yes_documentation='no'
         ;;
diff --git a/bin/test_one.sh.in b/bin/test_one.sh.in
index 1196016b2..afa4a0bcf 100755
--- a/bin/test_one.sh.in
+++ b/bin/test_one.sh.in
@@ -1,6 +1,6 @@
 #! /bin/bash -e
 # -----------------------------------------------------------------------------
-# CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
+# CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
 #
 # CppAD is distributed under the terms of the
 #              Eclipse Public License Version 2.0.
@@ -248,8 +248,10 @@ if [ -s test_one.warn ]
 then
     cat test_one.warn
     echo 'test_one.sh: unexpected warnings: see  test_one.warn, test_one.err'
+    echo "export LD_LIBRARY_PATH=$LD_LIBRARY_PATH"
     exit 1
 fi
 # --------------------------------------------------------------------------
 echo 'test_one.sh: OK'
+echo "export LD_LIBRARY_PATH=$LD_LIBRARY_PATH"
 exit 0
diff --git a/bin/trace.sh b/bin/trace.sh
index 296b473bb..c99aa6d7b 100755
--- a/bin/trace.sh
+++ b/bin/trace.sh
@@ -1,6 +1,6 @@
 #! /bin/bash -e
 # -----------------------------------------------------------------------------
-# CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-18 Bradley M. Bell
+# 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.
@@ -15,24 +15,27 @@ then
     echo "bin/trace.sh: must be executed from its parent directory"
     exit 1
 fi
-name="$1"
+file="include/cppad/local/sweep/$1"
 option="$2"
-file="include/cppad/local/sweep/$name.hpp"
 #
 ok='yes'
 if [ "$option" != '0' ] && [ "$option" != '1' ]
 then
     ok='no'
 fi
-echo "grep '_TRACE [01]' $file"
-if ! grep '_TRACE [01]' $file > /dev/null
+if [ "$ok" == 'yes' ]
 then
-    ok='no'
+    if ! grep '_TRACE [01]' $file > /dev/null
+    then
+        ok='no'
+    fi
 fi
 if [ "$ok" == 'no' ]
 then
-    echo 'usage: bin/trace.sh name (0|1)'
-    echo 'name: include/cppad/local/sweep/name.hpp defined *_TRACE as 0 or 1'
+    echo 'usage: bin/trace.sh file (0|1)'
+    echo 'Sets trace in file to off (0) or on (1) where the file is one of:'
+    grep -l '_TRACE [01]' include/cppad/local/sweep/*.hpp | \
+        sed -e 's|^include/cppad/local/sweep/||'
     exit 1
 fi
 old=`grep '_TRACE [01]' $file`
diff --git a/cmake/compile_source_test.cmake b/cmake/compile_source_test.cmake
new file mode 100644
index 000000000..eea0acbb4
--- /dev/null
+++ b/cmake/compile_source_test.cmake
@@ -0,0 +1,58 @@
+# -----------------------------------------------------------------------------
+# 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.
+# -----------------------------------------------------------------------------
+# compile_source_test(source variable)
+#
+# source: (in)
+# contains the source for the program that will be compiled and linked.
+#
+# variable: (out)
+# This variable must not be defined when this macro is called.
+# Upon return, the value of this variable is 1 (0) if the program compiles
+# and links (does not compile and link).
+#
+# CMAKE_REQUIRED_name (in)
+# For name equal to DEFINITIONS, INCLUDES, LIBRARIES, FLAGS, the variable
+# CMAKE_REQUIRED_name is an input to routine; see CHECK_CXX_SOURCE_COMPILES
+# documentation.
+#
+MACRO(compile_source_test source variable)
+    #
+    # check that variable is not yet defined
+    IF( DEFINED ${variable} )
+        MESSAGE(FATAL_ERROR
+            "compile_source_test: ${variable} is defined before expected"
+        )
+    ENDIF( DEFINED ${variable} )
+    #
+    IF( DEFINED compiles_source_test_result)
+        UNSET(compiles_source_test_result)
+    ENDIF( DEFINED compiles_source_test_result )
+    #
+    # check that source codee compiles
+    CHECK_CXX_SOURCE_COMPILES("${source}" compiles_source_test_result )
+    #
+    # change result varialbe to 0 (1) for fail (succeed).
+    IF( compiles_source_test_result )
+        SET(${variable} 1)
+    ELSE( compiles_source_test_result )
+        SET(${variable} 0)
+    ENDIF( compiles_source_test_result )
+    #
+    # check that varialbe is defined
+    IF( NOT DEFINED ${variable} )
+        MESSAGE(FATAL_ERROR
+            "compile_source_test: error in CMake script."
+        )
+    ENDIF( NOT DEFINED ${variable} )
+    #
+    MESSAGE(STATUS "${variable} = ${${variable}}" )
+ENDMACRO( compile_source_test )
diff --git a/cmake/optional_package.cmake b/cmake/optional_package.cmake
index 2d7ea3969..f967a62a2 100644
--- a/cmake/optional_package.cmake
+++ b/cmake/optional_package.cmake
@@ -1,5 +1,5 @@
 # -----------------------------------------------------------------------------
-# CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-17 Bradley M. Bell
+# CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
 #
 # CppAD is distributed under the terms of the
 #              Eclipse Public License Version 2.0.
@@ -40,30 +40,30 @@ MACRO(optional_package package system_include description)
     SET(prefix_variable ${package}_prefix)
     SET(cppad_has_${package} 0)
     SET(${prefix_variable} NOTFOUND CACHE PATH "${description}")
-    SET(prefix ${${prefix_variable}} )
-    MESSAGE(STATUS "${prefix_variable} = ${prefix}")
-    IF ( prefix )
+    SET(prefix_value ${${prefix_variable}} )
+    MESSAGE(STATUS "${prefix_variable} = ${prefix_value}")
+    IF ( prefix_value )
         SET(cppad_has_${package} 1)
         #
         # List of preprocessor include file search directories
         FOREACH(dir ${cmake_install_includedirs})
-            IF(IS_DIRECTORY ${prefix}/${dir} )
+            IF(IS_DIRECTORY ${prefix_value}/${dir} )
                 IF( ${system_include} )
-                    INCLUDE_DIRECTORIES( SYSTEM ${prefix}/${dir} )
-                    MESSAGE(STATUS "    Found SYSTEM ${prefix}/${dir}")
+                    INCLUDE_DIRECTORIES( SYSTEM ${prefix_value}/${dir} )
+                    MESSAGE(STATUS "    Found SYSTEM ${prefix_value}/${dir}")
                 ELSE( ${system_include} )
-                    INCLUDE_DIRECTORIES( ${prefix}/${dir} )
-                    MESSAGE(STATUS "    Found ${prefix}/${dir}")
+                    INCLUDE_DIRECTORIES( ${prefix_value}/${dir} )
+                    MESSAGE(STATUS "    Found ${prefix_value}/${dir}")
                 ENDIF( ${system_include} )
-            ENDIF(IS_DIRECTORY ${prefix}/${dir} )
+            ENDIF(IS_DIRECTORY ${prefix_value}/${dir} )
         ENDFOREACH(dir)
         # Paths in which the linker will search for libraries,
         # only applies to targets created after it is called
         FOREACH(dir ${cmake_install_libdirs})
-            IF(IS_DIRECTORY ${prefix}/${dir} )
-                LINK_DIRECTORIES( ${prefix}/${dir} )
-                MESSAGE(STATUS "    Found ${prefix}/${dir}")
-            ENDIF(IS_DIRECTORY ${prefix}/${dir} )
+            IF(IS_DIRECTORY ${prefix_value}/${dir} )
+                LINK_DIRECTORIES( ${prefix_value}/${dir} )
+                MESSAGE(STATUS "    Found ${prefix_value}/${dir}")
+            ENDIF(IS_DIRECTORY ${prefix_value}/${dir} )
         ENDFOREACH(dir)
-    ENDIF ( prefix )
+    ENDIF ( prefix_value )
 ENDMACRO(optional_package)
diff --git a/cmake/pkgconfig_info.cmake b/cmake/pkgconfig_info.cmake
index 519a0f24f..ec7fa8a7b 100644
--- a/cmake/pkgconfig_info.cmake
+++ b/cmake/pkgconfig_info.cmake
@@ -1,5 +1,5 @@
 # -----------------------------------------------------------------------------
-# CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
+# 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.
@@ -9,12 +9,15 @@
 # in the Eclipse Public License, Version 2.0 are satisfied:
 #       GNU General Public License, Version 2.0 or later.
 # -----------------------------------------------------------------------------
-# pkgconfig_info(name system)
+# pkgconfig_info(name system coin_or)
 #
 # Inputs:
-# name:   is the name of the package config file without the .pc extension
-# system: if true (false) include directory will (will not) be
-#         treated like a system directory; i.e., no warnings.
+# name:    is the name of the package config file without the .pc extension
+# system:  if true (false) include directories will (will not) be
+#          treated like a system directory; i.e., no warnings.
+# coin_or: if true (false) the string '/coin-or' at the end of an include
+#          include directory is (is not) removed because CppAD explicitly
+#           includes it in include commands.
 #
 # Outputs:
 # ${name}_LIBRARIES:     list of libraries necessary to use this package.
@@ -27,7 +30,7 @@
 # Assumptions:
 # FIND_PACKAGE(PkgConfig) was successful
 # It is a fatal error if ${name}.pc is not in PKG_CONFIG_PATH
-MACRO(pkgconfig_info name system)
+MACRO(pkgconfig_info name system coin_or)
     IF( NOT PKG_CONFIG_FOUND )
         FIND_PACKAGE(PkgConfig REQUIRED)
     ENDIF( NOT PKG_CONFIG_FOUND )
@@ -41,11 +44,16 @@ MACRO(pkgconfig_info name system)
         )
     ENDIF( ${name}_FOUND )
     #
+    IF( ${coin_or} )
+        STRING(REPLACE "/coin-or" "" include_dirs "${${name}_INCLUDE_DIRS}" )
+        SET(${name}_INCLUDE_DIRS "${include_dirs}")
+    ENDIF( ${coin_or} )
+    #
     # INLCUDE_DIRECTORIES
     IF( ${system} )
-        INCLUDE_DIRECTORIES( SYSTEM ${${name}_INCLUDE_DIRS} )
+        INCLUDE_DIRECTORIES( SYSTEM ${include_dirs} )
     ELSE( ${system}  )
-        INCLUDE_DIRECTORIES( ${${name}_INCLUDE_DIRS} )
+        INCLUDE_DIRECTORIES( ${include_dirs} )
     ENDIF( ${system} )
     #
     # LINK_DIRECTORIES
diff --git a/cmake/run_source_test.cmake b/cmake/run_source_test.cmake
index 2f03b0f1f..378276aef 100644
--- a/cmake/run_source_test.cmake
+++ b/cmake/run_source_test.cmake
@@ -34,7 +34,7 @@ MACRO(run_source_test source variable)
     SET(CMAKE_REQUIRED_INCLUDES    "" )
     SET(CMAKE_REQUIRED_LIBRARIES   "" )
     IF( cppad_cxx_flags )
-        SET(CMAKE_REQUIRED_FLAGS   "${cppad_cxx_flags}" )
+        SET(CMAKE_REQUIRED_FLAGS   "${cppad_cxx_flags} ${CMAKE_CXX_FLAGS}" )
     ELSE( cppad_cxx_flags )
         SET(CMAKE_REQUIRED_FLAGS   "" )
     ENDIF( cppad_cxx_flags )
diff --git a/cmake/set_compile_flags.cmake b/cmake/set_compile_flags.cmake
index e526603df..2fbf9b7b3 100644
--- a/cmake/set_compile_flags.cmake
+++ b/cmake/set_compile_flags.cmake
@@ -1,5 +1,5 @@
 # -----------------------------------------------------------------------------
-# CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-17 Bradley M. Bell
+# 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.
@@ -26,11 +26,8 @@
 # The files with an odd (even) index in source_list have debug (release) flags.
 # In addition the compiler flag -DCPPAD_DEBUG_AND_RELEASE is added.
 #
-# Case debug_all:
-# All the files have debug flags.
-#
-# Case debug_none:
-# All the the files have release flags.
+# Case debug_all, debug_none, or empty string:
+# The debug and release flags are not set by this routine.
 #
 # source_list: (in)
 # is a list of source files that get set to have debug or release
@@ -50,18 +47,14 @@ FUNCTION(set_compile_flags program_name debug_which source_list)
     ELSEIF( "${debug_which}" STREQUAL "debug_odd" )
         SET(alternate TRUE)
         SET(count_mod_2 1)
-    ELSEIF( "${debug_which}" STREQUAL "debug_all" )
-        SET(alternate FALSE)
-        SET_SOURCE_FILES_PROPERTIES(
-            ${source_list} PROPERTIES COMPILE_FLAGS "${debug_flags}"
-        )
-    ELSEIF( "${debug_which}" STREQUAL "debug_none" )
-        SET(alternate FALSE)
-        SET_SOURCE_FILES_PROPERTIES(
-            ${source_list} PROPERTIES COMPILE_FLAGS "${release_flags}"
-        )
     ELSE( "${debug_which}" )
-        MESSAGE(FATAL_ERROR "cmake error: debug_which = ${debug_which}")
+        SET(alternate FALSE)
+        IF( NOT "${cppad_cxx_flags}" STREQUAL "" )
+            SET(alternate FALSE)
+            SET_SOURCE_FILES_PROPERTIES(
+                ${source_list} PROPERTIES COMPILE_FLAGS "${cppad_cxx_flags}"
+            )
+        ENDIF( NOT "${cppad_cxx_flags}" STREQUAL "" )
     ENDIF( "${debug_which}" STREQUAL "debug_even" )
     #
     IF( alternate )
diff --git a/configure b/configure
index 048ef6603..b49e54793 100755
--- a/configure
+++ b/configure
@@ -1,6 +1,6 @@
 #! /bin/sh
 # Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.69 for cppad 20210000.8.
+# Generated by GNU Autoconf 2.69 for cppad 20220327.
 #
 # Report bugs to <cppad@list.coin-or.org>.
 #
@@ -579,8 +579,8 @@ MAKEFLAGS=
 # Identity of this package.
 PACKAGE_NAME='cppad'
 PACKAGE_TARNAME='cppad'
-PACKAGE_VERSION='20210000.8'
-PACKAGE_STRING='cppad 20210000.8'
+PACKAGE_VERSION='20220327'
+PACKAGE_STRING='cppad 20220327'
 PACKAGE_BUGREPORT='cppad@list.coin-or.org'
 PACKAGE_URL=''
 
@@ -629,7 +629,6 @@ RANLIB
 cppad_has_gettimeofday
 cppad_cppadvector
 compiler_has_conversion_warn
-cppad_cplusplus_201100_ok
 cppad_has_tmpnam_s
 cppad_has_mkstemp
 cppad_has_colpack
@@ -755,6 +754,7 @@ infodir
 docdir
 oldincludedir
 includedir
+runstatedir
 localstatedir
 sharedstatedir
 sysconfdir
@@ -850,6 +850,7 @@ datadir='${datarootdir}'
 sysconfdir='${prefix}/etc'
 sharedstatedir='${prefix}/com'
 localstatedir='${prefix}/var'
+runstatedir='${localstatedir}/run'
 includedir='${prefix}/include'
 oldincludedir='/usr/include'
 docdir='${datarootdir}/doc/${PACKAGE_TARNAME}'
@@ -1102,6 +1103,15 @@ do
   | -silent | --silent | --silen | --sile | --sil)
     silent=yes ;;
 
+  -runstatedir | --runstatedir | --runstatedi | --runstated \
+  | --runstate | --runstat | --runsta | --runst | --runs \
+  | --run | --ru | --r)
+    ac_prev=runstatedir ;;
+  -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \
+  | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \
+  | --run=* | --ru=* | --r=*)
+    runstatedir=$ac_optarg ;;
+
   -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
     ac_prev=sbindir ;;
   -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
@@ -1239,7 +1249,7 @@ fi
 for ac_var in	exec_prefix prefix bindir sbindir libexecdir datarootdir \
 		datadir sysconfdir sharedstatedir localstatedir includedir \
 		oldincludedir docdir infodir htmldir dvidir pdfdir psdir \
-		libdir localedir mandir
+		libdir localedir mandir runstatedir
 do
   eval ac_val=\$$ac_var
   # Remove trailing slashes.
@@ -1352,7 +1362,7 @@ if test "$ac_init_help" = "long"; then
   # Omit some internal or obsolete options to make the list less imposing.
   # This message is too long to be a string in the A/UX 3.1 sh.
   cat <<_ACEOF
-\`configure' configures cppad 20210000.8 to adapt to many kinds of systems.
+\`configure' configures cppad 20220327 to adapt to many kinds of systems.
 
 Usage: $0 [OPTION]... [VAR=VALUE]...
 
@@ -1392,6 +1402,7 @@ Fine tuning of the installation directories:
   --sysconfdir=DIR        read-only single-machine data [PREFIX/etc]
   --sharedstatedir=DIR    modifiable architecture-independent data [PREFIX/com]
   --localstatedir=DIR     modifiable single-machine data [PREFIX/var]
+  --runstatedir=DIR       modifiable per-process data [LOCALSTATEDIR/run]
   --libdir=DIR            object code libraries [EPREFIX/lib]
   --includedir=DIR        C header files [PREFIX/include]
   --oldincludedir=DIR     C header files for non-gcc [/usr/include]
@@ -1422,7 +1433,7 @@ fi
 
 if test -n "$ac_init_help"; then
   case $ac_init_help in
-     short | recursive ) echo "Configuration of cppad 20210000.8:";;
+     short | recursive ) echo "Configuration of cppad 20220327:";;
    esac
   cat <<\_ACEOF
 
@@ -1544,7 +1555,7 @@ fi
 test -n "$ac_init_help" && exit $ac_status
 if $ac_init_version; then
   cat <<\_ACEOF
-cppad configure 20210000.8
+cppad configure 20220327
 generated by GNU Autoconf 2.69
 
 Copyright (C) 2012 Free Software Foundation, Inc.
@@ -1917,7 +1928,7 @@ cat >config.log <<_ACEOF
 This file contains any messages produced by compilers while
 running configure, to aid debugging if configure makes a mistake.
 
-It was created by cppad $as_me 20210000.8, which was
+It was created by cppad $as_me 20220327, which was
 generated by GNU Autoconf 2.69.  Invocation command line was
 
   $ $0 $@
@@ -2807,7 +2818,7 @@ fi
 
 # Define the identity of the package.
  PACKAGE='cppad'
- VERSION='20210000.8'
+ VERSION='20220327'
 
 
 cat >>confdefs.h <<_ACEOF
@@ -5762,8 +5773,6 @@ cppad_has_mkstemp=0
 
 cppad_has_tmpnam_s=0
 
-cppad_cplusplus_201100_ok=0
-
 compiler_has_conversion_warn=0
 
 
@@ -7009,7 +7018,7 @@ eigen_prefix=${EIGEN_DIR}
 
 ipopt_prefix=${IPOPT_DIR}
 
-ac_config_files="$ac_config_files include/cppad/configure.hpp cppad_ipopt/example/test.sh cppad_ipopt/speed/test.sh cppad_ipopt/test/test.sh example/ipopt_solve/test.sh pkgconfig/cppad.pc pkgconfig/cppad-uninstalled.pc makefile cppad_ipopt/src/makefile cppad_ipopt/example/makefile cppad_ipopt/speed/makefile cppad_ipopt/test/makefile cppad_lib/makefile example/general/makefile example/abs_normal/makefile example/atomic_two/makefile example/atomic_three/makefile example/chkpoint_two/makefile example/ipopt_solve/makefile example/optimize/makefile example/sparse/makefile example/utility/makefile example/get_started/makefile include/makefile introduction/makefile example/multi_thread/makefile example/print_for/makefile speed/adolc/makefile speed/cppad/makefile speed/double/makefile speed/example/makefile speed/fadbad/makefile speed/sacado/makefile speed/src/makefile test_more/compare_c/makefile test_more/general/makefile test_more/deprecated/makefile test_more/deprecated/atomic_two/makefile test_more/deprecated/chkpoint_one/makefile"
+ac_config_files="$ac_config_files include/cppad/configure.hpp cppad_ipopt/example/test.sh cppad_ipopt/speed/test.sh cppad_ipopt/test/test.sh example/ipopt_solve/test.sh pkgconfig/cppad.pc pkgconfig/cppad-uninstalled.pc makefile cppad_ipopt/src/makefile cppad_ipopt/example/makefile cppad_ipopt/speed/makefile cppad_ipopt/test/makefile cppad_lib/makefile example/general/makefile example/abs_normal/makefile example/atomic_two/makefile example/atomic_three/makefile example/chkpoint_two/makefile example/ipopt_solve/makefile example/optimize/makefile example/sparse/makefile example/utility/makefile example/get_started/makefile include/makefile introduction/makefile example/multi_thread/makefile example/print_for/makefile speed/adolc/makefile speed/cppad/makefile speed/double/makefile speed/example/makefile speed/fadbad/makefile speed/sacado/makefile speed/src/makefile speed/xpackage/makefile test_more/compare_c/makefile test_more/general/makefile test_more/deprecated/makefile test_more/deprecated/atomic_two/makefile test_more/deprecated/chkpoint_one/makefile"
 
 
 ac_config_commands="$ac_config_commands configure.hpp"
@@ -7649,7 +7658,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
 # report actual input values of CONFIG_FILES etc. instead of their
 # values after options handling.
 ac_log="
-This file was extended by cppad $as_me 20210000.8, which was
+This file was extended by cppad $as_me 20220327, which was
 generated by GNU Autoconf 2.69.  Invocation command line was
 
   CONFIG_FILES    = $CONFIG_FILES
@@ -7706,7 +7715,7 @@ _ACEOF
 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
 ac_cs_version="\\
-cppad config.status 20210000.8
+cppad config.status 20220327
 configured by $0, generated by GNU Autoconf 2.69,
   with options \\"\$ac_cs_config\\"
 
@@ -7869,6 +7878,7 @@ do
     "speed/fadbad/makefile") CONFIG_FILES="$CONFIG_FILES speed/fadbad/makefile" ;;
     "speed/sacado/makefile") CONFIG_FILES="$CONFIG_FILES speed/sacado/makefile" ;;
     "speed/src/makefile") CONFIG_FILES="$CONFIG_FILES speed/src/makefile" ;;
+    "speed/xpackage/makefile") CONFIG_FILES="$CONFIG_FILES speed/xpackage/makefile" ;;
     "test_more/compare_c/makefile") CONFIG_FILES="$CONFIG_FILES test_more/compare_c/makefile" ;;
     "test_more/general/makefile") CONFIG_FILES="$CONFIG_FILES test_more/general/makefile" ;;
     "test_more/deprecated/makefile") CONFIG_FILES="$CONFIG_FILES test_more/deprecated/makefile" ;;
diff --git a/configure.ac b/configure.ac
index 87cd3a6b8..a3f75dec2 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,5 +1,5 @@
 # -----------------------------------------------------------------------------
-# CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-21 Bradley M. Bell
+# CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
 #
 # CppAD is distributed under the terms of the
 #              Eclipse Public License Version 2.0.
@@ -11,7 +11,7 @@
 # -----------------------------------------------------------------------------
 dnl Process this file with autoconf to produce a configure script.
 dnl   package   version              bug-report
-AC_INIT([cppad], [20210000.8], [cppad@list.coin-or.org])
+AC_INIT([cppad], [20220327], [cppad@list.coin-or.org])
 AM_SILENT_RULES([no])
 
 dnl By defalut disable maintainer mode when running configure;
@@ -361,7 +361,6 @@ AC_SUBST(cppad_cxx_flags, "")
 AC_SUBST(cppad_has_colpack, 0)
 AC_SUBST(cppad_has_mkstemp, 0)
 AC_SUBST(cppad_has_tmpnam_s, 0)
-AC_SUBST(cppad_cplusplus_201100_ok, 0)
 AC_SUBST(compiler_has_conversion_warn, 0)
 
 dnl -------------------------------------------------------------------------
@@ -698,6 +697,7 @@ AC_CONFIG_FILES([
     speed/fadbad/makefile
     speed/sacado/makefile
     speed/src/makefile
+    speed/xpackage/makefile
     test_more/compare_c/makefile
     test_more/general/makefile
     test_more/deprecated/makefile
diff --git a/cppad_ipopt/example/makefile.in b/cppad_ipopt/example/makefile.in
index 515128dd9..98cb7201d 100644
--- a/cppad_ipopt/example/makefile.in
+++ b/cppad_ipopt/example/makefile.in
@@ -289,7 +289,6 @@ 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@
@@ -344,6 +343,7 @@ pdfdir = @pdfdir@
 prefix = @prefix@
 program_transform_name = @program_transform_name@
 psdir = @psdir@
+runstatedir = @runstatedir@
 sbindir = @sbindir@
 sharedstatedir = @sharedstatedir@
 srcdir = @srcdir@
diff --git a/cppad_ipopt/example/ode_run.hpp b/cppad_ipopt/example/ode_run.hpp
index 15b08a70b..e11f3da12 100644
--- a/cppad_ipopt/example/ode_run.hpp
+++ b/cppad_ipopt/example/ode_run.hpp
@@ -1,7 +1,7 @@
 # ifndef CPPAD_CPPAD_IPOPT_EXAMPLE_ODE_RUN_HPP
 # define CPPAD_CPPAD_IPOPT_EXAMPLE_ODE_RUN_HPP
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
+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.
@@ -36,7 +36,7 @@ void ipopt_ode_case(
     bool  retape        ,
     const SizeVector& N ,
     NumberVector&     x )
-{   bool ok = true;
+{
     size_t i, j;
 
     // compute the partial sums of the number of grid points
@@ -103,13 +103,22 @@ void ipopt_ode_case(
     app->Options()-> SetStringValue( "derivative_test", "second-order");
     app->Options()-> SetNumericValue( "point_perturbation_radius", 0.);
 
+# ifndef NDEBUG
+    bool ok = true;
+    //
     // Initialize the application and process the options
     Ipopt::ApplicationReturnStatus status = app->Initialize();
     ok    &= status == Ipopt::Solve_Succeeded;
-
+    //
     // Run the application
     status = app->OptimizeTNLP(cppad_nlp);
     ok    &= status == Ipopt::Solve_Succeeded;
+    //
+    assert(ok);
+# else
+    app->Initialize();
+    app->OptimizeTNLP(cppad_nlp);
+# endif
 
     // return the solution
     x.resize( solution.x.size() );
diff --git a/cppad_ipopt/speed/makefile.in b/cppad_ipopt/speed/makefile.in
index 963d4923e..1fa3eba52 100644
--- a/cppad_ipopt/speed/makefile.in
+++ b/cppad_ipopt/speed/makefile.in
@@ -293,7 +293,6 @@ 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@
@@ -348,6 +347,7 @@ pdfdir = @pdfdir@
 prefix = @prefix@
 program_transform_name = @program_transform_name@
 psdir = @psdir@
+runstatedir = @runstatedir@
 sbindir = @sbindir@
 sharedstatedir = @sharedstatedir@
 srcdir = @srcdir@
diff --git a/cppad_ipopt/src/makefile.in b/cppad_ipopt/src/makefile.in
index 4d2dd896d..3debcbe3f 100644
--- a/cppad_ipopt/src/makefile.in
+++ b/cppad_ipopt/src/makefile.in
@@ -326,7 +326,6 @@ 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@
@@ -381,6 +380,7 @@ pdfdir = @pdfdir@
 prefix = @prefix@
 program_transform_name = @program_transform_name@
 psdir = @psdir@
+runstatedir = @runstatedir@
 sbindir = @sbindir@
 sharedstatedir = @sharedstatedir@
 srcdir = @srcdir@
diff --git a/cppad_ipopt/test/makefile.in b/cppad_ipopt/test/makefile.in
index 648ce731f..e164897bb 100644
--- a/cppad_ipopt/test/makefile.in
+++ b/cppad_ipopt/test/makefile.in
@@ -277,7 +277,6 @@ 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@
@@ -332,6 +331,7 @@ pdfdir = @pdfdir@
 prefix = @prefix@
 program_transform_name = @program_transform_name@
 psdir = @psdir@
+runstatedir = @runstatedir@
 sbindir = @sbindir@
 sharedstatedir = @sharedstatedir@
 srcdir = @srcdir@
diff --git a/cppad_lib/CMakeLists.txt b/cppad_lib/CMakeLists.txt
index d0e1f6f05..4d629fc67 100644
--- a/cppad_lib/CMakeLists.txt
+++ b/cppad_lib/CMakeLists.txt
@@ -1,5 +1,5 @@
 # -----------------------------------------------------------------------------
-# CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
+# 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.
@@ -47,10 +47,14 @@ ENDIF( cppad_has_cppadcg )
 #
 set_compile_flags(cppad_lib "${cppad_debug_which}" "${source_list}" )
 #
-IF( ${CMAKE_SYSTEM_NAME} STREQUAL "Windows" )
+# is_windows
+STRING( REGEX MATCH "^MSYS" is_msys "${CMAKE_SYSTEM_NAME}" )
+STRING( REGEX MATCH "^CYGWIN" is_cygwin "${CMAKE_SYSTEM_NAME}" )
+STRING( REGEX MATCH "^Windows" is_windows "${CMAKE_SYSTEM_NAME}" )
+IF( is_msys OR is_cygwin OR is_windows )
     MESSAGE( STATUS "Windows system so building static cppad_lib")
     ADD_LIBRARY( cppad_lib STATIC ${source_list} )
-ELSE( ${CMAKE_SYSTEM_NAME} STREQUAL "Windows" )
+ELSE( )
     MESSAGE( STATUS "Not Windows system so building shared cppad_lib")
     ADD_LIBRARY( cppad_lib SHARED ${source_list} )
     SET_TARGET_PROPERTIES( cppad_lib PROPERTIES SOVERSION ${soversion} )
@@ -59,7 +63,7 @@ ELSE( ${CMAKE_SYSTEM_NAME} STREQUAL "Windows" )
     IF( dl_LIBRARY )
         TARGET_LINK_LIBRARIES(cppad_lib ${dl_LIBRARY})
     ENDIF( dl_LIBRARY )
-ENDIF( ${CMAKE_SYSTEM_NAME} STREQUAL "Windows" )
+ENDIF( )
 #
 # install(TARGETS myExe mySharedLib myStaticLib
 #   RUNTIME DESTINATION bin
diff --git a/cppad_lib/cpp_graph_op.cpp b/cppad_lib/cpp_graph_op.cpp
index bb1e550e6..e5c032c17 100644
--- a/cppad_lib/cpp_graph_op.cpp
+++ b/cppad_lib/cpp_graph_op.cpp
@@ -1,5 +1,5 @@
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 Bradley M. Bell
+CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
 
   CppAD is distributed under the terms of the
                Eclipse Public License Version 2.0.
@@ -27,13 +27,23 @@ const char* op_enum2name[n_graph_op];
 // map from operator enum to n_arg (when fixed number of arguments)
 size_t op_enum2fixed_n_arg[n_graph_op];
 
+// This routine is called by the first use of the cpp_graph constructor
+// see cpp_grpah.hpp.
 void set_operator_info(void)
-{   typedef std::pair<std::string, graph_op_enum> pair;
+{   // This routine cannot be called in parallel mode
+    CPPAD_ASSERT_UNKNOWN( ! ( CppAD::thread_alloc::in_parallel() ));
+    //
+    typedef std::pair<std::string, graph_op_enum> pair;
     struct op_info {
         graph_op_enum code;
         const char*  name;
         size_t       n_arg;
     };
+    /*
+    If n_arg is zero in the table below, the table contains a comment as to
+    the heading in graph_op_enum.hpp below which you can find the
+    specifications for n_arg, n_result for the corresponding operator.
+    */
     // BEGIN_SORT_THIS_LINE_PLUS_2
     op_info op_info_vec[] = {
         { abs_graph_op,      "abs",      1 }, // 1 result
@@ -44,18 +54,19 @@ void set_operator_info(void)
         { asinh_graph_op,    "asinh",    1 }, // 1 result
         { atan_graph_op,     "atan",     1 }, // 1 result
         { atanh_graph_op,    "atanh",    1 }, // 1 result
-        { atom_graph_op,     "atom",     0 }, // n_result, n_arg in Json usage
+        { atom_graph_op,     "atom",     0 }, // See Atomic Function
+        { atom4_graph_op,    "atom4",    0 }, // See Atomic Function
         { azmul_graph_op,    "azmul",    2 }, // 1 result
         { cexp_eq_graph_op,  "cexp_eq",  4 }, // 1 result
         { cexp_le_graph_op,  "cexp_le",  4 }, // 1 result
         { cexp_lt_graph_op,  "cexp_lt",  4 }, // 1 result
-        { comp_eq_graph_op,  "comp_eq",  0 }, // n_result, n_arg in Json usage
+        { comp_eq_graph_op,  "comp_eq",  0 }, // See Comparisons
         { comp_le_graph_op,  "comp_le",  0 }, // ...
         { comp_lt_graph_op,  "comp_lt",  0 }, // ...
         { comp_ne_graph_op,  "comp_ne",  0 }, // ...
         { cos_graph_op,      "cos",      1 }, // 1 result
         { cosh_graph_op,     "cosh",     1 }, // 1 result
-        { discrete_graph_op, "discrete", 0 }, // n_result, n_arg in Json usage
+        { discrete_graph_op, "discrete", 0 }, // See Discrete Function
         { div_graph_op,      "div",      2 }, // 1 result
         { erf_graph_op,      "erf",      1 }, // 1 result
         { erfc_graph_op,     "erfc",     1 }, // 1 result
@@ -63,15 +74,16 @@ void set_operator_info(void)
         { expm1_graph_op,    "expm1",    1 }, // 1 result
         { log1p_graph_op,    "log1p",    1 }, // 1 result
         { log_graph_op,      "log",      1 }, // 1 result
+        { neg_graph_op,      "neg",      1 }, // 1 result
         { mul_graph_op,      "mul",      2 }, // 1 result
         { pow_graph_op,      "pow",      2 }, // 1 result
-        { print_graph_op,    "print",    0 }, // n_result, n_arg in Json usage
+        { print_graph_op,    "print",    0 }, // See Print
         { sign_graph_op,     "sign",     1 }, // 1 result
         { sin_graph_op,      "sin",      1 }, // 1 result
         { sinh_graph_op,     "sinh",     1 }, // 1 result
         { sqrt_graph_op,     "sqrt",     1 }, // 1 result
         { sub_graph_op,      "sub",      2 }, // 1 result
-        { sum_graph_op,      "sum",      0 }, // n_result, n_arg in Json usage
+        { sum_graph_op,      "sum",      0 }, // See Summation
         { tan_graph_op,      "tan",      1 }, // 1 result
         { tanh_graph_op,     "tanh",     1 }  // 1 result
     };
diff --git a/cppad_lib/json_lexer.cpp b/cppad_lib/json_lexer.cpp
index 27e3f386b..5966245e5 100644
--- a/cppad_lib/json_lexer.cpp
+++ b/cppad_lib/json_lexer.cpp
@@ -79,14 +79,7 @@ line_number_(1),
 char_number_(1),
 token_(""),
 function_name_("")
-{   // make sure op_name2enum has been initialized
-    if( op_name2enum.size() == 0 )
-    {   CPPAD_ASSERT_KNOWN( ! thread_alloc::in_parallel() ,
-            "call to set_operator_info in parallel mode"
-        );
-        set_operator_info();
-    }
-
+{
     skip_white_space();
     if( index_ < json_.size() )
         token_ = json_[index_];
diff --git a/cppad_lib/json_parser.cpp b/cppad_lib/json_parser.cpp
index 52f35182e..16c758ede 100644
--- a/cppad_lib/json_parser.cpp
+++ b/cppad_lib/json_parser.cpp
@@ -1,5 +1,5 @@
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
+CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
 
 CppAD is distributed under the terms of the
              Eclipse Public License Version 2.0.
@@ -176,6 +176,7 @@ void CppAD::local::graph::json_parser(
         graph_op_enum op_enum    = op_code2enum[ json_lexer.token2size_t() ];
         json_lexer.check_next_char(',');
         //
+        size_t call_id  = std::numeric_limits<size_t>::max();
         size_t n_result = 1;
         size_t n_arg    = op_enum2fixed_n_arg[op_enum];
         //
@@ -193,7 +194,7 @@ void CppAD::local::graph::json_parser(
                     graph_obj.discrete_name_vec_push_back( name );
                 str_index.push_back(name_index);
             }
-            else if( op_enum == atom_graph_op )
+            else if( op_enum == atom_graph_op || op_enum == atom4_graph_op )
             {   // name
                 json_lexer.check_next_string(match_any_string);
                 string name = json_lexer.token();
@@ -232,6 +233,11 @@ void CppAD::local::graph::json_parser(
                 op_enum == comp_ne_graph_op ||
                 op_enum == sum_graph_op
             );
+            if( op_enum == atom4_graph_op )
+            {   json_lexer.next_non_neg_int();
+                call_id = json_lexer.token2size_t();
+                json_lexer.check_next_char(',');
+            }
             // n_result,
             json_lexer.next_non_neg_int();
             n_result = json_lexer.token2size_t();
@@ -245,13 +251,18 @@ void CppAD::local::graph::json_parser(
         }
         //
         // atom_graph_op: name_index, n_result, n_arg
-        // come before first argument
-        if( op_enum == atom_graph_op )
+        // come before first function argument
+        //
+        // atom4_graph_op: name_index, call_id, n_result, n_arg
+        // come before first function argument
+        if( op_enum == atom_graph_op || op_enum == atom4_graph_op )
         {   // name_index, n_result, n_arg come before first_node
             size_t name_index = str_index[0];
             CPPAD_ASSERT_UNKNOWN(
                 name_index < graph_obj.atomic_name_vec_size()
             );
+            if( op_enum == atom4_graph_op )
+                graph_obj.operator_arg_push_back( call_id );
             graph_obj.operator_arg_push_back( name_index );
             graph_obj.operator_arg_push_back( n_result );
             graph_obj.operator_arg_push_back( n_arg );
diff --git a/cppad_lib/json_writer.cpp b/cppad_lib/json_writer.cpp
index 97979cfc5..d070e9f39 100644
--- a/cppad_lib/json_writer.cpp
+++ b/cppad_lib/json_writer.cpp
@@ -1,5 +1,5 @@
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
+CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
 
 CppAD is distributed under the terms of the
              Eclipse Public License Version 2.0.
@@ -21,13 +21,6 @@ void CppAD::local::graph::json_writer(
     std::string&                              json                   ,
     const cpp_graph&                          graph_obj              )
 {   using std::string;
-    // --------------------------------------------------------------------
-    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();
-    }
     // --------------------------------------------------------------------
     const string&  function_name( graph_obj.function_name_get() );
     const size_t&  n_dynamic_ind( graph_obj.n_dynamic_ind_get() );
@@ -114,6 +107,7 @@ void CppAD::local::graph::json_writer(
         cpp_graph::const_iterator::value_type itr_value = *graph_itr;
         const vector<size_t>& str_index( *itr_value.str_index_ptr );
         graph_op_enum op_enum    = itr_value.op_enum;
+        size_t        call_id    = itr_value.call_id;
         size_t        n_result   = itr_value.n_result;
         size_t        n_arg      = itr_value.arg_node_ptr->size();
         arg.resize(n_arg);
@@ -139,13 +133,16 @@ void CppAD::local::graph::json_writer(
             break;
 
             // --------------------------------------------------------------
-            // atom
+            // atom, atom4
             case atom_graph_op:
+            case atom4_graph_op:
             {   size_t name_index = str_index[0];
                 string name = graph_obj.atomic_name_vec_get(name_index);
                 json += "[ " + to_string(op_code) + ", ";
                 json += "'" + name + "', ";
             }
+            if( op_enum == atom4_graph_op )
+                json += to_string(call_id) + ", ";
             json += to_string(n_result) + ", ";
             json += to_string(n_arg) + ", [";
             for(size_t j = 0; j < n_arg; ++j)
diff --git a/cppad_lib/makefile.in b/cppad_lib/makefile.in
index daeaa0647..3a5bcd575 100644
--- a/cppad_lib/makefile.in
+++ b/cppad_lib/makefile.in
@@ -308,7 +308,6 @@ 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@
@@ -363,6 +362,7 @@ pdfdir = @pdfdir@
 prefix = @prefix@
 program_transform_name = @program_transform_name@
 psdir = @psdir@
+runstatedir = @runstatedir@
 sbindir = @sbindir@
 sharedstatedir = @sharedstatedir@
 srcdir = @srcdir@
diff --git a/debian/changelog b/debian/changelog
index 310db5e1a..fb80037a7 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,9 @@
+cppad (2021.00.00.8+git20220327.1.a1f9918-1) UNRELEASED; urgency=low
+
+  * New upstream snapshot.
+
+ -- Debian Janitor <janitor@jelmer.uk>  Mon, 28 Mar 2022 07:05:19 -0000
+
 cppad (2021.00.00.8-1) unstable; urgency=medium
 
   * New upstream release
diff --git a/debian/patches/0001-spelling.patch b/debian/patches/0001-spelling.patch
index 97f4e28d1..6570091b5 100644
--- a/debian/patches/0001-spelling.patch
+++ b/debian/patches/0001-spelling.patch
@@ -6,10 +6,10 @@ Subject: spelling
  test_more/general/adfun.cpp | 2 +-
  1 file changed, 1 insertion(+), 1 deletion(-)
 
-diff --git a/test_more/general/adfun.cpp b/test_more/general/adfun.cpp
-index efa8764..59a593c 100644
---- a/test_more/general/adfun.cpp
-+++ b/test_more/general/adfun.cpp
+Index: cppad/test_more/general/adfun.cpp
+===================================================================
+--- cppad.orig/test_more/general/adfun.cpp
++++ cppad/test_more/general/adfun.cpp
 @@ -24,7 +24,7 @@ bool adfun_empty(void)
  {   bool ok = true;
      size_t thread  = CppAD::thread_alloc::thread_num();
diff --git a/example/CMakeLists.txt b/example/CMakeLists.txt
index cf41e0579..b37ee8bed 100644
--- a/example/CMakeLists.txt
+++ b/example/CMakeLists.txt
@@ -1,5 +1,5 @@
 # -----------------------------------------------------------------------------
-# CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
+# CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
 #
 # CppAD is distributed under the terms of the
 #              Eclipse Public License Version 2.0.
@@ -12,7 +12,7 @@
 # Build the example directory tests
 # Inherit environment from ../CMakeList.txt
 
-# initialize check_depends
+# initialize check_example_depends
 SET(check_example_depends "")
 
 # abs_normal examples
@@ -21,6 +21,7 @@ ADD_SUBDIRECTORY(abs_normal)
 # atomic examples
 ADD_SUBDIRECTORY(atomic_two)
 ADD_SUBDIRECTORY(atomic_three)
+ADD_SUBDIRECTORY(atomic_four)
 
 # checkpoint exmaples
 ADD_SUBDIRECTORY(chkpoint_two)
diff --git a/example/abs_normal/makefile.in b/example/abs_normal/makefile.in
index 63f2dd15c..b5c5c7723 100644
--- a/example/abs_normal/makefile.in
+++ b/example/abs_normal/makefile.in
@@ -291,7 +291,6 @@ 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@
@@ -346,6 +345,7 @@ pdfdir = @pdfdir@
 prefix = @prefix@
 program_transform_name = @program_transform_name@
 psdir = @psdir@
+runstatedir = @runstatedir@
 sbindir = @sbindir@
 sharedstatedir = @sharedstatedir@
 srcdir = @srcdir@
diff --git a/example/atomic_four/CMakeLists.txt b/example/atomic_four/CMakeLists.txt
new file mode 100644
index 000000000..d65cb29c8
--- /dev/null
+++ b/example/atomic_four/CMakeLists.txt
@@ -0,0 +1,42 @@
+# -----------------------------------------------------------------------------
+# CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
+#
+# CppAD is distributed under the terms of the
+#              Eclipse Public License Version 2.0.
+#
+# This Source Code may also be made available under the following
+# Secondary License when the conditions for such availability set forth
+# in the Eclipse Public License, Version 2.0 are satisfied:
+#       GNU General Public License, Version 2.0 or later.
+# -----------------------------------------------------------------------------
+#
+# initialize check_example_atomic_four_depends
+SET(check_example_atomic_four_depends "")
+#
+ADD_SUBDIRECTORY(mat_mul)
+ADD_SUBDIRECTORY(vector)
+#
+# BEGIN_SORT_THIS_LINE_PLUS_2
+SET(source_list
+    atomic_four.cpp
+    dynamic.cpp
+    forward.cpp
+    get_started.cpp
+    norm_sq.cpp
+)
+# END_SORT_THIS_LINE_MINUS_2
+
+set_compile_flags(example_atomic_four "${cppad_debug_which}" "${source_list}" )
+#
+ADD_EXECUTABLE(example_atomic_four EXCLUDE_FROM_ALL ${source_list})
+#
+# Add the check_example_atomic_four target
+ADD_CUSTOM_TARGET(check_example_atomic_four
+    example_atomic_four
+    DEPENDS example_atomic_four ${check_example_atomic_four_depends}
+)
+MESSAGE(STATUS "make check_example_atomic_four: available")
+#
+# add to check check_example_depends in parent environment
+add_to_list(check_example_depends check_example_atomic_four)
+SET(check_example_depends "${check_example_depends}" PARENT_SCOPE)
diff --git a/example/atomic_four/atomic_four.cpp b/example/atomic_four/atomic_four.cpp
new file mode 100644
index 000000000..a53ba3b1d
--- /dev/null
+++ b/example/atomic_four/atomic_four.cpp
@@ -0,0 +1,56 @@
+/* --------------------------------------------------------------------------
+CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
+
+CppAD is distributed under the terms of the
+             Eclipse Public License Version 2.0.
+
+This Source Code may also be made available under the following
+Secondary License when the conditions 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_HAS_* defines
+# include <cppad/configure.hpp>
+
+// system include files used for I/O
+# include <iostream>
+
+// C style asserts
+# include <cassert>
+
+// for thread_alloc
+# include <cppad/utility/thread_alloc.hpp>
+
+// test runner
+# include <cppad/utility/test_boolofvoid.hpp>
+
+// BEGIN_SORT_THIS_LINE_PLUS_1
+extern bool dynamic(void);
+extern bool forward(void);
+extern bool get_started(void);
+extern bool norm_sq(void);
+// END_SORT_THIS_LINE_MINUS_1
+
+// main program that runs all the tests
+int main(void)
+{   std::string group = "example/atomic";
+    size_t      width = 20;
+    CppAD::test_boolofvoid Run(group, width);
+
+    // This line is used by test_one.sh
+
+    // BEGIN_SORT_THIS_LINE_PLUS_1
+    Run( dynamic,             "dynamic"        );
+    Run( forward,             "forward"        );
+    Run( get_started,         "get_started"    );
+    Run( norm_sq,             "norm_sq"        );
+    // END_SORT_THIS_LINE_MINUS_1
+
+    // check for memory leak
+    bool memory_ok = CppAD::thread_alloc::free_all();
+    // print summary at end
+    bool ok = Run.summary(memory_ok);
+    //
+    return static_cast<int>( ! ok );
+}
diff --git a/example/atomic_four/atomic_four.omh b/example/atomic_four/atomic_four.omh
new file mode 100644
index 000000000..02c107f9d
--- /dev/null
+++ b/example/atomic_four/atomic_four.omh
@@ -0,0 +1,25 @@
+/* --------------------------------------------------------------------------
+CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
+
+  CppAD is distributed under the terms of the
+               Eclipse Public License Version 2.0.
+
+  This Source Code may also be made available under the following
+  Secondary License when the conditions 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_four_example$$
+
+$section Example Defining Atomic Functions: Fourth Generation$$
+
+$childtable%
+    example/atomic_four/get_started.cpp
+    %example/atomic_four/norm_sq.cpp
+    %example/atomic_four/forward.cpp
+    %example/atomic_four/dynamic.cpp
+    %include/cppad/example/atomic_four/vector/vector.omh
+    %include/cppad/example/atomic_four/mat_mul/mat_mul.omh
+%$$
+
+$end
diff --git a/example/atomic_four/dynamic.cpp b/example/atomic_four/dynamic.cpp
new file mode 100644
index 000000000..4ea89bb07
--- /dev/null
+++ b/example/atomic_four/dynamic.cpp
@@ -0,0 +1,199 @@
+/* --------------------------------------------------------------------------
+CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
+
+CppAD is distributed under the terms of the
+             Eclipse Public License Version 2.0.
+
+This Source Code may also be made available under the following
+Secondary License when the conditions 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_four_dynamic.cpp$$
+
+$section Atomic Functions with Dynamic Parameters: Example and Test$$
+
+$head Purpose$$
+This example demonstrates using dynamic parameters with an
+$cref atomic_four$$ function.
+
+$head Function$$
+For this example, the atomic function
+$latex g : \B{R}^3 \rightarrow \B{R}^3$$ is defined by
+$latex g_0 (x) = x_0 * x_ 0$$,
+$latex g_1 (x) = x_0 * x_ 1$$,
+$latex g_2 (x) = x_1 * x_ 2$$.
+
+$head Define Atomic Function$$
+$srcthisfile%0
+    %// BEGIN_DEFINE_ATOMIC_FUNCTION%// END_DEFINE_ATOMIC_FUNCTION%
+1%$$
+
+$head Use Atomic Function$$
+$srcthisfile%0
+    %// BEGIN_USE_ATOMIC_FUNCTION%// END_USE_ATOMIC_FUNCTION%
+1%$$
+
+$end
+*/
+
+# include <cppad/cppad.hpp>
+
+// BEGIN_DEFINE_ATOMIC_FUNCTION
+// empty namespace
+namespace {
+    // atomic_dynamic
+    class atomic_dynamic : public CppAD::atomic_four<double> {
+    public:
+        atomic_dynamic(const std::string& name) :
+        CppAD::atomic_four<double>(name)
+        { }
+    private:
+        // for_type
+        bool for_type(
+        size_t                                     call_id     ,
+        const CppAD::vector<CppAD::ad_type_enum>&  type_x      ,
+        CppAD::vector<CppAD::ad_type_enum>&        type_y      ) override
+        {   assert( call_id == 0 );       // default value
+            assert( type_x.size() == 3 ); // n
+            assert( type_y.size() == 3 ); // m
+            //
+            // type_y
+            type_y[0] = type_x[0];
+            type_y[1] = std::max( type_x[0], type_x[1] );
+            type_y[2] = std::max( type_x[1], type_x[2] );
+            return true;
+        }
+        // forward
+        bool forward(
+            size_t                        call_id      ,
+            const CppAD::vector<bool>&    select_y     ,
+            size_t                        order_low    ,
+            size_t                        order_up     ,
+            const CppAD::vector<double>&  taylor_x     ,
+            CppAD::vector<double>&        taylor_y     ) override
+        {
+# ifndef NDEBUG
+            size_t q = order_up + 1;
+            size_t n = taylor_x.size() / q;
+            size_t m = taylor_y.size() / q;
+            assert( n == 3 );
+            assert( m == 3 );
+# endif
+            // ok
+            bool ok = order_low == 0 && order_up == 0;
+            if( ! ok )
+                return ok;
+            //
+            // taylor_y[0] = g_0 = x_0 * x_0
+            if( select_y[0] )
+                taylor_y[0] = taylor_x[0] * taylor_x[0];
+            //
+            // taylor_y[1] = g_1 = x_0 * x_1
+            if( select_y[1] )
+                taylor_y[1] = taylor_x[0] * taylor_x[1];
+            //
+            // taylor_y[2] = g_2 = x_1 * x_2
+            if( select_y[2] )
+                taylor_y[2] = taylor_x[1] * taylor_x[2];
+            //
+            return ok;
+        }
+    };
+}
+// END_DEFINE_ATOMIC_FUNCTION
+
+// BEGIN_USE_ATOMIC_FUNCTION
+bool dynamic(void)
+{   // ok, eps
+    bool ok = true;
+    double eps = 10. * CppAD::numeric_limits<double>::epsilon();
+    //
+    // afun
+    atomic_dynamic afun("atomic_dynamic");
+    //
+    // c, p, u
+    CPPAD_TESTVECTOR(double) c(1), p(1), u(1);
+    c[0] = 2.0;
+    p[0] = 3.0;
+    u[0] = 4.0;
+    //
+    //
+    // np, nu, ny
+    size_t np = 1;
+    size_t nu = 1;
+    size_t nx = 3;
+    size_t ny = 3;
+    //
+    // ap
+    // indepndent dynamic parameter vector
+    CPPAD_TESTVECTOR( CppAD::AD<double> ) ap(np);
+    ap[0] = p[0];
+    //
+    // au
+    // independent variable vector
+    CPPAD_TESTVECTOR( CppAD::AD<double> ) au(nu);
+    au[0] = u[0];
+    //
+    // Independent
+    CppAD::Independent(au, ap);
+    //
+    // ay
+    // y = ( c * c, c * p, p * x )
+    CPPAD_TESTVECTOR( CppAD::AD<double> ) ax(nx), ay(ny);
+    ax[0] = c[0];  // x_0
+    ax[1] = ap[0]; // x_1
+    ax[2] = au[0]; // x_2
+    afun(ax, ay);
+    //
+    // ay
+    // check type of result
+    ok &= Constant( ay[0] );
+    ok &= Dynamic(  ay[1] );
+    ok &= Variable( ay[2] );
+    //
+    // f
+    // f(u) = (c * c, c * p, p * u)
+    CppAD::ADFun<double> f;
+    f.Dependent (au, ay);
+    //
+    // ay[0]
+    double check = c[0] * c[0];
+    ok &= CppAD::NearEqual( Value(ay[0]) , check,  eps, eps);
+    //
+    // ay[1]
+    check = c[0] * p[0];
+    ok &= CppAD::NearEqual( Value(ay[1]) , check,  eps, eps);
+    //
+    // ay[2]
+    check = p[0] * u[0];
+    ok &= CppAD::NearEqual( Value(ay[2]) , check,  eps, eps);
+    //
+    // y = f.Foward(0, u)
+    CPPAD_TESTVECTOR(double) y(ny);
+    y     = f.Forward(0, u);
+    check = c[0] * c[0];
+    ok    &= CppAD::NearEqual(y[0] , check,  eps, eps);
+    check = c[0] * p[0];
+    ok    &= CppAD::NearEqual(y[1] , check,  eps, eps);
+    check = p[0] * u[0];
+    ok    &= CppAD::NearEqual(y[2] , check,  eps, eps);
+    //
+    // p
+    p[0]   = 2.0 * p[0];
+    f.new_dynamic(p);
+    //
+    // y = f.Foward(0, u)
+    y     = f.Forward(0, u);
+    check = c[0] * c[0];
+    ok    &= CppAD::NearEqual(y[0] , check,  eps, eps);
+    check = c[0] * p[0];
+    ok    &= CppAD::NearEqual(y[1] , check,  eps, eps);
+    check = p[0] * u[0];
+    ok    &= CppAD::NearEqual(y[2] , check,  eps, eps);
+    //
+    return ok;
+}
+// END_USE_ATOMIC_FUNCTION
diff --git a/example/atomic_four/forward.cpp b/example/atomic_four/forward.cpp
new file mode 100644
index 000000000..0c3ee4dfa
--- /dev/null
+++ b/example/atomic_four/forward.cpp
@@ -0,0 +1,328 @@
+/* --------------------------------------------------------------------------
+CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
+
+CppAD is distributed under the terms of the
+             Eclipse Public License Version 2.0.
+
+This Source Code may also be made available under the following
+Secondary License when the conditions 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_four_forward.cpp$$
+$spell
+    Jacobian
+$$
+
+$section Atomic Functions and Forward Mode: Example and Test$$
+
+$head Purpose$$
+This example demonstrates forward mode derivative calculation
+using an $cref atomic_four$$ function.
+
+$head Function$$
+For this example, the atomic function
+$latex g : \B{R}^3 \rightarrow \B{R}^2$$ is defined by
+$latex \[
+g(x) = \left( \begin{array}{c}
+    x_2 * x_2 \\
+    x_0 * x_1
+\end{array} \right)
+\] $$
+
+$head Jacobian$$
+The corresponding Jacobian is
+$latex \[
+g^{(1)} (x) = \left( \begin{array}{ccc}
+  0  &   0 & 2 x_2 \\
+x_1  & x_0 & 0
+\end{array} \right)
+\] $$
+
+$head Hessian$$
+The Hessians of the component functions are
+$latex \[
+g_0^{(2)} ( x ) = \left( \begin{array}{ccc}
+    0 & 0 & 0  \\
+    0 & 0 & 0  \\
+    0 & 0 & 2
+\end{array} \right)
+\W{,}
+g_1^{(2)} ( x ) = \left( \begin{array}{ccc}
+    0 & 1 & 0 \\
+    1 & 0 & 0 \\
+    0 & 0 & 0
+\end{array} \right)
+\] $$
+
+$head Define Atomic Function$$
+$srcthisfile%0
+    %// BEGIN_DEFINE_ATOMIC_FUNCTION%// END_DEFINE_ATOMIC_FUNCTION%
+1%$$
+
+$head Use Atomic Function$$
+$srcthisfile%0
+    %// BEGIN_USE_ATOMIC_FUNCTION%// END_USE_ATOMIC_FUNCTION%
+1%$$
+
+
+$end
+*/
+# include <cppad/cppad.hpp>
+
+// BEGIN_DEFINE_ATOMIC_FUNCTION
+// empty namespace
+namespace {
+    //
+    class atomic_forward : public CppAD::atomic_four<double> {
+    public:
+        atomic_forward(const std::string& name) :
+        CppAD::atomic_four<double>(name)
+        { }
+    private:
+        // for_type
+        bool for_type(
+            size_t                                     call_id     ,
+            const CppAD::vector<CppAD::ad_type_enum>&  type_x      ,
+            CppAD::vector<CppAD::ad_type_enum>&        type_y      ) override
+        {
+            bool ok = type_x.size() == 3; // n
+            ok     &= type_y.size() == 2; // m
+            if( ! ok )
+                return false;
+            type_y[0] = type_x[2];
+            type_y[1] = std::max(type_x[0], type_x[1]);
+            return true;
+        }
+        // forward
+        bool forward(
+            size_t                                    call_id      ,
+            const CppAD::vector<bool>&                select_y     ,
+            size_t                                    order_low    ,
+            size_t                                    order_up     ,
+            const CppAD::vector<double>&              tx           ,
+            CppAD::vector<double>&                    ty           ) override
+        {
+            size_t q = order_up + 1;
+# ifndef NDEBUG
+            size_t n = tx.size() / q;
+            size_t m = ty.size() / q;
+# endif
+            assert( n == 3 );
+            assert( m == 2 );
+            assert( order_low <= order_up );
+
+            // this example only implements up to second order forward mode
+            bool ok = order_up <=  2;
+            if( ! ok )
+                return ok;
+
+            // --------------------------------------------------------------
+            // Zero forward mode.
+            // This case must always be implemented
+            // g(x) = [ x_2 * x_2 ]
+            //        [ x_0 * x_1 ]
+            // y^0  = f( x^0 )
+            if( order_low <= 0 )
+            {   // y_0^0 = x_2^0 * x_2^0
+                ty[0 * q + 0] = tx[2 * q + 0] * tx[2 * q + 0];
+                // y_1^0 = x_0^0 * x_1^0
+                ty[1 * q + 0] = tx[0 * q + 0] * tx[1 * q + 0];
+            }
+            if( order_up <=  0 )
+                return ok;
+            // --------------------------------------------------------------
+            // First order forward mode.
+            // This case is needed if first order forward mode is used.
+            // g'(x) = [   0,   0, 2 * x_2 ]
+            //         [ x_1, x_0,       0 ]
+            // y^1 =  f'(x^0) * x^1
+            if( order_low <= 1 )
+            {   // y_0^1 = 2 * x_2^0 * x_2^1
+                ty[0 * q + 1] = 2.0 * tx[2 * q + 0] * tx[2 * q + 1];
+                // y_1^1 = x_1^0 * x_0^1 + x_0^0 * x_1^1
+                ty[1 * q + 1]  = tx[1 * q + 0] * tx[0 * q + 1];
+                ty[1 * q + 1] += tx[0 * q + 0] * tx[1 * q + 1];
+            }
+            if( order_up <=  1 )
+                return ok;
+            // --------------------------------------------------------------
+            // Second order forward mode.
+            // This case is needed if second order forwrd mode is used.
+            // g'(x) = [   0,   0, 2 x_2 ]
+            //         [ x_1, x_0,     0 ]
+            //
+            //            [ 0 , 0 , 0 ]                  [ 0 , 1 , 0 ]
+            // g_0''(x) = [ 0 , 0 , 0 ]  g_1^{(2)} (x) = [ 1 , 0 , 0 ]
+            //            [ 0 , 0 , 2 ]                  [ 0 , 0 , 0 ]
+            //
+            //  y_0^2 = x^1 * g_0''( x^0 ) x^1 / 2! + g_0'( x^0 ) x^2
+            //        = ( x_2^1 * 2.0 * x_2^1 ) / 2!
+            //        + 2.0 * x_2^0 * x_2^2
+            ty[0 * q + 2]  = tx[2 * q + 1] * tx[2 * q + 1];
+            ty[0 * q + 2] += 2.0 * tx[2 * q + 0] * tx[2 * q + 2];
+            //
+            //  y_1^2 = x^1 * g_1''( x^0 ) x^1 / 2! + g_1'( x^0 ) x^2
+            //        = ( x_1^1 * x_0^1 + x_0^1 * x_1^1) / 2
+            //        + x_1^0 * x_0^2 + x_0^0 + x_1^2
+            ty[1 * q + 2]  = tx[1 * q + 1] * tx[0 * q + 1];
+            ty[1 * q + 2] += tx[1 * q + 0] * tx[0 * q + 2];
+            ty[1 * q + 2] += tx[0 * q + 0] * tx[1 * q + 2];
+            // --------------------------------------------------------------
+            return ok;
+        }
+    };
+}
+// END_DEFINE_ATOMIC_FUNCTION
+
+// BEGIN_USE_ATOMIC_FUNCTION
+bool forward(void)
+{   // ok, eps
+    bool ok = true;
+    double eps = 10. * CppAD::numeric_limits<double>::epsilon();
+    //
+    // AD, NearEqual
+    using CppAD::AD;
+    using CppAD::NearEqual;
+    //
+    // afun
+    atomic_forward afun("atomic_forward");
+    //
+    // Create the function f(u) = g(u) for this example.
+    //
+    // n, u, au
+    size_t n  = 3;
+    CPPAD_TESTVECTOR(double)       u(n);
+    u[0] = 1.00;
+    u[1] = 2.00;
+    u[2] = 3.00;
+    CPPAD_TESTVECTOR( AD<double> ) au(n);
+    for(size_t j = 0; j < n; ++j)
+        au[j] = u[j];
+    CppAD::Independent(au);
+    //
+    // m, ay
+    size_t m = 2;
+    CPPAD_TESTVECTOR( AD<double> ) ay(m);
+    CPPAD_TESTVECTOR( AD<double> ) ax = au;
+    afun(ax, ay);
+    //
+    // f
+    CppAD::ADFun<double> f;
+    f.Dependent(au, ay);
+    //
+    // check function value
+    double check = u[2] * u[2];
+    ok &= NearEqual( Value(ay[0]) , check,  eps, eps);
+    check = u[0] * u[1];
+    ok &= NearEqual( Value(ay[1]) , check,  eps, eps);
+
+    // ----------------------------------------------------------------
+    // zero order forward
+    //
+    // u0, y0
+    CPPAD_TESTVECTOR(double) u0(n), y0(m);
+    u0 = u;
+    y0   = f.Forward(0, u0);
+    check = u[2] * u[2];
+    ok &= NearEqual(y0[0] , check,  eps, eps);
+    check = u[0] * u[1];
+    ok &= NearEqual(y0[1] , check,  eps, eps);
+    // ----------------------------------------------------------------
+    // first order forward
+    //
+    // check_jac
+    double check_jac[] = {
+        0.0, 0.0, 2.0 * u[2],
+        u[1], u[0],       0.0
+    };
+    //
+    // u1
+    CPPAD_TESTVECTOR(double) u1(n);
+    for(size_t j = 0; j < n; j++)
+        u1[j] = 0.0;
+    //
+    // y1, j
+    CPPAD_TESTVECTOR(double) y1(m);
+    for(size_t j = 0; j < n; j++)
+    {   //
+        // u1, y1
+        // compute partial in j-th component direction
+        u1[j] = 1.0;
+        y1    = f.Forward(1, u1);
+        u1[j] = 0.0;
+        //
+        // check this partial
+        for(size_t i = 0; i < m; i++)
+            ok &= NearEqual(y1[i], check_jac[i * n + j], eps, eps);
+    }
+    // ----------------------------------------------------------------
+    // second order forward
+    //
+    // check_hes_0
+    double check_hes_0[] = {
+        0.0, 0.0, 0.0,
+        0.0, 0.0, 0.0,
+        0.0, 0.0, 2.0
+    };
+    //
+    // check_hes_1
+    double check_hes_1[] = {
+        0.0, 1.0, 0.0,
+        1.0, 0.0, 0.0,
+        0.0, 0.0, 0.0
+    };
+    //
+    // u2
+    CPPAD_TESTVECTOR(double) u2(n);
+    for(size_t j = 0; j < n; j++)
+        u2[j] = 0.0;
+    //
+    // y2, j
+    CPPAD_TESTVECTOR(double) y2(m);
+    for(size_t j = 0; j < n; j++)
+    {   //
+        // u1, y2
+        // first order forward in j-th direction
+        u1[j] = 1.0;
+        f.Forward(1, u1);
+        y2 = f.Forward(2, u2);
+        //
+        // check y2 element of Hessian diagonal
+        ok &= NearEqual(y2[0], check_hes_0[j * n + j] / 2.0, eps, eps);
+        ok &= NearEqual(y2[1], check_hes_1[j * n + j] / 2.0, eps, eps);
+        //
+        // k
+        for(size_t k = 0; k < n; k++) if( k != j )
+        {   //
+            // u1, y2
+            u1[k] = 1.0;
+            f.Forward(1, u1);
+            y2 = f.Forward(2, u2);
+            //
+            // y2 = (H_jj + H_kk + H_jk + H_kj) / 2.0
+            // y2 = (H_jj + H_kk) / 2.0 + H_jk
+            //
+            // check y2[0]
+            double H_jj = check_hes_0[j * n + j];
+            double H_kk = check_hes_0[k * n + k];
+            double H_jk = y2[0] - (H_kk + H_jj) / 2.0;
+            ok &= NearEqual(H_jk, check_hes_0[j * n + k], eps, eps);
+            //
+            // check y2[1]
+            H_jj = check_hes_1[j * n + j];
+            H_kk = check_hes_1[k * n + k];
+            H_jk = y2[1] - (H_kk + H_jj) / 2.0;
+            ok &= NearEqual(H_jk, check_hes_1[j * n + k], eps, eps);
+            //
+            // u1
+            u1[k] = 0.0;
+        }
+        // u1
+        u1[j] = 0.0;
+    }
+    // ----------------------------------------------------------------
+    return ok;
+}
+// END_USE_ATOMIC_FUNCTION
diff --git a/example/atomic_four/get_started.cpp b/example/atomic_four/get_started.cpp
new file mode 100644
index 000000000..f1b6c286d
--- /dev/null
+++ b/example/atomic_four/get_started.cpp
@@ -0,0 +1,146 @@
+/* --------------------------------------------------------------------------
+CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
+
+CppAD is distributed under the terms of the
+             Eclipse Public License Version 2.0.
+
+This Source Code may also be made available under the following
+Secondary License when the conditions 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_four_get_started.cpp$$
+
+$section Getting Started with Atomic Functions: Example and Test$$
+
+$head Purpose$$
+This example demonstrates the minimal amount of information
+necessary for a $cref atomic_four$$ function.
+
+$head Define Atomic Function$$
+$srcthisfile%0
+    %// BEGIN_DEFINE_ATOMIC_FUNCTION%// END_DEFINE_ATOMIC_FUNCTION%
+1%$$
+
+$head Use Atomic Function$$
+$srcthisfile%0
+    %// BEGIN_USE_ATOMIC_FUNCTION%// END_USE_ATOMIC_FUNCTION%
+1%$$
+
+$end
+*/
+# include <cppad/cppad.hpp>  // CppAD include file
+
+// BEGIN_DEFINE_ATOMIC_FUNCTION
+// empty namespace
+namespace {
+    // atomic_get_started
+    class atomic_get_started : public CppAD::atomic_four<double> {
+    public:
+        // can use const char* name when calling this constructor
+        atomic_get_started(const std::string& name) :
+        CppAD::atomic_four<double>(name) // inform base class of name
+        { }
+    private:
+        // for_type
+        bool for_type(
+            size_t                                     call_id     ,
+            const CppAD::vector<CppAD::ad_type_enum>&  type_x      ,
+            CppAD::vector<CppAD::ad_type_enum>&        type_y      ) override
+        {
+            assert( call_id == 0 );       // default value
+            assert( type_x.size() == 1 ); // n
+            assert( type_y.size() == 1 ); // m
+            //
+            type_y[0] = type_x[0];
+            return true;
+        }
+        // forward
+        bool forward(
+            size_t                              call_id      ,
+            const CppAD::vector<bool>&          select_y     ,
+            size_t                              order_low    ,
+            size_t                              order_up     ,
+            const CppAD::vector<double>&        taylor_x     ,
+            CppAD::vector<double>&              taylor_y     ) override
+        {
+# ifndef NDEBUG
+            size_t q = order_up + 1;
+            size_t n = taylor_x.size() / q;
+            size_t m = taylor_y.size() / q;
+            assert( call_id == 0 );
+            assert( order_low == 0);
+            assert( order_up == 0);
+            assert( n == 1 );
+            assert( m == 1 );
+            assert( m == select_y.size() );
+# endif
+            // return flag
+            bool ok = order_up == 0;
+            if( ! ok )
+                return ok;
+
+            // taylor_y
+            // Order zero forward mode: y^0 = g( x^0 ) = 1 / x^0
+            taylor_y[0] = 1.0 / taylor_x[0];
+            //
+            return ok;
+        }
+    };
+}
+// END_DEFINE_ATOMIC_FUNCTION
+
+// BEGIN_USE_ATOMIC_FUNCTION
+bool get_started(void)
+{
+    // ok, eps
+    bool ok = true;
+    double eps = 10. * CppAD::numeric_limits<double>::epsilon();
+    //
+    // afun
+    atomic_get_started afun("atomic_get_started");
+    //
+    // n, m
+    size_t n = 1;
+    size_t m = 1;
+    //
+    // x0
+    double  x0 = 0.5;
+    //
+    // ax
+    CPPAD_TESTVECTOR( CppAD::AD<double> ) ax(n);
+    ax[0]     = x0;
+    CppAD::Independent(ax);
+    //
+    // au
+    // call atomic function and store result in au
+    CPPAD_TESTVECTOR( CppAD::AD<double> ) au(m);
+    afun(ax, au);
+    //
+    // ay
+    CPPAD_TESTVECTOR( CppAD::AD<double> ) ay(m);
+    ay[0] = 1.0 + au[0];
+    //
+    // f
+    // create f: x -> y and stop tape recording
+    CppAD::ADFun<double> f(ax, ay);
+    //
+    // check
+    double check = 1.0 + 1.0 / x0;
+    //
+    // ok
+    // check ay[0]
+    ok &= CppAD::NearEqual( Value(ay[0]) , check,  eps, eps);
+    //
+    // ok
+    // check zero order forward mode
+    CPPAD_TESTVECTOR( double ) x(n), y(m);
+    x[0] = x0;
+    y    = f.Forward(0, x);
+    ok    &= CppAD::NearEqual(y[0] , check,  eps, eps);
+    //
+    return ok;
+}
+// END_USE_ATOMIC_FUNCTION
diff --git a/example/atomic_four/mat_mul/CMakeLists.txt b/example/atomic_four/mat_mul/CMakeLists.txt
new file mode 100644
index 000000000..90f847671
--- /dev/null
+++ b/example/atomic_four/mat_mul/CMakeLists.txt
@@ -0,0 +1,44 @@
+# -----------------------------------------------------------------------------
+# CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
+#
+# CppAD is distributed under the terms of the
+#              Eclipse Public License Version 2.0.
+#
+# This Source Code may also be made available under the following
+# Secondary License when the conditions 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_2
+SET(source_list
+    forward.cpp
+    identical_zero.cpp
+    mat_mul.cpp
+    rev_depend.cpp
+    reverse.cpp
+    sparsity.cpp
+)
+# END_SORT_THIS_LINE_MINUS_2
+
+set_compile_flags(example_atomic_four_mat_mul
+    "${cppad_debug_which}" "${source_list}"
+)
+#
+ADD_EXECUTABLE(example_atomic_four_mat_mul EXCLUDE_FROM_ALL ${source_list})
+#
+# Add the check_example_atomic_four_mat_mul target
+ADD_CUSTOM_TARGET(check_example_atomic_four_mat_mul
+    example_atomic_four_mat_mul
+    DEPENDS example_atomic_four_mat_mul
+)
+MESSAGE(STATUS "make check_example_atomic_four_mat_mul: available")
+#
+# add to check check_example_atomic_four_depends in parent environment
+add_to_list(
+    check_example_atomic_four_depends
+    check_example_atomic_four_mat_mul
+)
+SET(check_example_atomic_four_depends
+    "${check_example_atomic_four_depends}" PARENT_SCOPE
+)
diff --git a/example/atomic_four/mat_mul/forward.cpp b/example/atomic_four/mat_mul/forward.cpp
new file mode 100644
index 000000000..909154c32
--- /dev/null
+++ b/example/atomic_four/mat_mul/forward.cpp
@@ -0,0 +1,245 @@
+/* --------------------------------------------------------------------------
+CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
+
+CppAD is distributed under the terms of the
+             Eclipse Public License Version 2.0.
+
+This Source Code may also be made available under the following
+Secondary License when the conditions 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_four_mat_mul_forward.cpp$$
+$spell
+    Jacobian
+$$
+
+$section Atomic Matrix Multiply Forward Mode: Example and Test$$
+
+$head Purpose$$
+This example demonstrates using forward mode with
+the $cref atomic_four_mat_mul$$ class.
+
+$head f(x)$$
+For this example, the function $latex f(x)$$ is
+$latex \[
+f(x) =
+\left( \begin{array}{cc}
+x_0 & x_1  \\
+x_2 & x_3  \\
+x_4 & x_5
+\end{array} \right)
+\left( \begin{array}{c}
+x_6  \\
+x_7
+\end{array} \right)
+=
+\left( \begin{array}{c}
+x_0 x_6 + x_1 x_7  \\
+x_2 x_6 + x_3 x_7  \\
+x_4 x_6 + x_5 x_7
+\end{array} \right)
+\] $$
+
+$head Jacobian of f(x)$$
+The Jacobian of $latex f(x)$$ is
+$latex \[
+f^{(1)} (x) = \left( \begin{array}{cccccccc}
+x_6 & x_7 & 0   & 0    & 0    & 0   & x_0  & x_1 \\
+0   & 0   & x_6 & x_7  & 0    & 0   & x_2  & x_3 \\
+0   & 0   & 0   & 0    & x_6  & x_7 & x_4  & x_5
+\end{array} \right)
+\] $$
+
+$head g(x)$$
+We define the function $latex g(x) = f_1^{(1)} (x)^\R{T}$$; i.e.,
+$latex \[
+g(x) = ( 0,  0,  x_6,  x_7,  0,  0,  x_2,  x_3 )^\R{T}
+\] $$
+
+$head Hessian$$
+The Hessian of $latex f_1(x)$$ is the Jacobian
+of $latex g(x)$$; i.e.,
+$latex \[
+f_1^{(2)} (x)
+=
+g^{(1)} (x)
+=
+\left( \begin{array}{cccccccc}
+    0   & 0   & 0   & 0    & 0    & 0   & 0    & 0   \\
+    0   & 0   & 0   & 0    & 0    & 0   & 0    & 0   \\
+    0   & 0   & 0   & 0    & 0    & 0   & 1    & 0   \\
+    0   & 0   & 0   & 0    & 0    & 0   & 0    & 1   \\
+    0   & 0   & 0   & 0    & 0    & 0   & 0    & 0   \\
+    0   & 0   & 0   & 0    & 0    & 0   & 0    & 0   \\
+    0   & 0   & 1   & 0    & 0    & 0   & 0    & 0   \\
+    0   & 0   & 0   & 1    & 0    & 0   & 0    & 0   \\
+\end{array} \right)
+\] $$
+
+$head Source$$
+$srcthisfile%0%// BEGIN C++%// END C++%1%$$
+$end
+*/
+// BEGIN C++
+# include <cppad/cppad.hpp>
+# include <cppad/example/atomic_four/mat_mul/mat_mul.hpp>
+
+bool forward(void)
+{   // ok, eps
+    bool ok = true;
+    //
+    // AD, NearEqual
+    using CppAD::AD;
+    using CppAD::NearEqual;
+    // -----------------------------------------------------------------------
+    // Record f
+    // -----------------------------------------------------------------------
+    //
+    // afun
+    CppAD::atomic_mat_mul<double> afun("atomic_mat_mul");
+    //
+    // nleft, n_middle, n_right
+    size_t n_left = 3, n_middle = 2, n_right = 1;
+    //
+    // nx, ax
+    size_t nx = n_middle * (n_left + n_right);
+    CPPAD_TESTVECTOR( AD<double> ) ax(nx);
+    for(size_t j = 0; j < nx; ++j)
+        ax[j] = AD<double>(j + 2);
+    CppAD::Independent(ax);
+    //
+    // ny, ay
+    size_t ny = n_left * n_right;
+    CPPAD_TESTVECTOR( AD<double> ) ay(ny);
+    //
+    // ay
+    size_t call_id = afun.set(n_left, n_middle, n_right);
+    afun(call_id, ax, ay);
+    //
+    // f
+    CppAD::ADFun<double> f(ax, ay);
+    // -----------------------------------------------------------------------
+    // Forward mode on f
+    // -----------------------------------------------------------------------
+    //
+    // x
+    CPPAD_TESTVECTOR(double) x(nx);
+    for(size_t j = 0; j < nx; ++j)
+        x[j] = double(3 + nx - j);
+    //
+    // y
+    // zero order forward mode computation of f(x)
+    CPPAD_TESTVECTOR(double) y(ny);
+    y = f.Forward(0, x);
+    //
+    // check_y
+    double check_y[] = {
+        x[0] * x[6] + x[1] * x[7],
+        x[2] * x[6] + x[3] * x[7],
+        x[4] * x[6] + x[5] * x[7]
+    };
+    for(size_t i = 0; i < ny; ++i)
+        ok &= y[i] == check_y[i];
+    //
+    // J
+    // first order forward mode computation of f'(x)
+    CPPAD_TESTVECTOR(double) x1(nx), y1(ny), J(ny * nx);
+    for(size_t j = 0; j < nx; ++j)
+        x1[j] = 0.0;
+    for(size_t j = 0; j < nx; ++j)
+    {   x1[j] = 1.0;
+        y1    = f.Forward(1, x1);
+        x1[j] = 0.0;
+        for(size_t i = 0; i < ny; ++i)
+            J[i * nx + j] = y1[i];
+    }
+    //
+    // check_J
+    double check_J[] = {
+        x[6], x[7],  0.0,  0.0,  0.0,  0.0, x[0], x[1],
+         0.0,  0.0, x[6], x[7],  0.0,  0.0, x[2], x[3],
+         0.0,  0.0,  0.0,  0.0, x[6], x[7], x[4], x[5]
+    };
+    for(size_t ij = 0; ij < ny * nx; ij++)
+        ok &= J[ij] == check_J[ij];
+    //
+    // H_1
+    // Second order forward mode computaiton of f_1^2 (x)
+    // (use the fact that the diagonal of this Hessian is zero).
+    CPPAD_TESTVECTOR(double) x2(nx), y2(nx), H_1(nx * nx);
+    for(size_t j = 0; j < nx; ++j)
+        x2[j] = 0.0;
+    for(size_t i = 0; i < nx; ++i)
+    {   for(size_t j = 0; j < nx; ++j)
+        {   x1[i] = 1.0;
+            x1[j] = 1.0;
+            f.Forward(1, x1);
+            x1[i] = 0.0;
+            x1[j] = 0.0;
+            y2 = f.Forward(2, x2);
+            H_1[i * nx + j] = y2[1];
+        }
+    }
+    //
+    // check_H_1
+    double check_H_1[] = {
+        0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,
+        0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,
+        0.,  0.,  0.,  0.,  0.,  0.,  1.,  0.,
+        0.,  0.,  0.,  0.,  0.,  0.,  0.,  1.,
+        0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,
+        0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,
+        0.,  0.,  1.,  0.,  0.,  0.,  0.,  0.,
+        0.,  0.,  0.,  1.,  0.,  0.,  0.,  0.
+    };
+    for(size_t ij = 0; ij < nx * nx; ij++)
+        ok &= H_1[ij] == check_H_1[ij];
+    // -----------------------------------------------------------------------
+    // Record g
+    // -----------------------------------------------------------------------
+    //
+    // af
+    CppAD::ADFun< AD<double>, double> af = f.base2ad();
+    //
+    // az
+    CppAD::Independent(ax);
+    CPPAD_TESTVECTOR( AD<double> ) ax1(nx), ay1(ny), az(nx);
+    af.Forward(0, ax);
+    for(size_t j = 0; j < nx; ++j)
+        ax1[j] = 0.0;
+    for(size_t j = 0; j < nx; ++j)
+    {   ax1[j]    = 1.0;
+        ay1       = af.Forward(1, ax1);
+        ax1[j]    = 0.0;
+        az[j]    = ay1[1];
+    }
+    // g
+    CppAD::ADFun<double> g(ax, az);
+    // -----------------------------------------------------------------------
+    // Forward mode on g
+    // -----------------------------------------------------------------------
+    //
+    // z
+    // zero order forward mode computation of g(x)
+    CPPAD_TESTVECTOR(double) z(nx);
+    z = g.Forward(0, x);
+    //
+    // check z
+    for(size_t j = 0; j < nx; ++j)
+        ok &= z[j] == J[1 * nx + j];
+    //
+    // z1
+    CPPAD_TESTVECTOR(double) z1(nx);
+    for(size_t j = 0; j < nx; ++j)
+    {   x1[j] = 1.0;
+        z1    = g.Forward(1, x1);
+        x1[j] = 0.0;
+        for(size_t i = 0; i < nx; ++i)
+            ok &= z1[i] == check_H_1[i * nx + j];
+    }
+    // ----------------------------------------------------------------
+    return ok;
+}
+// END C++
diff --git a/example/atomic_four/mat_mul/identical_zero.cpp b/example/atomic_four/mat_mul/identical_zero.cpp
new file mode 100644
index 000000000..694b6230c
--- /dev/null
+++ b/example/atomic_four/mat_mul/identical_zero.cpp
@@ -0,0 +1,159 @@
+/* --------------------------------------------------------------------------
+CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
+
+CppAD is distributed under the terms of the
+             Eclipse Public License Version 2.0.
+
+This Source Code may also be made available under the following
+Secondary License when the conditions 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_four_mat_mul_identical_zero.cpp$$
+$spell
+    enum
+$$
+
+$section Atomic Matrix Multiply Identical Zero: Example and Test$$
+
+$head Purpose$$
+This example demonstrates how the
+$cref atomic_four_mat_mul_for_type.hpp$$
+routine uses the $icode identical_zero_enum$$ type to reduce the number
+of variables.
+
+$head Zero$$
+The first case computes the following matrix product
+$latex \[
+\left( \begin{array}{ccc}
+u_0 & 0   & 0 \\
+0   & u_1 & 0 \\
+0   & 0   & u_2
+\end{array} \right)
+\left( \begin{array}{ccc}
+u_3 & 0   & 0 \\
+0   & u_4 & 0 \\
+0   & 0   & u_5
+\end{array} \right)
+=
+\left( \begin{array}{ccc}
+u_0 u_3 & 0       & 0 \\
+0       & u_1 u_4 & 0 \\
+0       & 0       & u_2 u_5
+\end{array} \right)
+\] $$
+The result matrix for this case has three variables,
+one for each product on the diagonal.
+
+$head One$$
+The second case computes the following matrix product
+$latex \[
+\left( \begin{array}{ccc}
+u_0 & 1   & 1 \\
+1   & u_1 & 1 \\
+1   & 1   & u_2
+\end{array} \right)
+\left( \begin{array}{ccc}
+u_3 & 1   & 1 \\
+1   & u_4 & 1 \\
+1   & 1   & u_5
+\end{array} \right)
+=
+\left( \begin{array}{ccc}
+u_0 u_3 + 2   & u_0 + u_3 + 1 & u_0 + u_5 + 1 \\
+u_1 + u_3 + 1 & u_1 u_4 + 2   & u_1 + u_5 + 1  \\
+u_2 + u_3 + 1 & u_2 + u_4 + 1 & u_2 u_5 + 2
+\end{array} \right)
+\] $$
+The result matrix for this case has nine variables,
+one for each of its elements.
+
+$head Source$$
+$srcthisfile%0%// BEGIN C++%// END C++%1%$$
+$end
+*/
+// BEGIN C++
+# include <cppad/cppad.hpp>
+# include <cppad/example/atomic_four/mat_mul/mat_mul.hpp>
+
+bool identical_zero(void)
+{   // ok, eps
+    bool ok = true;
+    //
+    // AD, NearEqual
+    using CppAD::AD;
+    using CppAD::NearEqual;
+    // -----------------------------------------------------------------------
+    // Record f
+    // -----------------------------------------------------------------------
+    //
+    // afun
+    CppAD::atomic_mat_mul<double> afun("atomic_mat_mul");
+    //
+    // nleft
+    size_t size = 3;
+    //
+    // size_var
+    size_t size_var[2];
+    //
+    // zero_one
+    for(size_t zero_one = 0; zero_one < 2; ++zero_one)
+    {   //
+        // n_right, n_middle
+        size_t n_left = size, n_middle = size, n_right = size;
+        //
+        // nu, au
+        size_t nu = 2 * size;
+        CPPAD_TESTVECTOR( AD<double> ) au(nu);
+        for(size_t j = 0; j < nu; ++j)
+            au[j] = AD<double>(j + 2);
+        CppAD::Independent(au);
+        //
+        // offset
+        size_t offset = size * size;
+        //
+        // nx, ax
+        size_t nx = size * (size + size);
+        CPPAD_TESTVECTOR( AD<double> ) ax(nx);
+        for(size_t i = 0; i < size; ++i)
+        {   for(size_t j = 0; j < size; ++j)
+            {   // left
+                size_t ij = i * size + j;
+                if( i == j )
+                    ax[ij] = au[j];
+                else
+                    ax[ij] = AD<double>(zero_one);
+                // right
+                ij = offset + i * n_right + j;
+                if( i == j )
+                    ax[ij] = au[i];
+                else
+                    ax[ij] = AD<double>(zero_one);
+            }
+        }
+        //
+        // ay
+        size_t ny = size * size;
+        CPPAD_TESTVECTOR( AD<double> ) ay(ny);
+        size_t call_id = afun.set(n_left, n_middle, n_right);
+        afun(call_id, ax, ay);
+        //
+        // av
+        size_t nv = size;
+        CPPAD_TESTVECTOR( AD<double> ) av(nv);
+        for(size_t i = 0; i < nv; ++i)
+            av[i] += ay[i * size + i];
+        //
+        // f
+        CppAD::ADFun<double> f(au, av);
+        //
+        // size_var
+        size_var[zero_one] = f.size_var();
+    }
+    // ok
+    ok = size_var[1] - size_var[0] == size * size - size;
+    //
+    return ok;
+}
+// END C++
diff --git a/example/atomic_four/mat_mul/mat_mul.cpp b/example/atomic_four/mat_mul/mat_mul.cpp
new file mode 100644
index 000000000..f42aa6251
--- /dev/null
+++ b/example/atomic_four/mat_mul/mat_mul.cpp
@@ -0,0 +1,58 @@
+/* --------------------------------------------------------------------------
+CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
+
+CppAD is distributed under the terms of the
+             Eclipse Public License Version 2.0.
+
+This Source Code may also be made available under the following
+Secondary License when the conditions 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_HAS_* defines
+# include <cppad/configure.hpp>
+
+// system include files used for I/O
+# include <iostream>
+
+// C style asserts
+# include <cassert>
+
+// for thread_alloc
+# include <cppad/utility/thread_alloc.hpp>
+
+// test runner
+# include <cppad/utility/test_boolofvoid.hpp>
+
+// BEGIN_SORT_THIS_LINE_PLUS_1
+extern bool forward(void);
+extern bool identical_zero(void);
+extern bool rev_depend(void);
+extern bool reverse(void);
+extern bool sparsity(void);
+// END_SORT_THIS_LINE_MINUS_1
+
+// main program that runs all the tests
+int main(void)
+{   std::string group = "example/atomic_four/mat_mul";
+    size_t      width = 20;
+    CppAD::test_boolofvoid Run(group, width);
+
+    // This line is used by test_one.sh
+
+    // BEGIN_SORT_THIS_LINE_PLUS_1
+    Run( forward,             "forward"        );
+    Run( identical_zero,      "identical_zero" );
+    Run( rev_depend,          "rev_depend"     );
+    Run( reverse,             "reverse"        );
+    Run( sparsity,            "sparsity"       );
+    // END_SORT_THIS_LINE_MINUS_1
+
+    // check for memory leak
+    bool memory_ok = CppAD::thread_alloc::free_all();
+    // print summary at end
+    bool ok = Run.summary(memory_ok);
+    //
+    return static_cast<int>( ! ok );
+}
diff --git a/example/atomic_four/mat_mul/rev_depend.cpp b/example/atomic_four/mat_mul/rev_depend.cpp
new file mode 100644
index 000000000..e6c4ece48
--- /dev/null
+++ b/example/atomic_four/mat_mul/rev_depend.cpp
@@ -0,0 +1,133 @@
+/* --------------------------------------------------------------------------
+CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
+
+CppAD is distributed under the terms of the
+             Eclipse Public License Version 2.0.
+
+This Source Code may also be made available under the following
+Secondary License when the conditions 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_four_mat_mul_rev_depend.cpp$$
+$spell
+    var
+$$
+
+$section Atomic Matrix Multiply Reverse Dependency: Example and Test$$
+
+$head Purpose$$
+This example uses the atomic matrix multiply
+$code rev_depend$$ function to reduce the number of variables in
+the recording of $latex g(u)$$.
+
+
+$head f(u)$$
+$latex \[
+f(u) =
+\left( \begin{array}{cc}
+2 u_0 & 2 u_1  \\
+2 u_2 & 2 u_3  \\
+\end{array} \right)
+\left( \begin{array}{cc}
+2 u_4 & 2 u_5  \\
+2 u_6 & 2 u_7
+\end{array} \right)
+=
+\left( \begin{array}{cc}
+4( u_0 u_4 + u_1 u_6 )  & 4( u_0 u_5 + u_1 u_7 )  \\
+4( u_2 u_4 + u_3 u_6 )  & 4( u_2 u_5 + u_3 u_7 )  \\
+\end{array} \right)
+\] $$
+$latex \[
+f_{0,0} (u)
+=
+4 ( u_0 u_4 + u_1 u_6 )
+\] $$
+
+$head Forward Analysis$$
+Forward dependency analysis determines that there
+is a new variable for each of the 8 multiplications by 2.0.
+It also determines, using $cref/for_type/atomic_four_mat_mul_for_type.hpp/$$
+that each of the 4 elements in the matrix product result is a new variable.
+
+$head Reverse Analysis$$
+Reverse analysis detect that only 1 of the 4 elements
+in the matrix product is used.
+In addition it determines,
+using $cref/rev_depend/atomic_four_mat_mul_rev_depend.hpp/$$,
+that only 4 of the 8 multiplications by 2.0 are used.
+
+$head size_var$$
+The difference in $cref/size_var/fun_property/size_var/$$
+is the difference between only using forward dependency and using both; i.e.,
+(8 - 4) + (4 - 1) = 7.
+
+
+$head Source$$
+$srcthisfile%0%// BEGIN C++%// END C++%1%$$
+$end
+*/
+// BEGIN C++
+# include <cppad/cppad.hpp>
+# include <cppad/example/atomic_four/mat_mul/mat_mul.hpp>
+
+bool rev_depend(void)
+{   // ok, eps
+    bool ok = true;
+    //
+    // AD
+    using CppAD::AD;
+    using CppAD::sparse_rc;
+    // -----------------------------------------------------------------------
+    // Record g
+    // -----------------------------------------------------------------------
+    //
+    // afun
+    CppAD::atomic_mat_mul<double> afun("atomic_mat_mul");
+    //
+    // nleft, n_middle, n_right
+    size_t n_left = 2, n_middle = 2, n_right = 2;
+    //
+    // nu, au
+    size_t nu = n_middle * (n_left + n_right);
+    CPPAD_TESTVECTOR( AD<double> ) au(nu);
+    for(size_t j = 0; j < nu; ++j)
+        au[j] = AD<double>(j + 2);
+    CppAD::Independent(au);
+    //
+    // nx, ax
+    CPPAD_TESTVECTOR( AD<double> ) ax(nu);
+    for(size_t j = 0; j < nu; ++j)
+        ax[j] = 2.0 * au[j];
+    //
+    // ny, ay
+    size_t ny = n_left * n_right;
+    CPPAD_TESTVECTOR( AD<double> ) ay(ny);
+    size_t call_id = afun.set(n_left, n_middle, n_right);
+    afun(call_id, ax, ay);
+    //
+    // az = f_{0,0} (x)
+    CPPAD_TESTVECTOR( AD<double> ) az(1);
+    az[0] = ay[ 0 * n_right + 0 ];
+    //
+    // g
+    CppAD::ADFun<double> g(au, az);
+    //
+    // size_var_before
+    size_t size_var_before = g.size_var();
+    //
+    //
+    // optimize
+    g.optimize();
+    //
+    // size_var_after
+    size_t size_var_after = g.size_var();
+    //
+    // ok
+    ok &= size_var_before - size_var_after == 7;
+    //
+    return ok;
+}
+// END C++
diff --git a/example/atomic_four/mat_mul/reverse.cpp b/example/atomic_four/mat_mul/reverse.cpp
new file mode 100644
index 000000000..caae04ee8
--- /dev/null
+++ b/example/atomic_four/mat_mul/reverse.cpp
@@ -0,0 +1,242 @@
+/* --------------------------------------------------------------------------
+CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
+
+CppAD is distributed under the terms of the
+             Eclipse Public License Version 2.0.
+
+This Source Code may also be made available under the following
+Secondary License when the conditions 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_four_mat_mul_reverse.cpp$$
+$spell
+    Jacobian
+$$
+
+$section Atomic Matrix Multiply Reverse Mode: Example and Test$$
+
+$head Purpose$$
+This example demonstrates using reverse mode
+with the $cref atomic_four_mat_mul$$ class.
+
+$head f(x)$$
+For this example, the function $latex f(x)$$ is
+$latex \[
+f(x) =
+\left( \begin{array}{ccc}
+x_0 & x_1 & x_2  \\
+x_3 & x_4 & x_5
+\end{array} \right)
+\left( \begin{array}{c}
+x_6 \\
+x_7 \\
+x_8
+\end{array} \right)
+=
+\left( \begin{array}{c}
+x_0 * x_6 + x_1 * x_7 + x_2 * x_8 \\
+x_3 * x_6 + x_4 * x_7 + x_5 * x_8
+\end{array} \right)
+\] $$
+
+$head Jacobian of f(x)$$
+The Jacobian of $latex f(x)$$ is
+$latex \[
+f^{(1)} (x) = \left( \begin{array}{cccccccccc}
+    x_6 & x_7 & x_8 & 0   & 0   & 0   & x_0 & x_1 & x_2 \\
+    0   & 0   & 0   & x_6 & x_7 & x_8 & x_3 & x_4 & x_5
+\end{array} \right)
+\] $$
+
+$head g(x)$$
+We define the function $latex g(x) = f_0^{(1)} (x)^\R{T}$$; i.e.,
+$latex \[
+g(x) = ( x_6, x_7, x_8, 0, 0, 0, x_0, x_1, x_2 )^\R{T}
+\] $$
+
+$head Hessian$$
+The Hessian of $latex f_1(x)$$ is the Jacobian
+of $latex g(x)$$; i.e.,
+$latex \[
+f_1^{(2)} (x)
+=
+g^{(1)} (x)
+=
+\left( \begin{array}{ccccccccc}
+    % 0   1   2   3   4   5   6   7   8
+      0 & 0 & 0 & 0 & 0 & 0 & 1 & 0 & 0   \\ % 0
+      0 & 0 & 0 & 0 & 0 & 0 & 0 & 1 & 0   \\ % 1
+      0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 1   \\ % 2
+      0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0   \\ % 3
+      0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0   \\ % 4
+      0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0   \\ % 5
+      1 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0   \\ % 6
+      0 & 1 & 0 & 0 & 0 & 0 & 0 & 0 & 0   \\ % 7
+      0 & 0 & 1 & 0 & 0 & 0 & 0 & 0 & 0   \\ % 8
+\end{array} \right)
+\] $$
+
+$head Source$$
+$srcthisfile%0%// BEGIN C++%// END C++%1%$$
+$end
+*/
+// BEGIN C++
+# include <cppad/cppad.hpp>
+# include <cppad/example/atomic_four/mat_mul/mat_mul.hpp>
+
+bool reverse(void)
+{   // ok, eps
+    bool ok = true;
+    //
+    // AD, NearEqual
+    using CppAD::AD;
+    using CppAD::NearEqual;
+    // -----------------------------------------------------------------------
+    // Record f
+    // -----------------------------------------------------------------------
+    //
+    // afun
+    CppAD::atomic_mat_mul<double> afun("atomic_mat_mul");
+    //
+    // nleft, n_middle, n_right
+    size_t n_left = 2, n_middle = 3, n_right = 1;
+    //
+    // nx, ax
+    size_t nx = n_middle * (n_left + n_right);
+    CPPAD_TESTVECTOR( AD<double> ) ax(nx);
+    for(size_t j = 0; j < nx; ++j)
+        ax[j] = AD<double>(j + 2);
+    CppAD::Independent(ax);
+    //
+    // ny, ay
+    size_t ny = n_left * n_right;
+    CPPAD_TESTVECTOR( AD<double> ) ay(ny);
+    //
+    // ay
+    size_t call_id = afun.set(n_left, n_middle, n_right);
+    afun(call_id, ax, ay);
+    //
+    // f
+    CppAD::ADFun<double> f(ax, ay);
+    // -----------------------------------------------------------------------
+    // Reverse mode on f
+    // -----------------------------------------------------------------------
+    //
+    // x
+    CPPAD_TESTVECTOR(double) x(nx);
+    for(size_t j = 0; j < nx; ++j)
+        x[j] = double(3 + nx - j);
+    //
+    // y
+    // zero order forward mode computation of f(x)
+    CPPAD_TESTVECTOR(double) y(nx);
+    y = f.Forward(0, x);
+    //
+    // check_y
+    double check_y[] = {
+        x[0] * x[6] + x[1] * x[7] + x[2] * x[8],
+        x[3] * x[6] + x[4] * x[7] + x[5] * x[8]
+    };
+    for(size_t i = 0; i < ny; ++i)
+        ok &= y[i] == check_y[i];
+    //
+    // J
+    // first order reverse mode computation of f'(x)
+    CPPAD_TESTVECTOR(double) w1(ny), dw1(nx), J(ny * nx);
+    for(size_t i = 0; i < ny; ++i)
+        w1[i] = 0.0;
+    for(size_t i = 0; i < ny; ++i)
+    {   w1[i] = 1.0;
+        dw1   = f.Reverse(1, w1);
+        w1[i] = 0.0;
+        for(size_t j = 0; j < nx; ++j)
+            J[i * nx + j] = dw1[j];
+    }
+    //
+    // check_J
+    double check_J[] = {
+        x[6], x[7], x[8],  0.0,  0.0,  0.0, x[0], x[1], x[2],
+         0.0,  0.0,  0.0, x[6], x[7], x[8], x[3], x[4], x[5]
+    };
+    for(size_t ij = 0; ij < ny * nx; ij++)
+        ok &= J[ij] == check_J[ij];
+    //
+    // H_0
+    // Second order reverse mode computaiton of f_0^2 (x)
+    CPPAD_TESTVECTOR(double) x1(nx), w2(ny), dw2(2 * nx), H_0(nx * nx);
+    for(size_t i = 0; i < ny; ++i)
+        w2[i] = 0.0;
+    w2[0] = 1.0;
+    for(size_t j = 0; j < nx; ++j)
+        x1[j] = 0.0;
+    for(size_t i = 0; i < nx; ++i)
+    {   x1[i] = 1.0;
+        f.Forward(1, x1);
+        x1[i] = 0.0;
+        dw2 = f.Reverse(2, w2);
+        for(size_t j = 0; j < nx; ++j)
+            H_0[i * nx + j] = dw2[2 * j + 1];
+    }
+    //
+    // check_H_0
+    assert( nx == 9 );
+    double check_H_0[] = {
+        0.,  0.,  0.,  0.,  0.,  0.,  1.,  0.,  0.,
+        0.,  0.,  0.,  0.,  0.,  0.,  0.,  1.,  0.,
+        0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  1.,
+        0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,
+        0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,
+        0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,
+        1.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,
+        0.,  1.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,
+        0.,  0.,  1.,  0.,  0.,  0.,  0.,  0.,  0,
+    };
+    for(size_t ij = 0; ij < nx * nx; ij++)
+        ok &= H_0[ij] == check_H_0[ij];
+    // -----------------------------------------------------------------------
+    // Record g
+    // -----------------------------------------------------------------------
+    //
+    // af
+    CppAD::ADFun< AD<double>, double> af = f.base2ad();
+    //
+    // az
+    CppAD::Independent(ax);
+    CPPAD_TESTVECTOR( AD<double> ) aw(ny), az(nx);
+    af.Forward(0, ax);
+    for(size_t i = 0; i < ny; ++i)
+        aw[i] = 0.0;
+    aw[0] = 1.0;
+    az = af.Reverse(1, aw);
+    // g
+    CppAD::ADFun<double> g(ax, az);
+    // -----------------------------------------------------------------------
+    // Forward mode on g
+    // -----------------------------------------------------------------------
+    //
+    // z
+    // zero order forward mode computation of g(x)
+    CPPAD_TESTVECTOR(double) z(nx);
+    z = g.Forward(0, x);
+    //
+    // check z
+    for(size_t j = 0; j < nx; ++j)
+        ok &= z[j] == J[0 * nx + j];
+    //
+    // z1
+    CPPAD_TESTVECTOR(double) w(nx), dw(nx);
+    for(size_t i = 0; i < nx; ++i)
+        w[i] = 0.0;
+    for(size_t i = 0; i < nx; ++i)
+    {   w[i] = 1.0;
+        dw   = g.Reverse(1, w);
+        w[i] = 0.0;
+        for(size_t j = 0; j < nx; ++j)
+            ok &= dw[j] == check_H_0[i * nx + j];
+    }
+    // ----------------------------------------------------------------
+    return ok;
+}
+// END C++
diff --git a/example/atomic_four/mat_mul/sparsity.cpp b/example/atomic_four/mat_mul/sparsity.cpp
new file mode 100644
index 000000000..61d12fe26
--- /dev/null
+++ b/example/atomic_four/mat_mul/sparsity.cpp
@@ -0,0 +1,228 @@
+/* --------------------------------------------------------------------------
+CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
+
+CppAD is distributed under the terms of the
+             Eclipse Public License Version 2.0.
+
+This Source Code may also be made available under the following
+Secondary License when the conditions 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_four_mat_mul_sparsity.cpp$$
+$spell
+    Jacobian
+$$
+
+$section Atomic Matrix Multiply Sparsity Patterns: Example and Test$$
+
+$head Purpose$$
+This example demonstrates using sparsity mode with
+the $cref atomic_four_mat_mul$$ class.
+
+$head f(x)$$
+For a matrix $latex A$$ we define the function $latex \R{rvec} ( A )$$
+to be the elements of $latex A$$ in row major order.
+For this example, the function $latex f(x)$$ is
+$latex \[
+f(x) =
+\R{rvec} \left[
+\left( \begin{array}{cc}
+x_0 & x_1  \\
+x_2 & x_3  \\
+\end{array} \right)
+\left( \begin{array}{cc}
+x_4 & x_5  \\
+x_6 & x_7
+\end{array} \right)
+\right]
+=
+\R{rvec}
+\left( \begin{array}{cc}
+x_0 x_4 + x_1 x_6 & x_0 x_5 + x_1 x_7  \\
+x_2 x_4 + x_3 x_6 & x_2 x_5 + x_3 x_7  \\
+\end{array} \right)
+\] $$
+$latex \[
+f(x)
+=
+\left( \begin{array}{c}
+x_0 x_4 + x_1 x_6 \\
+x_0 x_5 + x_1 x_7 \\
+x_2 x_4 + x_3 x_6 \\
+x_2 x_5 + x_3 x_7
+\end{array} \right)
+\] $$
+
+$head Jacobian of f(x)$$
+The Jacobian of $latex f(x)$$ is
+$latex \[
+f^{(1)} (x) = \left( \begin{array}{cccccccc}
+% 0   1     2     3      4      5     6      7
+x_4 & x_6 & 0   & 0    & x_0  & 0   & x_1  & 0   \\ % 0
+x_5 & x_7 & 0   & 0    & 0    & x_0 & 0    & x_1 \\ % 1
+0   & 0   & x_4 & x_6  & x_2  & 0   & x_3  & 0   \\ % 2
+0   & 0   & x_5 & x_7  & 0    & x_2 & 0    & x_3 \\ % 3
+\end{array} \right)
+\] $$
+
+$head Hessian$$
+The function $latex f_2 (x)$$ is
+$latex \[
+    f_2 (x) = x_2 x_4 + x_3 x_6
+\] $$
+The Hessian of $latex f_2(x)$$ is
+$latex \[
+f_2^{(2)} (x)
+=
+\left( \begin{array}{cccccccccc}
+            & 0    & 1    & 2    & 3    & 4    & 5    & 6    & 7    \\
+            & -    & -    & -    & -    & -    & -    & -    & -    \\
+    0 \; |  & 0    & 0    & 0    & 0    & 0    & 0    & 0    & 0    \\
+    1 \; |  & 0    & 0    & 0    & 0    & 0    & 0    & 0    & 0    \\
+    2 \; |  & 0    & 0    & 0    & 0    & 1    & 0    & 0    & 0    \\
+    3 \; |  & 0    & 0    & 0    & 0    & 0    & 0    & 1    & 0    \\
+    4 \; |  & 0    & 0    & 1    & 0    & 0    & 0    & 0    & 0    \\
+    5 \; |  & 0    & 0    & 0    & 0    & 0    & 0    & 0    & 0    \\
+    6 \; |  & 0    & 0    & 0    & 1    & 0    & 0    & 0    & 0    \\
+    7 \; |  & 0    & 0    & 0    & 0    & 0    & 0    & 0    & 0    \\
+\end{array} \right)
+\] $$
+where the first row is the column index,
+and the first column is the row index,
+for the corresponding matrix entries above.
+
+$head Source$$
+$srcthisfile%0%// BEGIN C++%// END C++%1%$$
+$end
+*/
+// BEGIN C++
+# include <cppad/cppad.hpp>
+# include <cppad/example/atomic_four/mat_mul/mat_mul.hpp>
+
+bool sparsity(void)
+{   // ok, eps
+    bool ok = true;
+    //
+    // AD
+    using CppAD::AD;
+    using CppAD::sparse_rc;
+    // -----------------------------------------------------------------------
+    // Record f
+    // -----------------------------------------------------------------------
+    //
+    // afun
+    CppAD::atomic_mat_mul<double> afun("atomic_mat_mul");
+    //
+    // nleft, n_middle, n_right
+    size_t n_left = 2, n_middle = 2, n_right = 2;
+    //
+    // nx, ax
+    size_t nx = n_middle * (n_left + n_right);
+    CPPAD_TESTVECTOR( AD<double> ) ax(nx);
+    for(size_t j = 0; j < nx; ++j)
+        ax[j] = AD<double>(j + 2);
+    CppAD::Independent(ax);
+    //
+    // ny, ay
+    size_t ny = n_left * n_right;
+    CPPAD_TESTVECTOR( AD<double> ) ay(ny);
+    //
+    // ay
+    size_t call_id = afun.set(n_left, n_middle, n_right);
+    afun(call_id, ax, ay);
+    //
+    // f
+    CppAD::ADFun<double> f(ax, ay);
+    //
+    // s_vector
+    typedef CPPAD_TESTVECTOR(size_t) s_vector;
+    //
+    // eye_sparsity
+    // nx by nx identitty matrix
+    sparse_rc<s_vector> eye_sparsity;
+    eye_sparsity.resize(nx, nx, nx);
+    for(size_t i = 0; i < nx; ++i)
+        eye_sparsity.set(i, i, i);
+    //
+    // -----------------------------------------------------------------------
+    // jac_sparsity
+    bool transpose     = false;
+    bool dependency    = false;
+    bool internal_bool = false;
+    sparse_rc<s_vector> jac_sparsity;
+    f.for_jac_sparsity(
+        eye_sparsity, transpose, dependency, internal_bool, jac_sparsity
+    );
+    {   // check jac_sparsity
+        //
+        // row, col
+        const s_vector& row       = jac_sparsity.row();
+        const s_vector& col       = jac_sparsity.col();
+        s_vector        row_major = jac_sparsity.row_major();
+        //
+        // ok
+        ok &= jac_sparsity.nnz() == 16;
+        for(size_t k = 0; k < jac_sparsity.nnz(); ++k)
+            ok &= row[ row_major[k] ] == k / 4;
+        // row 0
+        ok &= col[ row_major[0] ]  == 0;
+        ok &= col[ row_major[1] ]  == 1;
+        ok &= col[ row_major[2] ]  == 4;
+        ok &= col[ row_major[3] ]  == 6;
+        // row 1
+        ok &= col[ row_major[4] ]  == 0;
+        ok &= col[ row_major[5] ]  == 1;
+        ok &= col[ row_major[6] ]  == 5;
+        ok &= col[ row_major[7] ]  == 7;
+        // row 2
+        ok &= col[ row_major[8] ]  == 2;
+        ok &= col[ row_major[9] ]  == 3;
+        ok &= col[ row_major[10] ] == 4;
+        ok &= col[ row_major[11] ] == 6;
+        // row 3
+        ok &= col[ row_major[12] ] == 2;
+        ok &= col[ row_major[13] ] == 3;
+        ok &= col[ row_major[14] ] == 5;
+        ok &= col[ row_major[15] ] == 7;
+    }
+    // ----------------------------------------------------------------
+    //
+    // select_y
+    // corresponding to f_2
+    CPPAD_TESTVECTOR(bool) select_y(ny);
+    for(size_t i = 0; i < ny; ++i)
+        select_y[i] = false;
+    select_y[2]   = true;
+    //
+    // hes_sparsity
+    transpose     = false;
+    internal_bool = false;
+    sparse_rc<s_vector> hes_sparsity;
+    f.rev_hes_sparsity(select_y, transpose, internal_bool, hes_sparsity);
+    {   // check hes_sparsity
+        //
+        // row, col
+        const s_vector& row       = hes_sparsity.row();
+        const s_vector& col       = hes_sparsity.col();
+        s_vector        row_major = hes_sparsity.row_major();
+        //
+        // ok
+        ok &= hes_sparsity.nnz() == 4;
+        //
+        ok &= row[ row_major[0] ] == 2;
+        ok &= col[ row_major[0] ] == 4;
+        //
+        ok &= row[ row_major[1] ] == 3;
+        ok &= col[ row_major[1] ] == 6;
+        //
+        ok &= row[ row_major[2] ] == 4;
+        ok &= col[ row_major[2] ] == 2;
+        //
+        ok &= row[ row_major[3] ] == 6;
+        ok &= col[ row_major[3] ] == 3;
+    }
+    return ok;
+}
+// END C++
diff --git a/example/atomic_four/norm_sq.cpp b/example/atomic_four/norm_sq.cpp
new file mode 100644
index 000000000..c9a4c1dd1
--- /dev/null
+++ b/example/atomic_four/norm_sq.cpp
@@ -0,0 +1,390 @@
+/* --------------------------------------------------------------------------
+CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
+
+CppAD is distributed under the terms of the
+             Eclipse Public License Version 2.0.
+
+This Source Code may also be made available under the following
+Secondary License when the conditions 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_four_norm_sq.cpp$$
+$spell
+    sq
+    bool
+    enum
+$$
+
+$section Atomic Euclidean Norm Squared: Example and Test$$
+
+$head Function$$
+This example demonstrates using $cref atomic_four$$
+to define the operation
+$latex g : \B{R}^n \rightarrow \B{R}$$ where
+$latex \[
+    g(x) =  x_0^2 + \cdots + x_{n-1}^2
+\] $$
+
+$head Purpose$$
+This atomic function demonstrates the following cases:
+$list number$$
+an arbitrary number of arguments $icode n$$
+$lnext
+zero and first order forward mode.
+$lnext
+first order derivatives using reverse mode.
+$lend
+
+$head Define Atomic Function$$
+$srcthisfile%0
+    %// BEGIN_DEFINE_ATOMIC_FUNCTION%// END_DEFINE_ATOMIC_FUNCTION%
+1%$$
+
+$head Use Atomic Function$$
+$srcthisfile%0
+    %// BEGIN_USE_ATOMIC_FUNCTION%// END_USE_ATOMIC_FUNCTION%
+1%$$
+
+$end
+*/
+# include <cppad/cppad.hpp>
+
+// BEGIN_DEFINE_ATOMIC_FUNCTION
+// empty namespace
+namespace {
+    // BEGIN CONSTRUCTOR
+    class atomic_norm_sq : public CppAD::atomic_four<double> {
+    public:
+        atomic_norm_sq(const std::string& name) :
+        CppAD::atomic_four<double>(name)
+        { }
+    // END CONSTRUCTOR
+    private:
+        // BEGIN FOR_TYPE
+        bool for_type(
+            size_t                                     call_id     ,
+            const CppAD::vector<CppAD::ad_type_enum>&  type_x      ,
+            CppAD::vector<CppAD::ad_type_enum>&        type_y      ) override
+        {   assert( call_id == 0 );       // default value
+            assert(type_y.size() == 1 );  // m
+            //
+            // type_y
+            size_t n     = type_x.size();
+            type_y[0] = CppAD::constant_enum;
+            for(size_t j = 0; j < n; ++j)
+                type_y[0] = std::max(type_y[0], type_x[j]);
+            return true;
+        }
+        // END FOR_TYPE
+        // BEGIN FORWARD
+        bool forward(
+            size_t                             call_id     ,
+            const CppAD::vector<bool>&         select_y    ,
+            size_t                             order_low   ,
+            size_t                             order_up    ,
+            const CppAD::vector<double>&       tx          ,
+            CppAD::vector<double>&             ty          ) override
+        {
+            size_t q = order_up + 1;
+            size_t n = tx.size() / q;
+    # ifndef NDEBUG
+            size_t m = ty.size() / q;
+            assert( call_id == 0 );
+            assert( m == 1 );
+            assert( m == select_y.size() );
+    # endif
+            // ok
+            bool ok = order_up <= 1 && order_low <= order_up;
+            if ( ! ok )
+                return ok;
+            //
+            // sum = x_0^0 * x_0^0 + x_1^0 * x_1^0 + ...
+            double sum = 0.0;
+            for(size_t j = 0; j < n; ++j)
+            {   double xj0 = tx[ j * q + 0];
+                sum       += xj0 * xj0;
+            }
+            //
+            // ty[0] = sum
+            if( order_low <= 0 )
+                ty[0] = sum;
+            if( order_up < 1 )
+                return ok;
+
+            // sum = x_0^0 * x_0^1 + x_1^0 ^ x_1^1 + ...
+            sum   = 0.0;
+            for(size_t j = 0; j < n; ++j)
+            {   double xj0 = tx[ j * q + 0];
+                double xj1 = tx[ j * q + 1];
+                sum       += xj0 * xj1;
+            }
+            // ty[1] = 2.0 * sum
+            assert( order_up == 1 );
+            ty[1] = 2.0 * sum;
+            return ok;
+
+            // Assume we are not using forward mode with order > 1
+            assert( ! ok );
+            return ok;
+        }
+        // END FORWARD
+        // BEGIN REVERSE
+        bool reverse(
+            size_t                              call_id     ,
+            const CppAD::vector<bool>&          select_x    ,
+            size_t                              order_up    ,
+            const CppAD::vector<double>&        tx          ,
+            const CppAD::vector<double>&        ty          ,
+            CppAD::vector<double>&              px          ,
+            const CppAD::vector<double>&        py          ) override
+        {
+            size_t q = order_up + 1;
+            size_t n = tx.size() / q;
+    # ifndef NDEBUG
+            size_t m = ty.size() / q;
+            assert( call_id == 0 );
+            assert( m == 1 );
+            assert( px.size() == tx.size() );
+            assert( py.size() == ty.size() );
+            assert( n == select_x.size() );
+    # endif
+            // ok
+            bool ok = order_up == 0;
+            if ( ! ok )
+                return ok;
+
+            // first order reverse mode
+            for(size_t j = 0; j < n; ++j)
+            {   // x_0^0
+                double xj0 = tx[ j * q + 0];
+                //
+                // H = G( F( { x_j^k } ) )
+                double dF = 2.0 * xj0; // partial F w.r.t x_j^0
+                double dG = py[0];     // partial of G w.r.t. y[0]
+                double dH = dG * dF;   // partial of H w.r.t. x_j^0
+
+                // px[j]
+                px[j] = dH;
+            }
+            return ok;
+        }
+        // END REVERSE
+        // BEGIN JAC_SPARSITY
+        bool jac_sparsity(
+            size_t                                     call_id     ,
+            bool                                       dependency  ,
+            const CppAD::vector<bool>&                 select_x    ,
+            const CppAD::vector<bool>&                 select_y    ,
+            CppAD::sparse_rc< CppAD::vector<size_t> >& pattern_out ) override
+        {   size_t n = select_x.size();
+            size_t m = select_y.size();
+# ifndef NDEBUG
+            assert( call_id == 0 );
+            assert( m == 1 );
+# endif
+            // nnz
+            size_t nnz = 0;
+            if( select_y[0] )
+            {   for(size_t j = 0; j < n; ++j)
+                {   if( select_x[j] )
+                        ++nnz;
+                }
+            }
+            // pattern_out
+            pattern_out.resize(m, n, nnz);
+            size_t k = 0;
+            if( select_y[0] )
+            {   for(size_t j = 0; j < n; ++j)
+                {   if( select_x[j] )
+                        pattern_out.set(k++, 0, j);
+                }
+            }
+            assert( k == nnz );
+            return true;
+        }
+        // END JAC_SPARSITY
+        // BEGIN HES_SPARSITY
+        bool hes_sparsity(
+            size_t                                     call_id     ,
+            const CppAD::vector<bool>&                 select_x    ,
+            const CppAD::vector<bool>&                 select_y    ,
+            CppAD::sparse_rc< CppAD::vector<size_t> >& pattern_out ) override
+        {   size_t n = select_x.size();
+# ifndef NDEBUG
+            size_t m = select_y.size();
+            assert( call_id == 0 );
+            assert( m == 1 );
+# endif
+            // nnz
+            size_t nnz = 0;
+            if( select_y[0] )
+            {   for(size_t j = 0; j < n; ++j)
+                {   if( select_x[j] )
+                        ++nnz;
+                }
+            }
+            // pattern_out
+            pattern_out.resize(n, n, nnz);
+            size_t k = 0;
+            if( select_y[0] )
+            {   for(size_t j = 0; j < n; ++j)
+                {   if( select_x[j] )
+                        pattern_out.set(k++, j, j);
+                }
+            }
+            return true;
+        }
+        // END HES_SPARSITY
+        // BEGIN REV_DEPEND
+        bool rev_depend(
+            size_t                                     call_id     ,
+            CppAD::vector<bool>&                       depend_x    ,
+            const CppAD::vector<bool>&                 depend_y    ) override
+        {   size_t n = depend_x.size();
+# ifndef NDEBUG
+            size_t m = depend_y.size();
+            assert( call_id == 0 );
+            assert( m == 1 );
+# endif
+            for(size_t j = 0; j < n; ++j)
+                depend_x[j] = depend_y[0];
+            //
+            return true;
+        }
+        // END REV_DEPEND
+    };
+}
+// END_DEFINE_ATOMIC_FUNCTION
+
+// BEGIN_USE_ATOMIC_FUNCTION
+bool norm_sq(void)
+{   // ok, eps
+    bool ok    = true;
+    double eps = 10. * CppAD::numeric_limits<double>::epsilon();
+    //
+    // atom_norm_sq
+    atomic_norm_sq afun("atomic_norm_sq");
+    //
+    // n, m
+    size_t n = 2;
+    size_t m = 1;
+    //
+    // x
+    CPPAD_TESTVECTOR(double) x(n);
+    for(size_t j = 0; j < n; ++j)
+        x[j] = 1.0 / (double(j) + 1.0);
+    //
+    // ax
+    CPPAD_TESTVECTOR( CppAD::AD<double> ) ax(n);
+    for(size_t j = 0; j < n; ++j)
+        ax[j] = x[j];
+    CppAD::Independent(ax);
+    //
+    // ay
+    CPPAD_TESTVECTOR( CppAD::AD<double> ) ay(m);
+    afun(ax, ay);
+    //
+    // f
+    CppAD::ADFun<double> f;
+    f.Dependent (ax, ay);
+    //
+    // check
+    double check = 0.0;
+    for(size_t j = 0; j < n; ++j)
+        check += x[j] * x[j];
+    //
+    // ok
+    // check ay[0]
+    ok &= CppAD::NearEqual( Value(ay[0]) , check,  eps, eps);
+    //
+    // ok
+    // check zero order forward mode
+    CPPAD_TESTVECTOR(double) y(m);
+    y   = f.Forward(0, x);
+    ok &= CppAD::NearEqual(y[0] , check,  eps, eps);
+    //
+    // n2, check
+    size_t n2  = n / 2;
+    check      = 2.0 * x[n2];
+    //
+    // ok
+    // check first order forward mode partial w.r.t. x[n2]
+    CPPAD_TESTVECTOR(double) x1(n), y1(m);
+    for(size_t j = 0; j < n; ++j)
+            x1[j] = 0.0;
+    x1[n2] = 1.0;
+    y1     = f.Forward(1, x1);
+    ok    &= CppAD::NearEqual(y1[0] , check,  eps, eps);
+    //
+    // ok
+    // first order reverse mode
+    size_t q = 1;
+    CPPAD_TESTVECTOR(double)  w(m), dw(n * q);
+    w[0]  = 1.;
+    dw    = f.Reverse(q, w);
+    for(size_t j = 0; j < n; ++j)
+    {   check = 2.0 * x[j];
+        ok &= CppAD::NearEqual(dw[j] , check,  eps, eps);
+    }
+    //
+    // pattern_out
+    // reverse mode Jacobian sparstiy pattern
+    CppAD::sparse_rc< CPPAD_TESTVECTOR(size_t) > pattern_in, pattern_out;
+    pattern_in.resize(m, m, m);
+    for(size_t i = 0; i < m; ++i)
+        pattern_in.set(i, i, i);
+    bool transpose     = false;
+    bool dependency    = false;
+    bool internal_bool = false;
+    f.rev_jac_sparsity(
+        pattern_in, transpose, dependency, internal_bool, pattern_out
+    );
+    //
+    // ok
+    ok &= pattern_out.nnz() == n;
+    CPPAD_TESTVECTOR(size_t) row_major  = pattern_out.row_major();
+    for(size_t j = 0; j < n; ++j)
+    {   size_t r = pattern_out.row()[ row_major[j] ];
+        size_t c = pattern_out.col()[ row_major[j] ];
+        ok      &= r == 0 && c == j;
+    }
+    //
+    // pattern_out
+    // forward mode Hessian sparsity pattern
+    CPPAD_TESTVECTOR(bool) select_x(n), select_y(m);
+    for(size_t j = 0; j < n; ++j)
+        select_x[j] = true;
+    for(size_t i = 0; i < m; ++i)
+        select_y[i] = true;
+    internal_bool = false;
+    f.for_hes_sparsity(
+        select_x, select_y, internal_bool, pattern_out
+    );
+    //
+    // ok
+    ok &= pattern_out.nnz() == n;
+    row_major  = pattern_out.row_major();
+    for(size_t j = 0; j < n; ++j)
+    {   size_t r   = pattern_out.row()[ row_major[j] ];
+        size_t c   = pattern_out.col()[ row_major[j] ];
+        ok        &= r == j && c == j;
+    }
+    //
+    // optimize
+    // this uses the rev_depend overide above
+    f.optimize();
+    //
+    // ok
+    // check zero order forward mode (on optimized verison of f)
+    y     = f.Forward(0, x);
+    check = 0.0;
+    for(size_t j = 0; j < n; ++j)
+        check += x[j] * x[j];
+    ok &= CppAD::NearEqual(y[0] , check,  eps, eps);
+    //
+    return ok;
+}
+// END_USE_ATOMIC_FUNCTION
diff --git a/example/atomic_four/vector/CMakeLists.txt b/example/atomic_four/vector/CMakeLists.txt
new file mode 100644
index 000000000..700578a5d
--- /dev/null
+++ b/example/atomic_four/vector/CMakeLists.txt
@@ -0,0 +1,42 @@
+# -----------------------------------------------------------------------------
+# CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
+#
+# CppAD is distributed under the terms of the
+#              Eclipse Public License Version 2.0.
+#
+# This Source Code may also be made available under the following
+# Secondary License when the conditions 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_2
+SET(source_list
+    add.cpp
+    vector.cpp
+    div.cpp
+    hes_sparsity.cpp
+    jac_sparsity.cpp
+    mul.cpp
+    neg.cpp
+    rev_depend.cpp
+    sub.cpp
+)
+# END_SORT_THIS_LINE_MINUS_2
+
+set_compile_flags(example_atomic_four_vector "${cppad_debug_which}" "${source_list}" )
+#
+ADD_EXECUTABLE(example_atomic_four_vector EXCLUDE_FROM_ALL ${source_list})
+#
+# Add the check_example_atomic_four_vector target
+ADD_CUSTOM_TARGET(check_example_atomic_four_vector
+    example_atomic_four_vector
+    DEPENDS example_atomic_four_vector
+)
+MESSAGE(STATUS "make check_example_atomic_four_vector: available")
+#
+# add to check check_example_atomic_four_depends in parent environment
+add_to_list(check_example_atomic_four_depends check_example_atomic_four_vector)
+SET(check_example_atomic_four_depends
+    "${check_example_atomic_four_depends}" PARENT_SCOPE
+)
diff --git a/example/atomic_four/vector/add.cpp b/example/atomic_four/vector/add.cpp
new file mode 100644
index 000000000..a64418083
--- /dev/null
+++ b/example/atomic_four/vector/add.cpp
@@ -0,0 +1,200 @@
+/* --------------------------------------------------------------------------
+CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
+
+CppAD is distributed under the terms of the
+             Eclipse Public License Version 2.0.
+
+This Source Code may also be made available under the following
+Secondary License when the conditions 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_four_vector_add.cpp$$
+
+$section Atomic Vector Addition Example$$
+
+$head f(u, v, w)$$
+For this example,
+$latex f : \B{R}^{3m} \rightarrow \B{R}^m$$
+is defined by $latex f(u, v, w) = u + v + w$$.
+where $icode u$$, $icode v$$, and $icode w$$ are in $latex \B{R}^m$$.
+
+$head g(u, v, w)$$
+For this example $latex g : \B{R}^{3m} \rightarrow \B{R}^m$$
+is defined by $latex g_i (u, v, w) = \partial_{v[i]}  f_i (u, v, w)$$
+
+$head Source$$
+$srcthisfile%0%// BEGIN C++%// END C++%1%$$
+
+$end
+*/
+// BEGIN C++
+# include <cppad/cppad.hpp>
+# include <cppad/example/atomic_four/vector/vector.hpp>
+bool add(void)
+{   bool ok = true;
+    using CppAD::NearEqual;
+    using CppAD::AD;
+    double eps99 = 99.0 * CppAD::numeric_limits<double>::epsilon();
+    //
+    // vec_op
+    // atomic vector_op object
+    CppAD::atomic_vector<double> vec_op("atomic_vector");
+    //
+    // m
+    // size of u, v, and w
+    size_t m = 5;
+    //
+    // add_op
+    typedef CppAD::atomic_vector<double>::op_enum_t op_enum_t;
+    op_enum_t add_op = CppAD::atomic_vector<double>::add_enum;
+    // -----------------------------------------------------------------------
+    // Record f(u, v, w) = u + v + w
+    // -----------------------------------------------------------------------
+    // Independent variable vector
+    CPPAD_TESTVECTOR( CppAD::AD<double> ) auvw(3 * m);
+    for(size_t j = 0; j < 3 * m; ++j)
+        auvw[j] = AD<double>(1 + j);
+    CppAD::Independent(auvw);
+    //
+    // au, av, aw
+    CPPAD_TESTVECTOR( CppAD::AD<double> ) au(m), av(m), aw(m);
+    for(size_t i = 0; i < m; ++i)
+    {   au[i] = auvw[0 * m + i];
+        av[i] = auvw[1 * m + i];
+        aw[i] = auvw[2 * m + i];
+    }
+    //
+    // ax = (au, av)
+    CPPAD_TESTVECTOR( CppAD::AD<double> ) ax(2 * m);
+    for(size_t i = 0; i < m; ++i)
+    {   ax[i]     = au[i];
+        ax[m + i] = av[i];
+    }
+    //
+    // ay = u + v
+    CPPAD_TESTVECTOR( CppAD::AD<double> ) ay(m);
+    vec_op(add_op, ax, ay);
+    //
+    // ax = (ay, aw)
+    for(size_t i = 0; i < m; ++i)
+    {   ax[i]     = ay[i];
+        ax[m + i] = aw[i];
+    }
+    //
+    // az = ay + w
+    CPPAD_TESTVECTOR( CppAD::AD<double> ) az(m);
+    vec_op(add_op, ax, az);
+    //
+    // f
+    CppAD::ADFun<double> f(auvw, az);
+    // -----------------------------------------------------------------------
+    // check forward mode on f
+    // -----------------------------------------------------------------------
+    //
+    // uvw, duvw
+    CPPAD_TESTVECTOR(double) uvw(3 * m), duvw(3 * m);
+    for(size_t j = 0; j < 3 * m; ++j)
+    {   uvw[j]  = double(1 + j);
+        duvw[j] = double(j);
+    }
+    //
+    // z, dz
+    CPPAD_TESTVECTOR(double) z(m), dz(m);
+    z  = f.Forward(0, uvw);
+    dz = f.Forward(1, duvw);
+    //
+    // ok
+    for(size_t i = 0; i < m; ++i)
+    {   double check_z  = uvw[0 * m + i] + uvw[1 * m + i] + uvw[2 * m + i];
+        ok             &= NearEqual( z[i] ,  check_z,  eps99, eps99);
+        double check_dz = double( (0 * m + i)  + (1 * m + i) + (2 * m + i) );
+        ok             &= NearEqual( dz[i] ,  check_dz,  eps99, eps99);
+    }
+    // -----------------------------------------------------------------------
+    // check reverse mode on f
+    // -----------------------------------------------------------------------
+    //
+    // weight
+    CPPAD_TESTVECTOR(double) weight(m);
+    for(size_t i = 0; i < m; ++i)
+        weight[i] = 1.0;
+    //
+    // dweight
+    CPPAD_TESTVECTOR(double) dweight(3 * m);
+    f.Forward(0, uvw);
+    dweight = f.Reverse(1, weight);
+    //
+    // ok
+    for(size_t j = 0; j < 3 * m; ++j)
+    {   double check  = 1.0;
+        ok           &= NearEqual(dweight[j], check, eps99, eps99);
+    }
+    // -----------------------------------------------------------------------
+    // Record g_i (u, v, w) = \partial d/dv[i] f_i (u , v , w)
+    // -----------------------------------------------------------------------
+    //
+    // af
+    CppAD::ADFun< AD<double>, double > af = f.base2ad();
+    //
+    // auvw
+    CppAD::Independent(auvw);
+    //
+    // aduvw
+    CPPAD_TESTVECTOR( AD<double> ) aduvw(3 * m);
+    for(size_t i = 0; i < m; ++i)
+    {   aduvw[0 * m + i]  = 0.0; // du[i]
+        aduvw[1 * m + i]  = 1.0; // dv[i]
+        aduvw[2 * m + i]  = 0.0; // dw[i]
+    }
+    //
+    // az
+    // use the fact that d_v[i] f_k (u, v, w) is zero when i != k
+    af.Forward(0, auvw);
+    az = af.Forward(1, aduvw);
+    CppAD::ADFun<double> g(auvw, az);
+    // -----------------------------------------------------------------------
+    // Record h (u, v, w) = sum f_i^(1) (u , v , w)
+    // -----------------------------------------------------------------------
+    //
+    // auvw
+    CppAD::Independent(auvw);
+    //
+    // aweight
+    CPPAD_TESTVECTOR( AD<double> ) aweight(m);
+    for(size_t i = 0; i < m; ++i)
+        aweight[i] = 1.0;
+    //
+    // az
+    CPPAD_TESTVECTOR( AD<double> ) adweight(3 * m);
+    af.Forward(0, auvw);
+    az = af.Reverse(1, aweight);
+    CppAD::ADFun<double> h(auvw, az);
+    // -----------------------------------------------------------------------
+    // check forward mode on g
+    // -----------------------------------------------------------------------
+    //
+    // z
+    z = g.Forward(0, uvw);
+    //
+    // ok
+    for(size_t i = 0; i < m; ++i)
+    {   double check_z  = 1.0;
+        ok             &= NearEqual( z[i] ,  check_z,  eps99, eps99);
+    }
+    // -----------------------------------------------------------------------
+    // check forward mode on h
+    // -----------------------------------------------------------------------
+    //
+    // z
+    z = h.Forward(0, uvw);
+    //
+    // ok
+    for(size_t j = 0; j < 3 * m; ++j)
+    {   double check_z  = 1.0;
+        ok             &= NearEqual( z[j] ,  check_z,  eps99, eps99);
+    }
+    return ok;
+}
+// END C++
diff --git a/example/atomic_four/vector/div.cpp b/example/atomic_four/vector/div.cpp
new file mode 100644
index 000000000..72a4c4750
--- /dev/null
+++ b/example/atomic_four/vector/div.cpp
@@ -0,0 +1,213 @@
+/* --------------------------------------------------------------------------
+CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
+
+CppAD is distributed under the terms of the
+             Eclipse Public License Version 2.0.
+
+This Source Code may also be made available under the following
+Secondary License when the conditions 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_four_vector_div.cpp$$
+
+$section Atomic Vector Division Example$$
+
+$head f(u, v, w)$$
+For this example,
+$latex f : \B{R}^{2m} \rightarrow \B{R}^m$$
+is defined by $latex f(u, v) = u * u / v$$.
+where $icode u$$ and $icode v$$ are in $latex \B{R}^m$$.
+
+$head g(u, v)$$
+For this example $latex g : \B{R}^{2m} \rightarrow \B{R}^m$$
+is defined by $latex g_i (u, v) = \partial_{v[i]}  f_i (u, v)$$
+
+$head Source$$
+$srcthisfile%0%// BEGIN C++%// END C++%1%$$
+
+$end
+*/
+// BEGIN C++
+# include <cppad/cppad.hpp>
+# include <cppad/example/atomic_four/vector/vector.hpp>
+bool div(void)
+{   bool ok = true;
+    using CppAD::NearEqual;
+    using CppAD::AD;
+    double eps99 = 99.0 * CppAD::numeric_limits<double>::epsilon();
+    //
+    // vec_op
+    // atomic vector_op object
+    CppAD::atomic_vector<double> vec_op("atomic_vector");
+    //
+    // m
+    // size of u and v
+    size_t m = 4;
+    //
+    // mul_op, div_op
+    typedef CppAD::atomic_vector<double>::op_enum_t op_enum_t;
+    op_enum_t mul_op = CppAD::atomic_vector<double>::mul_enum;
+    op_enum_t div_op = CppAD::atomic_vector<double>::div_enum;
+    // -----------------------------------------------------------------------
+    // Record f(u, v) = u * u / v
+    // -----------------------------------------------------------------------
+    // Independent variable vector
+    CPPAD_TESTVECTOR( CppAD::AD<double> ) auv(2 * m);
+    for(size_t j = 0; j < 2 * m; ++j)
+        auv[j] = AD<double>(1 + j);
+    CppAD::Independent(auv);
+    //
+    // au, av, aw
+    CPPAD_TESTVECTOR( CppAD::AD<double> ) au(m), av(m);
+    for(size_t i = 0; i < m; ++i)
+    {   au[i] = auv[0 * m + i];
+        av[i] = auv[1 * m + i];
+    }
+    //
+    // ax = (mul_op, au, au)
+    CPPAD_TESTVECTOR( CppAD::AD<double> ) ax(2 * m);
+    for(size_t i = 0; i < m; ++i)
+    {   ax[i]     = au[i];
+        ax[m + i] = au[i];
+    }
+    //
+    // ay = u * u
+    CPPAD_TESTVECTOR( CppAD::AD<double> ) ay(m);
+    vec_op(mul_op, ax, ay);
+    //
+    // ax = (ay, av)
+    for(size_t i = 0; i < m; ++i)
+    {   ax[i]     = ay[i];
+        ax[m + i] = av[i];
+    }
+    //
+    // az = au / ay
+    CPPAD_TESTVECTOR( CppAD::AD<double> ) az(m);
+    vec_op(div_op, ax, az);
+    //
+    // f
+    CppAD::ADFun<double> f(auv, az);
+    // -----------------------------------------------------------------------
+    // check forward mode on f
+    // -----------------------------------------------------------------------
+    //
+    // uv, duv
+    CPPAD_TESTVECTOR(double) uv(2 * m), duv(2 * m);
+    for(size_t j = 0; j < 2 * m; ++j)
+    {   uv[j]  = double(2 + j);
+        duv[j] = 1.0;
+    }
+    //
+    // z, dz
+    CPPAD_TESTVECTOR(double) z(m), dz(m);
+    z  = f.Forward(0, uv);
+    dz = f.Forward(1, duv);
+    //
+    // ok
+    for(size_t i = 0; i < m; ++i)
+    {   double ui     = uv[0 * m + i];
+        double vi     = uv[1 * m + i];
+        double check  = ui * ui / vi;
+        ok           &= NearEqual( z[i] ,  check,  eps99, eps99);
+        check         = 2.0 * ui / vi - ui * ui / (vi * vi);
+        ok         &= NearEqual( dz[i] ,  check,  eps99, eps99);
+    }
+    // -----------------------------------------------------------------------
+    // check reverse mode on f
+    // -----------------------------------------------------------------------
+    //
+    // weight
+    CPPAD_TESTVECTOR(double) weight(m);
+    for(size_t i = 0; i < m; ++i)
+        weight[i] = 1.0;
+    //
+    // dweight
+    CPPAD_TESTVECTOR(double) dweight(2 * m);
+    f.Forward(0, uv);
+    dweight = f.Reverse(1, weight);
+    //
+    // ok
+    for(size_t i = 0; i < m; ++i)
+    {   double ui      = uv[0 * m + i];
+        double vi      = uv[1 * m + i];
+        double dfi_dui = 2.0 * ui / vi;
+        ok           &= NearEqual(dweight[0 * m + i], dfi_dui, eps99, eps99);
+        double dfi_dvi = - ui * ui / (vi * vi);
+        ok           &= NearEqual(dweight[1 * m + i], dfi_dvi, eps99, eps99);
+    }
+    // -----------------------------------------------------------------------
+    // Record g_i (u, v) = \partial d/dv[i] f_i (u, v)
+    // -----------------------------------------------------------------------
+    //
+    // af
+    CppAD::ADFun< AD<double>, double > af = f.base2ad();
+    //
+    // auv
+    CppAD::Independent(auv);
+    //
+    // aduv
+    CPPAD_TESTVECTOR( AD<double> ) aduv(2 * m);
+    for(size_t i = 0; i < m; ++i)
+    {   aduv[0 * m + i]  = 0.0; // du[i]
+        aduv[1 * m + i]  = 1.0; // dv[i]
+    }
+    //
+    // az
+    // use the fact that d_u[i] f_k (u, v, w) is zero when i != k
+    af.Forward(0, auv);
+    az = af.Forward(1, aduv);
+    CppAD::ADFun<double> g(auv, az);
+    // -----------------------------------------------------------------------
+    // Record h (u, v) = sum f_i^(1) (u , v)
+    // -----------------------------------------------------------------------
+    //
+    // auv
+    CppAD::Independent(auv);
+    //
+    // aweight
+    CPPAD_TESTVECTOR( AD<double> ) aweight(m);
+    for(size_t i = 0; i < m; ++i)
+        aweight[i] = 1.0;
+    //
+    // az
+    CPPAD_TESTVECTOR( AD<double> ) adweight(3 * m);
+    af.Forward(0, auv);
+    az = af.Reverse(1, aweight);
+    CppAD::ADFun<double> h(auv, az);
+    // -----------------------------------------------------------------------
+    // check forward mode on g
+    // -----------------------------------------------------------------------
+    //
+    // z
+    z = g.Forward(0, uv);
+    //
+    // ok
+    for(size_t i = 0; i < m; ++i)
+    {   double ui      = uv[0 * m + i];
+        double vi      = uv[1 * m + i];
+        double check   = - ui * ui / (vi * vi);
+        ok           &= NearEqual( z[i] ,  check,  eps99, eps99);
+    }
+    // -----------------------------------------------------------------------
+    // check forward mode on h
+    // -----------------------------------------------------------------------
+    //
+    // z
+    z = h.Forward(0, uv);
+    //
+    // ok
+    for(size_t i = 0; i < m; ++i)
+    {   double ui  = uv[0 * m + i];
+        double vi  = uv[1 * m + i];
+        //
+        double dfi_dui  = 2.0 * ui / vi;
+        ok             &= NearEqual(z[0 * m + i] ,  dfi_dui,  eps99, eps99);
+        //
+        double dfi_dvi  = - ui * ui / (vi * vi);
+        ok             &= NearEqual(z[1 * m + i] ,  dfi_dvi,  eps99, eps99);
+    }
+    return ok;
+}
+// END C++
diff --git a/example/atomic_four/vector/hes_sparsity.cpp b/example/atomic_four/vector/hes_sparsity.cpp
new file mode 100644
index 000000000..1ada125f2
--- /dev/null
+++ b/example/atomic_four/vector/hes_sparsity.cpp
@@ -0,0 +1,193 @@
+/* --------------------------------------------------------------------------
+CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
+
+CppAD is distributed under the terms of the
+             Eclipse Public License Version 2.0.
+
+This Source Code may also be made available under the following
+Secondary License when the conditions 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_four_vector_hes_sparsity.cpp$$
+
+$section Atomic Vector Sparsity Patterns Example$$
+
+$head f(u, v)$$
+For this example,
+$latex f : \B{R}^{3m} \rightarrow \B{R}^m$$
+is defined by $latex f(u, v, w) = - u * v * w$$.
+where $icode u$$, $icode v$$, and $icode w$$ are in $latex \B{R}^m$$.
+
+$head Source$$
+$srcthisfile%0%// BEGIN C++%// END C++%1%$$
+
+$end
+*/
+// BEGIN C++
+# include <cppad/cppad.hpp>
+# include <cppad/example/atomic_four/vector/vector.hpp>
+bool hes_sparsity(void)
+{   bool ok = true;
+    using CppAD::NearEqual;
+    using CppAD::AD;
+    //
+    // vec_op
+    // atomic vector_op object
+    CppAD::atomic_vector<double> vec_op("atomic_vector");
+    //
+    // m
+    // size of u, v, and w
+    size_t m = 6;
+    //
+    // n
+    size_t n = 3 * m;
+    //
+    // mul_op, neg_op
+    typedef CppAD::atomic_vector<double>::op_enum_t op_enum_t;
+    op_enum_t mul_op = CppAD::atomic_vector<double>::mul_enum;
+    op_enum_t neg_op = CppAD::atomic_vector<double>::neg_enum;
+    // -----------------------------------------------------------------------
+    // Record f(u, v, w) = - u * v * w
+    // -----------------------------------------------------------------------
+    // Independent variable vector
+    CPPAD_TESTVECTOR( CppAD::AD<double> ) auvw(n);
+    for(size_t j = 0; j < n; ++j)
+        auvw[j] = AD<double>(1 + j);
+    CppAD::Independent(auvw);
+    //
+    // au, av, aw
+    CPPAD_TESTVECTOR( CppAD::AD<double> ) au(m), av(m), aw(m);
+    for(size_t i = 0; i < m; ++i)
+    {   au[i] = auvw[0 * m + i];
+        av[i] = auvw[1 * m + i];
+        aw[i] = auvw[2 * m + i];
+    }
+    //
+    // ax = (au, av)
+    CPPAD_TESTVECTOR( CppAD::AD<double> ) ax(2 * m);
+    for(size_t i = 0; i < m; ++i)
+    {   ax[i]     = au[i];
+        ax[m + i] = av[i];
+    }
+    //
+    // ay = u * v
+    CPPAD_TESTVECTOR( CppAD::AD<double> ) ay(m);
+    vec_op(mul_op, ax, ay);
+    //
+    // ax = (ay, aw)
+    for(size_t i = 0; i < m; ++i)
+    {   ax[i]     = ay[i];
+        ax[m + i] = aw[i];
+    }
+    //
+    // az = ay * w
+    CPPAD_TESTVECTOR( CppAD::AD<double> ) az(m);
+    vec_op(mul_op, ax, az);
+    //
+    // ay = - az
+    vec_op(neg_op, az, ay);
+    //
+    // f
+    CppAD::ADFun<double> f(auvw, ay);
+    //
+    // size_vector, sparsity_pattern
+    typedef CPPAD_TESTVECTOR(size_t) size_vector;
+    typedef CppAD::sparse_rc<size_vector> sparsity_pattern;
+    // -----------------------------------------------------------------------
+    // Hessian sparsity
+    // -----------------------------------------------------------------------
+    for(size_t direction = 0; direction < 2; ++direction)
+    {   sparsity_pattern pattern_out;
+        //
+        // select_range
+        CPPAD_TESTVECTOR(bool) select_range(m);
+        for(size_t i = 0; i < m; ++i)
+            select_range[i] = true;
+        //
+        if( direction == 0 )
+        {   // Forward
+            //
+            // select_domain
+            CPPAD_TESTVECTOR(bool) select_domain(n);
+            for(size_t j = 0; j < n; ++j)
+                select_domain[j] = true;
+            //
+            // pattern_out
+            bool internal_bool = false;
+            f.for_hes_sparsity(
+                select_domain, select_range, internal_bool, pattern_out
+            );
+        }
+        else
+        {   // Reverse
+            //
+            // transpose, internal_bool
+            bool transpose     = false;
+            bool dependency    = false;
+            bool internal_bool = false;
+            //
+            // pattern_in
+            sparsity_pattern pattern_in(n, n, n);
+            for(size_t j = 0; j < n; ++j)
+                pattern_in.set(j, j, j);
+            //
+            // f stores forward Jacobian
+            f.for_jac_sparsity(
+                pattern_in, transpose, dependency, internal_bool, pattern_out
+            );
+            //
+            // pattern_out
+            f.rev_hes_sparsity(
+                select_range, transpose, internal_bool, pattern_out
+            );
+        }
+        //
+        // ok
+        ok &= pattern_out.nnz() == 2 * n;
+        ok &= pattern_out.nr()  == n;
+        ok &= pattern_out.nc()  == n;
+        //
+        // row, col, row_major
+        const size_vector& row = pattern_out.row();
+        const size_vector& col = pattern_out.col();
+        size_vector row_major  = pattern_out.row_major();
+        //
+        // ok
+        size_t ell = 0;
+        for(size_t i = 0; i < m; ++i)
+        {   // first non-zero in row i
+            size_t k = row_major[ell++];
+            ok      &= row[k] == i;
+            ok      &= col[k] == m + i;
+            // second non-zero in row i
+            k        = row_major[ell++];
+            ok      &= row[k] == i;
+            ok      &= col[k] == 2 * m + i;
+        }
+        for(size_t i = m; i < 2 * m; ++i)
+        {   // first non-zero in row i
+            size_t k = row_major[ell++];
+            ok      &= row[k] == i;
+            ok      &= col[k] == i - m;
+            // second non-zero in row i
+            k        = row_major[ell++];
+            ok      &= row[k] == i;
+            ok      &= col[k] == i + m;
+        }
+        for(size_t i = 2 * m; i < 3 * m; ++i)
+        {   // first non-zero in row i
+            size_t k = row_major[ell++];
+            ok      &= row[k] == i;
+            ok      &= col[k] == i - 2 * m;
+            // second non-zero in row i
+            k        = row_major[ell++];
+            ok      &= row[k] == i;
+            ok      &= col[k] == i - m;
+        }
+    }
+    //
+    return ok;
+}
+// END C++
diff --git a/example/atomic_four/vector/jac_sparsity.cpp b/example/atomic_four/vector/jac_sparsity.cpp
new file mode 100644
index 000000000..287275b23
--- /dev/null
+++ b/example/atomic_four/vector/jac_sparsity.cpp
@@ -0,0 +1,165 @@
+/* --------------------------------------------------------------------------
+CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
+
+CppAD is distributed under the terms of the
+             Eclipse Public License Version 2.0.
+
+This Source Code may also be made available under the following
+Secondary License when the conditions 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_four_vector_jac_sparsity.cpp$$
+
+$section Atomic Vector Sparsity Patterns Example$$
+
+$head f(u, v)$$
+For this example,
+$latex f : \B{R}^{3m} \rightarrow \B{R}^m$$
+is defined by $latex f(u, v, w) = - u * v * w$$.
+where $icode u$$, $icode v$$, and $icode w$$ are in $latex \B{R}^m$$.
+
+$head Source$$
+$srcthisfile%0%// BEGIN C++%// END C++%1%$$
+
+$end
+*/
+// BEGIN C++
+# include <cppad/cppad.hpp>
+# include <cppad/example/atomic_four/vector/vector.hpp>
+bool jac_sparsity(void)
+{   bool ok = true;
+    using CppAD::NearEqual;
+    using CppAD::AD;
+    //
+    // vec_op
+    // atomic vector_op object
+    CppAD::atomic_vector<double> vec_op("atomic_vector");
+    //
+    // m
+    // size of u, v, and w
+    size_t m = 6;
+    //
+    // n
+    size_t n = 3 * m;
+    //
+    // mul_op, neg_op
+    typedef CppAD::atomic_vector<double>::op_enum_t op_enum_t;
+    op_enum_t mul_op = CppAD::atomic_vector<double>::mul_enum;
+    op_enum_t neg_op = CppAD::atomic_vector<double>::neg_enum;
+    // -----------------------------------------------------------------------
+    // Record f(u, v, w) = - u * v * w
+    // -----------------------------------------------------------------------
+    // Independent variable vector
+    CPPAD_TESTVECTOR( CppAD::AD<double> ) auvw(n);
+    for(size_t j = 0; j < n; ++j)
+        auvw[j] = AD<double>(1 + j);
+    CppAD::Independent(auvw);
+    //
+    // au, av, aw
+    CPPAD_TESTVECTOR( CppAD::AD<double> ) au(m), av(m), aw(m);
+    for(size_t i = 0; i < m; ++i)
+    {   au[i] = auvw[0 * m + i];
+        av[i] = auvw[1 * m + i];
+        aw[i] = auvw[2 * m + i];
+    }
+    //
+    // ax = (au, av)
+    CPPAD_TESTVECTOR( CppAD::AD<double> ) ax(2 * m);
+    for(size_t i = 0; i < m; ++i)
+    {   ax[i]     = au[i];
+        ax[m + i] = av[i];
+    }
+    //
+    // ay = u * v
+    CPPAD_TESTVECTOR( CppAD::AD<double> ) ay(m);
+    vec_op(mul_op, ax, ay);
+    //
+    // ax = (ay, aw)
+    for(size_t i = 0; i < m; ++i)
+    {   ax[i]     = ay[i];
+        ax[m + i] = aw[i];
+    }
+    //
+    // az = ay * w
+    CPPAD_TESTVECTOR( CppAD::AD<double> ) az(m);
+    vec_op(mul_op, ax, az);
+    //
+    // ay = - az
+    vec_op(neg_op, az, ay);
+    //
+    // f
+    CppAD::ADFun<double> f(auvw, ay);
+    //
+    // size_vector, sparsity_pattern
+    typedef CPPAD_TESTVECTOR(size_t) size_vector;
+    typedef CppAD::sparse_rc<size_vector> sparsity_pattern;
+    // -----------------------------------------------------------------------
+    // Jacobian sparsity
+    // -----------------------------------------------------------------------
+    for(size_t direction = 0; direction < 2; ++direction)
+    {   sparsity_pattern pattern_out;
+        bool transpose     = false;
+        bool dependency    = false;
+        bool internal_bool = false;
+        if( direction == 0 )
+        {   // Forward direction
+            //
+            // pattern_in
+            // sparsity pattern for identity matrix
+            sparsity_pattern pattern_in(n, n, n);
+            for(size_t k = 0; k < n; ++k)
+                pattern_in.set(k, k, k);
+            //
+            // pattern_out
+            f.for_jac_sparsity(
+                pattern_in, transpose, dependency, internal_bool, pattern_out
+            );
+        }
+        else
+        {   // Reverse direction
+            //
+            // pattern_in
+            // sparsity pattern for identity matrix
+            sparsity_pattern pattern_in(m, m, m);
+            for(size_t k = 0; k < m; ++k)
+                pattern_in.set(k, k, k);
+            //
+            // pattern_out
+            f.rev_jac_sparsity(
+                pattern_in, transpose, dependency, internal_bool, pattern_out
+            );
+        }
+        //
+        // ok
+        ok &= pattern_out.nnz() == 3 * m;
+        ok &= pattern_out.nr()  == m;
+        ok &= pattern_out.nc()  == n;
+        //
+        // row, col, row_major
+        const size_vector& row = pattern_out.row();
+        const size_vector& col = pattern_out.col();
+        size_vector row_major  = pattern_out.row_major();
+        //
+        // ok
+        size_t ell = 0;
+        for(size_t i = 0; i < m; ++i)
+        {   // first non-zero in row i
+            size_t k = row_major[ell++];
+            ok      &= row[k] == i;
+            ok      &= col[k] == i;
+            // second non-zero in row i
+            k        = row_major[ell++];
+            ok      &= row[k] == i;
+            ok      &= col[k] == m + i;
+            // third non-zero in row i
+            k        = row_major[ell++];
+            ok      &= row[k] == i;
+            ok      &= col[k] == 2 * m + i;
+        }
+    }
+    //
+    return ok;
+}
+// END C++
diff --git a/example/atomic_four/vector/mul.cpp b/example/atomic_four/vector/mul.cpp
new file mode 100644
index 000000000..4e838f9d3
--- /dev/null
+++ b/example/atomic_four/vector/mul.cpp
@@ -0,0 +1,226 @@
+/* --------------------------------------------------------------------------
+CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
+
+CppAD is distributed under the terms of the
+             Eclipse Public License Version 2.0.
+
+This Source Code may also be made available under the following
+Secondary License when the conditions 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_four_vector_mul.cpp$$
+
+$section Atomic Vector Multiplication Example$$
+
+$head f(u, v, w)$$
+For this example,
+$latex f : \B{R}^{3m} \rightarrow \B{R}^m$$
+is defined by $latex f(u, v, w) = u * v * w$$.
+where $icode u$$, $icode v$$, and $icode w$$ are in $latex \B{R}^m$$.
+
+$head g(u, v, w)$$
+For this example $latex g : \B{R}^{3m} \rightarrow \B{R}^m$$
+is defined by $latex g_i (u, v, w) = \partial_{u[i]}  f_i (u, v, w)$$
+
+$head Source$$
+$srcthisfile%0%// BEGIN C++%// END C++%1%$$
+
+$end
+*/
+// BEGIN C++
+# include <cppad/cppad.hpp>
+# include <cppad/example/atomic_four/vector/vector.hpp>
+bool mul(void)
+{   bool ok = true;
+    using CppAD::NearEqual;
+    using CppAD::AD;
+    double eps99 = 99.0 * CppAD::numeric_limits<double>::epsilon();
+    //
+    // vec_op
+    // atomic vector_op object
+    CppAD::atomic_vector<double> vec_op("atomic_vector");
+    //
+    // m
+    // size of u, v, and w
+    size_t m = 5;
+    //
+    // mul_op
+    typedef CppAD::atomic_vector<double>::op_enum_t op_enum_t;
+    op_enum_t mul_op = CppAD::atomic_vector<double>::mul_enum;
+    // -----------------------------------------------------------------------
+    // Record f(u, v, w) = u * v * w
+    // -----------------------------------------------------------------------
+    // Independent variable vector
+    CPPAD_TESTVECTOR( CppAD::AD<double> ) auvw(3 * m);
+    for(size_t j = 0; j < 3 * m; ++j)
+        auvw[j] = AD<double>(1 + j);
+    CppAD::Independent(auvw);
+    //
+    // au, av, aw
+    CPPAD_TESTVECTOR( CppAD::AD<double> ) au(m), av(m), aw(m);
+    for(size_t i = 0; i < m; ++i)
+    {   au[i] = auvw[0 * m + i];
+        av[i] = auvw[1 * m + i];
+        aw[i] = auvw[2 * m + i];
+    }
+    //
+    // ax = (mul_op, au, av)
+    CPPAD_TESTVECTOR( CppAD::AD<double> ) ax(2 * m);
+    for(size_t i = 0; i < m; ++i)
+    {   ax[i]     = au[i];
+        ax[m + i] = av[i];
+    }
+    //
+    // ay = u * v
+    CPPAD_TESTVECTOR( CppAD::AD<double> ) ay(m);
+    vec_op(mul_op, ax, ay);
+    //
+    // ax = (ay, aw)
+    for(size_t i = 0; i < m; ++i)
+    {   ax[i]     = ay[i];
+        ax[m + i] = aw[i];
+    }
+    //
+    // az = ay * aw
+    CPPAD_TESTVECTOR( CppAD::AD<double> ) az(m);
+    vec_op(mul_op, ax, az);
+    //
+    // f
+    CppAD::ADFun<double> f(auvw, az);
+    // -----------------------------------------------------------------------
+    // check forward mode on f
+    // -----------------------------------------------------------------------
+    //
+    // uvw, duvw
+    CPPAD_TESTVECTOR(double) uvw(3 * m), duvw(3 * m);
+    for(size_t j = 0; j < 3 * m; ++j)
+    {   uvw[j]  = double(1 + j);
+        duvw[j] = 1.0;
+    }
+    //
+    // z, dz
+    CPPAD_TESTVECTOR(double) z(m), dz(m);
+    z  = f.Forward(0, uvw);
+    dz = f.Forward(1, duvw);
+    //
+    // ok
+    for(size_t i = 0; i < m; ++i)
+    {   double ui  = uvw[0 * m + i];
+        double vi  = uvw[1 * m + i];
+        double wi  = uvw[2 * m + i];
+        //
+        double check_z  = ui * vi * wi;
+        ok             &= NearEqual( z[i] ,  check_z,  eps99, eps99);
+        //
+        double check_dz = (vi * wi) + (ui * wi) + (ui * vi);
+        ok             &= NearEqual( dz[i] ,  check_dz,  eps99, eps99);
+    }
+    // -----------------------------------------------------------------------
+    // check reverse mode on f
+    // -----------------------------------------------------------------------
+    //
+    // weight
+    CPPAD_TESTVECTOR(double) weight(m);
+    for(size_t i = 0; i < m; ++i)
+        weight[i] = 1.0;
+    //
+    // dweight
+    CPPAD_TESTVECTOR(double) dweight(3 * m);
+    f.Forward(0, uvw);
+    dweight = f.Reverse(1, weight);
+    //
+    // ok
+    for(size_t i = 0; i < m; ++i)
+    {   double ui  = uvw[0 * m + i];
+        double vi  = uvw[1 * m + i];
+        double wi  = uvw[2 * m + i];
+        //
+        double dfi_dui = vi * wi;
+        ok           &= NearEqual(dweight[0 * m + i], dfi_dui, eps99, eps99);
+        double dfi_dvi = ui * wi;
+        ok           &= NearEqual(dweight[1 * m + i], dfi_dvi, eps99, eps99);
+        double dfi_dwi = ui * vi;
+        ok           &= NearEqual(dweight[2 * m + i], dfi_dwi, eps99, eps99);
+    }
+    // -----------------------------------------------------------------------
+    // Record g_i (u, v, w) = \partial d/dv[i] f_i (u , v , w)
+    // -----------------------------------------------------------------------
+    //
+    // af
+    CppAD::ADFun< AD<double>, double > af = f.base2ad();
+    //
+    // auvw
+    CppAD::Independent(auvw);
+    //
+    // aduvw
+    CPPAD_TESTVECTOR( AD<double> ) aduvw(3 * m);
+    for(size_t i = 0; i < m; ++i)
+    {   aduvw[0 * m + i]  = 1.0; // du[i]
+        aduvw[1 * m + i]  = 0.0; // dv[i]
+        aduvw[2 * m + i]  = 0.0; // dw[i]
+    }
+    //
+    // az
+    // use the fact that d_u[i] f_k (u, v, w) is zero when i != k
+    af.Forward(0, auvw);
+    az = af.Forward(1, aduvw);
+    CppAD::ADFun<double> g(auvw, az);
+    // -----------------------------------------------------------------------
+    // Record h (u, v, w) = sum f_i^(1) (u , v , w)
+    // -----------------------------------------------------------------------
+    //
+    // auvw
+    CppAD::Independent(auvw);
+    //
+    // aweight
+    CPPAD_TESTVECTOR( AD<double> ) aweight(m);
+    for(size_t i = 0; i < m; ++i)
+        aweight[i] = 1.0;
+    //
+    // az
+    CPPAD_TESTVECTOR( AD<double> ) adweight(3 * m);
+    af.Forward(0, auvw);
+    az = af.Reverse(1, aweight);
+    CppAD::ADFun<double> h(auvw, az);
+    // -----------------------------------------------------------------------
+    // check forward mode on g
+    // -----------------------------------------------------------------------
+    //
+    // z
+    z = g.Forward(0, uvw);
+    //
+    // ok
+    for(size_t i = 0; i < m; ++i)
+    {   double vi       = uvw[1 * m + i];
+        double wi       = uvw[2 * m + i];
+        double check_z  = vi * wi;
+        ok             &= NearEqual( z[i] ,  check_z,  eps99, eps99);
+    }
+    return ok;
+    // -----------------------------------------------------------------------
+    // check forward mode on h
+    // -----------------------------------------------------------------------
+    //
+    // z
+    z = h.Forward(0, uvw);
+    //
+    // ok
+    for(size_t i = 0; i < m; ++i)
+    {   double ui  = uvw[0 * m + i];
+        double vi  = uvw[1 * m + i];
+        double wi  = uvw[2 * m + i];
+        //
+        double dfi_dui  = vi * wi;
+        ok             &= NearEqual(z[0 * m + i] ,  dfi_dui,  eps99, eps99);
+        //
+        double dfi_dvi  = ui * wi;
+        ok             &= NearEqual(z[1 * m + i] ,  dfi_dvi,  eps99, eps99);
+        //
+        double dfi_dwi  = ui * vi;
+        ok             &= NearEqual(z[2 * m + i] ,  dfi_dwi,  eps99, eps99);
+    }
+    return ok;
+}
+// END C++
diff --git a/example/atomic_four/vector/neg.cpp b/example/atomic_four/vector/neg.cpp
new file mode 100644
index 000000000..7526462ea
--- /dev/null
+++ b/example/atomic_four/vector/neg.cpp
@@ -0,0 +1,150 @@
+/* --------------------------------------------------------------------------
+CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
+
+CppAD is distributed under the terms of the
+             Eclipse Public License Version 2.0.
+
+This Source Code may also be made available under the following
+Secondary License when the conditions 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_four_vector_neg.cpp$$
+
+$section Atomic Vector Negation Example$$
+
+$head f(u, w)$$
+For this example,
+$latex f : \B{R}^{2m} \rightarrow \B{R}^m$$
+is defined by $latex f(u, w) = u - w$$.
+where $icode u$$ and $icode w$$ are in $latex \B{R}^m$$.
+
+$head g(u, w)$$
+For this example $latex g : \B{R}^{2m} \rightarrow \B{R}^m$$
+is defined by $latex g_i (u, w) = \partial_{w[i]}  f_i (u, w)$$
+
+$head Source$$
+$srcthisfile%0%// BEGIN C++%// END C++%1%$$
+
+$end
+*/
+// BEGIN C++
+# include <cppad/cppad.hpp>
+# include <cppad/example/atomic_four/vector/vector.hpp>
+bool neg(void)
+{   bool ok = true;
+    using CppAD::NearEqual;
+    using CppAD::AD;
+    double eps99 = 99.0 * CppAD::numeric_limits<double>::epsilon();
+    //
+    // vec_op
+    // atomic vector_op object
+    CppAD::atomic_vector<double> vec_op("atomic_vector");
+    //
+    // m
+    // size of u, v
+    size_t m = 5;
+    //
+    // add_op, neg_op
+    typedef CppAD::atomic_vector<double>::op_enum_t op_enum_t;
+    op_enum_t add_op = CppAD::atomic_vector<double>::add_enum;
+    op_enum_t neg_op = CppAD::atomic_vector<double>::neg_enum;
+    // -----------------------------------------------------------------------
+    // Record f(u, v) = u - v
+    // -----------------------------------------------------------------------
+    // Independent variable vector
+    CPPAD_TESTVECTOR( CppAD::AD<double> ) auv(2 * m);
+    for(size_t j = 0; j < 2 * m; ++j)
+        auv[j] = AD<double>(1 + j);
+    CppAD::Independent(auv);
+    //
+    // au, av
+    CPPAD_TESTVECTOR( CppAD::AD<double> ) au(m), av(m);
+    for(size_t i = 0; i < m; ++i)
+    {   au[i] = auv[0 * m + i];
+        av[i] = auv[1 * m + i];
+    }
+    //
+    // ax = av
+    CPPAD_TESTVECTOR( CppAD::AD<double> ) ax(m);
+    for(size_t i = 0; i < m; ++i)
+        ax[i] = av[i];
+    //
+    // ay = - av
+    CPPAD_TESTVECTOR( CppAD::AD<double> ) ay(m);
+    vec_op(neg_op, ax, ay);
+    //
+    // ax = (au, ay)
+    ax.resize(2 * m);
+    for(size_t i = 0; i < m; ++i)
+    {   ax[i]     = au[i];
+        ax[m + i] = ay[i];
+    }
+    //
+    // az = au + ay
+    CPPAD_TESTVECTOR( CppAD::AD<double> ) az(m);
+    vec_op(add_op, ax, az);
+    //
+    // f
+    CppAD::ADFun<double> f(auv, az);
+    // -----------------------------------------------------------------------
+    // check forward mode on f
+    // -----------------------------------------------------------------------
+    //
+    // uv, duv
+    CPPAD_TESTVECTOR(double) uv(2 * m), duv(2 * m);
+    for(size_t j = 0; j < 2 * m; ++j)
+    {   uv[j]  = double(1 + j);
+        duv[j] = double(j);
+    }
+    //
+    // z, dz
+    CPPAD_TESTVECTOR(double) z(m), dz(m);
+    z  = f.Forward(0, uv);
+    dz = f.Forward(1, duv);
+    //
+    // ok
+    for(size_t i = 0; i < m; ++i)
+    {   double check_z  = uv[0 * m + i] - uv[1 * m + i];
+        ok             &= NearEqual( z[i] ,  check_z,  eps99, eps99);
+        double check_dz = double(0 * m + i) - double(1 * m + i);
+        ok             &= NearEqual( dz[i] ,  check_dz,  eps99, eps99);
+    }
+    // -----------------------------------------------------------------------
+    // Record g_i (u, v) = \partial d/dv[i] f_i (u , v)
+    // -----------------------------------------------------------------------
+    //
+    // af
+    CppAD::ADFun< AD<double>, double > af = f.base2ad();
+    //
+    // auv
+    CppAD::Independent(auv);
+    //
+    // aduv
+    CPPAD_TESTVECTOR( AD<double> ) aduv(2 * m);
+    for(size_t i = 0; i < m; ++i)
+    {   aduv[0 * m + i]  = 0.0; // du[i]
+        aduv[1 * m + i]  = 1.0; // dv[i]
+    }
+    //
+    // az
+    // use the fact that d_v[i] f_k (u, v) is zero when i != k
+    af.Forward(0, auv);
+    az = af.Forward(1, aduv);
+    CppAD::ADFun<double> g(auv, az);
+    // -----------------------------------------------------------------------
+    // check forward mode on g
+    // -----------------------------------------------------------------------
+    //
+    // z
+    z = g.Forward(0, uv);
+    //
+    // ok
+    for(size_t i = 0; i < m; ++i)
+    {   double check_z  = - 1.0;
+        ok             &= NearEqual( z[i] ,  check_z,  eps99, eps99);
+    }
+    return ok;
+}
+// END C++
diff --git a/example/atomic_four/vector/rev_depend.cpp b/example/atomic_four/vector/rev_depend.cpp
new file mode 100644
index 000000000..3139cc193
--- /dev/null
+++ b/example/atomic_four/vector/rev_depend.cpp
@@ -0,0 +1,113 @@
+/* --------------------------------------------------------------------------
+CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
+
+CppAD is distributed under the terms of the
+             Eclipse Public License Version 2.0.
+
+This Source Code may also be made available under the following
+Secondary License when the conditions 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_four_vector_rev_depend.cpp$$
+
+$section Example Optimizing Atomic Vector Usage$$
+
+$head f(u, v)$$
+For this example,
+$latex f : \B{R}^{3m} \rightarrow \B{R}$$
+is defined by $latex f(u, v, w) = - ( u_0 + v_0 ) * w_0$$.
+where $icode u$$, $icode v$$, and $icode w$$ are in $latex \B{R}^m$$.
+
+$head Source$$
+$srcthisfile%0%// BEGIN C++%// END C++%1%$$
+
+$end
+*/
+// BEGIN C++
+# include <cppad/cppad.hpp>
+# include <cppad/example/atomic_four/vector/vector.hpp>
+bool rev_depend(void)
+{   bool ok = true;
+    using CppAD::NearEqual;
+    using CppAD::AD;
+    //
+    // vec_op
+    // atomic vector_op object
+    CppAD::atomic_vector<double> vec_op("atomic_vector");
+    //
+    // m
+    // size of u, v, and w
+    size_t m = 6;
+    //
+    // n
+    size_t n = 3 * m;
+    //
+    // add_op, mul_op, neg_op
+    typedef CppAD::atomic_vector<double>::op_enum_t op_enum_t;
+    op_enum_t add_op = CppAD::atomic_vector<double>::add_enum;
+    op_enum_t mul_op = CppAD::atomic_vector<double>::mul_enum;
+    op_enum_t neg_op = CppAD::atomic_vector<double>::neg_enum;
+    // -----------------------------------------------------------------------
+    // Record f(u, v, w) = - (u + v) * w
+    // -----------------------------------------------------------------------
+    // Independent variable vector
+    CPPAD_TESTVECTOR( CppAD::AD<double> ) a_ind(n);
+    for(size_t j = 0; j < n; ++j)
+        a_ind[j] = AD<double>(1 + j);
+    CppAD::Independent(a_ind);
+    //
+    // au, av, aw
+    CPPAD_TESTVECTOR( CppAD::AD<double> ) au(m), av(m), aw(m);
+    for(size_t i = 0; i < m; ++i)
+    {   au[i] = a_ind[0 * m + i];
+        av[i] = a_ind[1 * m + i];
+        aw[i] = a_ind[2 * m + i];
+    }
+    //
+    // ax = (au, av)
+    CPPAD_TESTVECTOR( CppAD::AD<double> ) ax(2 * m);
+    for(size_t i = 0; i < m; ++i)
+    {   ax[i]     = au[i];
+        ax[m + i] = av[i];
+    }
+    //
+    // ay = u + v
+    CPPAD_TESTVECTOR( CppAD::AD<double> ) ay(m);
+    vec_op(add_op, ax, ay);
+    //
+    // ax = (ay, aw)
+    for(size_t i = 0; i < m; ++i)
+    {   ax[i]     = ay[i];
+        ax[m + i] = aw[i];
+    }
+    //
+    // az = ay * w
+    CPPAD_TESTVECTOR( CppAD::AD<double> ) az(m);
+    vec_op(mul_op, ax, az);
+    //
+    // ay = - az
+    vec_op(neg_op, az, ay);
+    //
+    // f
+    CPPAD_TESTVECTOR( CppAD::AD<double> ) a_dep(1);
+    a_dep[0] = ay[0];
+    CppAD::ADFun<double> f(a_ind, a_dep);
+    //
+    // size_var
+    // phantom variable, independent variables, operator results
+    ok   &= f.size_var() == 1 + n + 3 * m;
+    //
+    // optimize
+    // The atomic funciton rev_depend routine is called by optimizer
+    f.optimize();
+    //
+    // size_var
+    // phantom variablem, independent variables, operator variables
+    ok &= f.size_var() == 1 + n + 3;
+    //
+    //
+    return ok;
+}
+// END C++
diff --git a/example/atomic_four/vector/sub.cpp b/example/atomic_four/vector/sub.cpp
new file mode 100644
index 000000000..cfd0d489c
--- /dev/null
+++ b/example/atomic_four/vector/sub.cpp
@@ -0,0 +1,186 @@
+/* --------------------------------------------------------------------------
+CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
+
+CppAD is distributed under the terms of the
+             Eclipse Public License Version 2.0.
+
+This Source Code may also be made available under the following
+Secondary License when the conditions 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_four_vector_sub.cpp$$
+
+$section Atomic Vector Subtraction Example$$
+
+$head f(u, v, w)$$
+For this example,
+$latex f : \B{R}^{3m} \rightarrow \B{R}^m$$
+is defined by $latex f(u, v, w) = u - (v + w)$$.
+where $icode u$$, $icode v$$, and $icode w$$ are in $latex \B{R}^m$$.
+
+$head g(u, v, w)$$
+For this example $latex g : \B{R}^{3m} \rightarrow \B{R}^m$$
+is defined by $latex g_i (u, v, w) = \partial_{v[i]}  f_i (u, v, w)$$
+
+$head Source$$
+$srcthisfile%0%// BEGIN C++%// END C++%1%$$
+
+$end
+*/
+// BEGIN C++
+# include <cppad/cppad.hpp>
+# include <cppad/example/atomic_four/vector/vector.hpp>
+bool sub(void)
+{   bool ok = true;
+    using CppAD::NearEqual;
+    using CppAD::AD;
+    double eps99 = 99.0 * CppAD::numeric_limits<double>::epsilon();
+    //
+    // vec_op
+    // atomic vector_op object
+    CppAD::atomic_vector<double> vec_op("atomic_vector");
+    //
+    // m
+    // size of u, v, and w
+    size_t m = 5;
+    //
+    // add_op, sub_op
+    typedef CppAD::atomic_vector<double>::op_enum_t op_enum_t;
+    op_enum_t add_op = CppAD::atomic_vector<double>::add_enum;
+    op_enum_t sub_op = CppAD::atomic_vector<double>::sub_enum;
+    // -----------------------------------------------------------------------
+    // Record f(u, v, w) = u - (v + w)
+    // -----------------------------------------------------------------------
+    // Independent variable vector
+    CPPAD_TESTVECTOR( CppAD::AD<double> ) auvw(3 * m);
+    for(size_t j = 0; j < 3 * m; ++j)
+        auvw[j] = AD<double>(1 + j);
+    CppAD::Independent(auvw);
+    //
+    // au, av, aw
+    CPPAD_TESTVECTOR( CppAD::AD<double> ) au(m), av(m), aw(m);
+    for(size_t i = 0; i < m; ++i)
+    {   au[i] = auvw[0 * m + i];
+        av[i] = auvw[1 * m + i];
+        aw[i] = auvw[2 * m + i];
+    }
+    //
+    // ax = (av, aw)
+    CPPAD_TESTVECTOR( CppAD::AD<double> ) ax(2 * m);
+    for(size_t i = 0; i < m; ++i)
+    {   ax[i]     = av[i];
+        ax[m + i] = aw[i];
+    }
+    //
+    // ay = v + w
+    CPPAD_TESTVECTOR( CppAD::AD<double> ) ay(m);
+    vec_op(add_op, ax, ay);
+    //
+    // ax = (sub_op, au, ay)
+    for(size_t i = 0; i < m; ++i)
+    {   ax[i]     = au[i];
+        ax[m + i] = ay[i];
+    }
+    //
+    // az = au - ay
+    CPPAD_TESTVECTOR( CppAD::AD<double> ) az(m);
+    vec_op(sub_op, ax, az);
+    //
+    // f
+    CppAD::ADFun<double> f(auvw, az);
+    // -----------------------------------------------------------------------
+    // check forward mode on f
+    // -----------------------------------------------------------------------
+    //
+    // uvw, duvw
+    CPPAD_TESTVECTOR(double) uvw(3 * m), duvw(3 * m);
+    for(size_t j = 0; j < 3 * m; ++j)
+    {   uvw[j]  = double(1 + j);
+        duvw[j] = double(j);
+    }
+    //
+    // z, dz
+    CPPAD_TESTVECTOR(double) z(m), dz(m);
+    z  = f.Forward(0, uvw);
+    dz = f.Forward(1, duvw);
+    //
+    // ok
+    for(size_t i = 0; i < m; ++i)
+    {   double check_z  = uvw[0 * m + i] - ( uvw[1 * m + i] + uvw[2 * m + i] );
+        ok             &= NearEqual( z[i] ,  check_z,  eps99, eps99);
+        double check_dz = double(0 * m + i) - double(1 * m + i + 2 * m + i);
+        ok             &= NearEqual( dz[i] ,  check_dz,  eps99, eps99);
+    }
+    // -----------------------------------------------------------------------
+    // Record g_i (u, v, w) = \partial d/dv[i] f_i (u , v , w)
+    // -----------------------------------------------------------------------
+    //
+    // af
+    CppAD::ADFun< AD<double>, double > af = f.base2ad();
+    //
+    // auvw
+    CppAD::Independent(auvw);
+    //
+    // aduvw
+    CPPAD_TESTVECTOR( AD<double> ) aduvw(3 * m);
+    for(size_t i = 0; i < m; ++i)
+    {   aduvw[0 * m + i]  = 0.0; // du[i]
+        aduvw[1 * m + i]  = 1.0; // dv[i]
+        aduvw[2 * m + i]  = 0.0; // dw[i]
+    }
+    //
+    // az
+    // use the fact that d_v[i] f_k (u, v, w) is zero when i != k
+    af.Forward(0, auvw);
+    az = af.Forward(1, aduvw);
+    CppAD::ADFun<double> g(auvw, az);
+    // -----------------------------------------------------------------------
+    // Record h (u, v, w) = sum f_i^(1) (u , v , w)
+    // -----------------------------------------------------------------------
+    //
+    // auvw
+    CppAD::Independent(auvw);
+    //
+    // aweight
+    CPPAD_TESTVECTOR( AD<double> ) aweight(m);
+    for(size_t i = 0; i < m; ++i)
+        aweight[i] = 1.0;
+    //
+    // az
+    CPPAD_TESTVECTOR( AD<double> ) adweight(3 * m);
+    af.Forward(0, auvw);
+    az = af.Reverse(1, aweight);
+    CppAD::ADFun<double> h(auvw, az);
+    // -----------------------------------------------------------------------
+    // check forward mode on g
+    // -----------------------------------------------------------------------
+    //
+    // z
+    z = g.Forward(0, uvw);
+    //
+    // ok
+    for(size_t i = 0; i < m; ++i)
+    {   double check_z  = - 1.0;
+        ok             &= NearEqual( z[i] ,  check_z,  eps99, eps99);
+    }
+    return ok;
+    // -----------------------------------------------------------------------
+    // check forward mode on h
+    // -----------------------------------------------------------------------
+    //
+    // z
+    z = h.Forward(0, uvw);
+    //
+    // ok
+    for(size_t i = 0; i < m; ++i)
+    {   double check_z  =  1.0;
+        ok             &= NearEqual( z[0 * m + i] ,  check_z,  eps99, eps99);
+        check_z         =  - 1.0;
+        ok             &= NearEqual( z[1 * m + i] ,  check_z,  eps99, eps99);
+        ok             &= NearEqual( z[2 * m + i] ,  check_z,  eps99, eps99);
+    }
+    return ok;
+}
+// END C++
diff --git a/example/atomic_four/vector/vector.cpp b/example/atomic_four/vector/vector.cpp
new file mode 100644
index 000000000..bdafce08c
--- /dev/null
+++ b/example/atomic_four/vector/vector.cpp
@@ -0,0 +1,64 @@
+/* --------------------------------------------------------------------------
+CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
+
+CppAD is distributed under the terms of the
+             Eclipse Public License Version 2.0.
+
+This Source Code may also be made available under the following
+Secondary License when the conditions 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_HAS_* defines
+# include <cppad/configure.hpp>
+
+// system include files used for I/O
+# include <iostream>
+
+// C style asserts
+# include <cassert>
+
+// for thread_alloc
+# include <cppad/utility/thread_alloc.hpp>
+
+// test runner
+# include <cppad/utility/test_boolofvoid.hpp>
+
+// BEGIN_SORT_THIS_LINE_PLUS_1
+extern bool add(void);
+extern bool div(void);
+extern bool hes_sparsity(void);
+extern bool jac_sparsity(void);
+extern bool mul(void);
+extern bool neg(void);
+extern bool rev_depend(void);
+extern bool sub(void);
+// END_SORT_THIS_LINE_MINUS_1
+
+// main program that runs all the tests
+int main(void)
+{   std::string group = "example/atomic_four/vector";
+    size_t      width = 20;
+    CppAD::test_boolofvoid Run(group, width);
+
+    // This line is used by test_one.sh
+
+    // BEGIN_SORT_THIS_LINE_PLUS_1
+    Run( add,                 "add"            );
+    Run( div,                 "div"            );
+    Run( hes_sparsity,        "hes_sparsity"   );
+    Run( jac_sparsity,        "jac_sparsity"   );
+    Run( mul,                 "mul"            );
+    Run( neg,                 "neg"            );
+    Run( rev_depend,          "rev_depend"     );
+    Run( sub,                 "sub"            );
+    // END_SORT_THIS_LINE_MINUS_1
+
+    // check for memory leak
+    bool memory_ok = CppAD::thread_alloc::free_all();
+    // print summary at end
+    bool ok = Run.summary(memory_ok);
+    //
+    return static_cast<int>( ! ok );
+}
diff --git a/example/atomic_three/CMakeLists.txt b/example/atomic_three/CMakeLists.txt
index f96251281..ce6e31d79 100644
--- a/example/atomic_three/CMakeLists.txt
+++ b/example/atomic_three/CMakeLists.txt
@@ -1,5 +1,5 @@
 # -----------------------------------------------------------------------------
-# CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 Bradley M. Bell
+# CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
 #
 # CppAD is distributed under the terms of the
 #              Eclipse Public License Version 2.0.
diff --git a/example/atomic_three/atomic_three.cpp b/example/atomic_three/atomic_three.cpp
index 3d13fd38c..08419255b 100644
--- a/example/atomic_three/atomic_three.cpp
+++ b/example/atomic_three/atomic_three.cpp
@@ -1,5 +1,5 @@
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-18 Bradley M. Bell
+CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
 
 CppAD is distributed under the terms of the
              Eclipse Public License Version 2.0.
@@ -25,19 +25,20 @@ in the Eclipse Public License, Version 2.0 are satisfied:
 // test runner
 # include <cppad/utility/test_boolofvoid.hpp>
 
-// external compiled tests
-extern bool mat_mul(void);
-extern bool norm_sq(void);
-extern bool tangent(void);
+// BEGIN_SORT_THIS_LINE_PLUS_1
 extern bool base2ad(void);
-extern bool reciprocal(void);
 extern bool dynamic(void);
 extern bool forward(void);
 extern bool get_started(void);
 extern bool hes_sparsity(void);
 extern bool jac_sparsity(void);
-extern bool reverse(void);
+extern bool mat_mul(void);
+extern bool norm_sq(void);
+extern bool reciprocal(void);
 extern bool rev_depend(void);
+extern bool reverse(void);
+extern bool tangent(void);
+// END_SORT_THIS_LINE_MINUS_1
 
 // main program that runs all the tests
 int main(void)
@@ -47,19 +48,20 @@ int main(void)
 
     // This line is used by test_one.sh
 
-    // external compiled tests
-    Run( mat_mul,             "mat_mul"        );
-    Run( norm_sq, "norm_sq" );
-    Run( tangent, "tangent" );
-    Run( base2ad, "base2ad" );
-    Run( reciprocal, "reciprocal" );
+    // BEGIN_SORT_THIS_LINE_PLUS_1
+    Run( base2ad,             "base2ad"        );
     Run( dynamic,             "dynamic"        );
     Run( forward,             "forward"        );
     Run( get_started,         "get_started"    );
     Run( hes_sparsity,        "hes_sparsity"   );
     Run( jac_sparsity,        "jac_sparsity"   );
+    Run( mat_mul,             "mat_mul"        );
+    Run( norm_sq,             "norm_sq"        );
+    Run( reciprocal,          "reciprocal"     );
+    Run( rev_depend,          "rev_depend"     );
     Run( reverse,             "reverse"        );
-    Run( rev_depend,            "rev_depend"       );
+    Run( tangent,             "tangent"        );
+    // END_SORT_THIS_LINE_MINUS_1
 
     // check for memory leak
     bool memory_ok = CppAD::thread_alloc::free_all();
diff --git a/example/atomic_three/atomic_three.omh b/example/atomic_three/atomic_three.omh
new file mode 100644
index 000000000..4b4b55fa8
--- /dev/null
+++ b/example/atomic_three/atomic_three.omh
@@ -0,0 +1,24 @@
+/* --------------------------------------------------------------------------
+CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
+
+  CppAD is distributed under the terms of the
+               Eclipse Public License Version 2.0.
+
+  This Source Code may also be made available under the following
+  Secondary License when the conditions 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_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
diff --git a/example/atomic_three/base2ad.cpp b/example/atomic_three/base2ad.cpp
index a498683dc..7f64d63e7 100644
--- a/example/atomic_three/base2ad.cpp
+++ b/example/atomic_three/base2ad.cpp
@@ -1,5 +1,5 @@
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
+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.
@@ -37,10 +37,10 @@ public:
 private:
     // ------------------------------------------------------------------------
     // type
-    virtual bool for_type(
+    bool for_type(
         const vector<double>&               parameter_x ,
         const vector<CppAD::ad_type_enum>&  type_x      ,
-        vector<CppAD::ad_type_enum>&        type_y      )
+        vector<CppAD::ad_type_enum>&        type_y      ) override
     {   assert( parameter_x.size() == type_x.size() );
         bool ok = type_x.size() == 1; // n
         ok     &= type_y.size() == 1; // m
@@ -80,25 +80,25 @@ private:
         return ok;
     }
     // forward mode routines called by ADFun<Base> objects
-    virtual bool forward(
+    bool forward(
         const vector<double>&              parameter_x ,
         const vector<CppAD::ad_type_enum>& type_x      ,
         size_t                             need_y      ,
         size_t                             p           ,
         size_t                             q           ,
         const vector<double>&              tx          ,
-        vector<double>&                    ty          )
+        vector<double>&                    ty          ) override
     {   return template_forward(p, q, tx, ty);
     }
     // forward mode routines called by ADFun< AD<Base> , Base> objects
-    virtual bool forward(
+    bool forward(
         const vector< AD<double> >&        aparameter_x ,
         const vector<CppAD::ad_type_enum>& type_x      ,
         size_t                             need_y      ,
         size_t                             p           ,
         size_t                             q           ,
         const vector< AD<double> >&        atx         ,
-        vector< AD<double> >&              aty         )
+        vector< AD<double> >&              aty         ) override
     {   return template_forward(p, q, atx, aty);
     }
     // ----------------------------------------------------------------------
@@ -131,25 +131,25 @@ private:
         return ok;
     }
     // reverse mode routines called by ADFun<Base> objects
-    virtual bool reverse(
+    bool reverse(
         const vector<double>&              parameter_x ,
         const vector<CppAD::ad_type_enum>& type_x      ,
         size_t                             q           ,
         const vector<double>&              tx          ,
         const vector<double>&              ty          ,
         vector<double>&                    px          ,
-        const vector<double>&              py          )
+        const vector<double>&              py          ) override
     {   return template_reverse(q, tx, ty, px, py);
     }
     // reverse mode routines called by ADFun<Base> objects
-    virtual bool reverse(
+    bool reverse(
         const vector< AD<double> >&        aparameter_x ,
         const vector<CppAD::ad_type_enum>& type_x       ,
         size_t                             q            ,
         const vector< AD<double> >&        atx          ,
         const vector< AD<double> >&        aty          ,
         vector< AD<double> >&              apx          ,
-        const vector< AD<double> >&        apy          )
+        const vector< AD<double> >&        apy          ) override
     {   return template_reverse(q, atx, aty, apx, apy);
     }
 }; // End of atomic_base2ad class
diff --git a/example/atomic_three/dynamic.cpp b/example/atomic_three/dynamic.cpp
index ba729ff92..e9b4508a9 100644
--- a/example/atomic_three/dynamic.cpp
+++ b/example/atomic_three/dynamic.cpp
@@ -1,5 +1,5 @@
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 Bradley M. Bell
+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.
@@ -49,10 +49,10 @@ private:
 $head for_type$$
 $srccode%cpp% */
     // calculate type_y
-    virtual bool for_type(
+    bool for_type(
         const vector<double>&               parameter_x ,
         const vector<CppAD::ad_type_enum>&  type_x      ,
-        vector<CppAD::ad_type_enum>&        type_y      )
+        vector<CppAD::ad_type_enum>&        type_y      ) override
     {   assert( parameter_x.size() == type_x.size() );
         bool ok = type_x.size() == 3; // n
         ok     &= type_y.size() == 3; // m
@@ -67,14 +67,14 @@ $srccode%cpp% */
 $head forward$$
 $srccode%cpp% */
     // forward mode routine called by CppAD
-    virtual bool forward(
+    bool forward(
         const vector<double>&               parameter_x  ,
         const vector<CppAD::ad_type_enum>&  type_x       ,
         size_t                              need_y       ,
         size_t                              order_low    ,
         size_t                              order_up     ,
         const vector<double>&               taylor_x     ,
-        vector<double>&                     taylor_y     )
+        vector<double>&                     taylor_y     ) override
     {
 # ifndef NDEBUG
         size_t n = taylor_x.size() / (order_up + 1);
diff --git a/example/atomic_three/forward.cpp b/example/atomic_three/forward.cpp
index 4f0ddbe70..293694a2b 100644
--- a/example/atomic_three/forward.cpp
+++ b/example/atomic_three/forward.cpp
@@ -1,5 +1,5 @@
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-18 Bradley M. Bell
+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.
@@ -77,10 +77,10 @@ private:
 $head for_type$$
 $srccode%cpp% */
     // calculate type_y
-    virtual bool for_type(
+    bool for_type(
         const vector<double>&               parameter_x ,
         const vector<CppAD::ad_type_enum>&  type_x      ,
-        vector<CppAD::ad_type_enum>&        type_y      )
+        vector<CppAD::ad_type_enum>&        type_y      ) override
     {   assert( parameter_x.size() == type_x.size() );
         bool ok = type_x.size() == 3; // n
         ok     &= type_y.size() == 2; // m
@@ -94,14 +94,14 @@ $srccode%cpp% */
 $head forward$$
 $srccode%cpp% */
     // forward mode routine called by CppAD
-    virtual bool forward(
+    bool forward(
         const vector<double>&              parameter_x  ,
         const vector<CppAD::ad_type_enum>& type_x       ,
         size_t                             need_y       ,
         size_t                             order_low    ,
         size_t                             order_up     ,
         const vector<double>&              taylor_x     ,
-        vector<double>&                    taylor_y     )
+        vector<double>&                    taylor_y     ) override
     {
         size_t q1 = order_up + 1;
 # ifndef NDEBUG
diff --git a/example/atomic_three/get_started.cpp b/example/atomic_three/get_started.cpp
index 97642f99b..255c93032 100644
--- a/example/atomic_three/get_started.cpp
+++ b/example/atomic_three/get_started.cpp
@@ -1,5 +1,5 @@
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-18 Bradley M. Bell
+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.
@@ -42,10 +42,10 @@ private:
 $head for_type$$
 $srccode%cpp% */
     // calculate type_y
-    virtual bool for_type(
+    bool for_type(
         const vector<double>&               parameter_x ,
         const vector<CppAD::ad_type_enum>&  type_x      ,
-        vector<CppAD::ad_type_enum>&        type_y      )
+        vector<CppAD::ad_type_enum>&        type_y      ) override
     {   assert( parameter_x.size() == type_x.size() );
         bool ok = type_x.size() == 1; // n
         ok     &= type_y.size() == 1; // m
@@ -58,14 +58,14 @@ $srccode%cpp% */
 $head forward$$
 $srccode%cpp% */
     // forward mode routine called by CppAD
-    virtual bool forward(
+    bool forward(
         const vector<double>&               parameter_x  ,
         const vector<CppAD::ad_type_enum>&  type_x       ,
         size_t                              need_y       ,
         size_t                              order_low    ,
         size_t                              order_up     ,
         const vector<double>&               taylor_x     ,
-        vector<double>&                     taylor_y     )
+        vector<double>&                     taylor_y     ) override
     {
 # ifndef NDEBUG
         size_t n = taylor_x.size() / (order_up + 1);
diff --git a/example/atomic_three/hes_sparsity.cpp b/example/atomic_three/hes_sparsity.cpp
index a81ff63ff..4c5d37e58 100644
--- a/example/atomic_three/hes_sparsity.cpp
+++ b/example/atomic_three/hes_sparsity.cpp
@@ -1,5 +1,5 @@
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-18 Bradley M. Bell
+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.
@@ -77,10 +77,10 @@ private:
 $head for_type$$
 $srccode%cpp% */
     // calculate type_y
-    virtual bool for_type(
+    bool for_type(
         const vector<double>&               parameter_x ,
         const vector<CppAD::ad_type_enum>&  type_x      ,
-        vector<CppAD::ad_type_enum>&        type_y      )
+        vector<CppAD::ad_type_enum>&        type_y      ) override
     {   assert( parameter_x.size() == type_x.size() );
         bool ok = type_x.size() == 3; // n
         ok     &= type_y.size() == 2; // m
@@ -95,14 +95,14 @@ $srccode%cpp% */
 $head forward$$
 $srccode%cpp% */
     // forward mode routine called by CppAD
-    virtual bool forward(
+    bool forward(
         const vector<double>&              parameter_x  ,
         const vector<CppAD::ad_type_enum>& type_x       ,
         size_t                             need_y       ,
         size_t                             order_low    ,
         size_t                             order_up     ,
         const vector<double>&              taylor_x     ,
-        vector<double>&                    taylor_y     )
+        vector<double>&                    taylor_y     ) override
     {
 # ifndef NDEBUG
         size_t n = taylor_x.size() / (order_up + 1);
@@ -127,13 +127,13 @@ $srccode%cpp% */
 $head jac_sparsity$$
 $srccode%cpp% */
     // Jacobian sparsity routine called by CppAD
-    virtual bool jac_sparsity(
+    bool jac_sparsity(
         const vector<double>&               parameter_x ,
         const vector<CppAD::ad_type_enum>&  type_x      ,
         bool                                dependency  ,
         const vector<bool>&                 select_x    ,
         const vector<bool>&                 select_y    ,
-        CppAD::sparse_rc< vector<size_t> >& pattern_out )
+        CppAD::sparse_rc< vector<size_t> >& pattern_out ) override
     {
         size_t n = select_x.size();
         size_t m = select_y.size();
@@ -183,12 +183,12 @@ $srccode%cpp% */
 $head hes_sparsity$$
 $srccode%cpp% */
     // Hessian sparsity routine called by CppAD
-    virtual bool hes_sparsity(
+    bool hes_sparsity(
         const vector<double>&               parameter_x ,
         const vector<CppAD::ad_type_enum>&  type_x      ,
         const vector<bool>&                 select_x    ,
         const vector<bool>&                 select_y    ,
-        CppAD::sparse_rc< vector<size_t> >& pattern_out )
+        CppAD::sparse_rc< vector<size_t> >& pattern_out ) override
     {   assert( parameter_x.size() == select_x.size() );
         assert( select_y.size() == 2 );
         size_t n = select_x.size();
diff --git a/example/atomic_three/jac_sparsity.cpp b/example/atomic_three/jac_sparsity.cpp
index 8588b6955..c748343af 100644
--- a/example/atomic_three/jac_sparsity.cpp
+++ b/example/atomic_three/jac_sparsity.cpp
@@ -1,5 +1,5 @@
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-18 Bradley M. Bell
+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.
@@ -61,10 +61,10 @@ private:
 $head for_type$$
 $srccode%cpp% */
     // calculate type_y
-    virtual bool for_type(
+    bool for_type(
         const vector<double>&               parameter_x ,
         const vector<CppAD::ad_type_enum>&  type_x      ,
-        vector<CppAD::ad_type_enum>&        type_y      )
+        vector<CppAD::ad_type_enum>&        type_y      ) override
     {   assert( parameter_x.size() == type_x.size() );
         bool ok = type_x.size() == 3; // n
         ok     &= type_y.size() == 2; // m
@@ -79,14 +79,14 @@ $srccode%cpp% */
 $head forward$$
 $srccode%cpp% */
     // forward mode routine called by CppAD
-    virtual bool forward(
+    bool forward(
         const vector<double>&              parameter_x  ,
         const vector<CppAD::ad_type_enum>& type_x       ,
         size_t                             need_y       ,
         size_t                             order_low    ,
         size_t                             order_up     ,
         const vector<double>&              taylor_x     ,
-        vector<double>&                    taylor_y     )
+        vector<double>&                    taylor_y     ) override
     {
 # ifndef NDEBUG
         size_t n = taylor_x.size() / (order_up + 1);
@@ -111,13 +111,13 @@ $srccode%cpp% */
 $head jac_sparsity$$
 $srccode%cpp% */
     // Jacobian sparsity routine called by CppAD
-    virtual bool jac_sparsity(
+    bool jac_sparsity(
         const vector<double>&               parameter_x ,
         const vector<CppAD::ad_type_enum>&  type_x      ,
         bool                                dependency  ,
         const vector<bool>&                 select_x    ,
         const vector<bool>&                 select_y    ,
-        CppAD::sparse_rc< vector<size_t> >& pattern_out )
+        CppAD::sparse_rc< vector<size_t> >& pattern_out ) override
     {
         size_t n = select_x.size();
         size_t m = select_y.size();
diff --git a/example/atomic_three/makefile.am b/example/atomic_three/makefile.am
index 00528030b..93ccf1ba2 100644
--- a/example/atomic_three/makefile.am
+++ b/example/atomic_three/makefile.am
@@ -1,5 +1,5 @@
 # -----------------------------------------------------------------------------
-# CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-18 Bradley M. Bell
+# 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.
@@ -37,7 +37,8 @@ atomic_SOURCES   = \
 	hes_sparsity.cpp \
 	jac_sparsity.cpp \
 	reverse.cpp \
-	rev_depend.cpp
+	rev_depend.cpp \
+	vector_op.cpp
 
 test: check
 	./atomic
diff --git a/example/atomic_three/makefile.in b/example/atomic_three/makefile.in
index bca13c41d..e2fdd364e 100644
--- a/example/atomic_three/makefile.in
+++ b/example/atomic_three/makefile.in
@@ -101,7 +101,8 @@ am_atomic_OBJECTS = atomic_three.$(OBJEXT) mat_mul.$(OBJEXT) \
 	norm_sq.$(OBJEXT) tangent.$(OBJEXT) base2ad.$(OBJEXT) \
 	reciprocal.$(OBJEXT) dynamic.$(OBJEXT) forward.$(OBJEXT) \
 	get_started.$(OBJEXT) hes_sparsity.$(OBJEXT) \
-	jac_sparsity.$(OBJEXT) reverse.$(OBJEXT) rev_depend.$(OBJEXT)
+	jac_sparsity.$(OBJEXT) reverse.$(OBJEXT) rev_depend.$(OBJEXT) \
+	vector_op.$(OBJEXT)
 atomic_OBJECTS = $(am_atomic_OBJECTS)
 atomic_LDADD = $(LDADD)
 AM_V_P = $(am__v_P_@AM_V@)
@@ -125,7 +126,8 @@ am__depfiles_remade = ./$(DEPDIR)/atomic_three.Po \
 	./$(DEPDIR)/hes_sparsity.Po ./$(DEPDIR)/jac_sparsity.Po \
 	./$(DEPDIR)/mat_mul.Po ./$(DEPDIR)/norm_sq.Po \
 	./$(DEPDIR)/reciprocal.Po ./$(DEPDIR)/rev_depend.Po \
-	./$(DEPDIR)/reverse.Po ./$(DEPDIR)/tangent.Po
+	./$(DEPDIR)/reverse.Po ./$(DEPDIR)/tangent.Po \
+	./$(DEPDIR)/vector_op.Po
 am__mv = mv -f
 CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
 	$(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
@@ -196,7 +198,7 @@ CXX_FLAGS = @CXX_FLAGS@
 CYGPATH_W = @CYGPATH_W@
 
 # -----------------------------------------------------------------------------
-# CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-18 Bradley M. Bell
+# 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.
@@ -279,7 +281,6 @@ 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@
@@ -334,6 +335,7 @@ pdfdir = @pdfdir@
 prefix = @prefix@
 program_transform_name = @program_transform_name@
 psdir = @psdir@
+runstatedir = @runstatedir@
 sbindir = @sbindir@
 sharedstatedir = @sharedstatedir@
 srcdir = @srcdir@
@@ -365,7 +367,8 @@ atomic_SOURCES = \
 	hes_sparsity.cpp \
 	jac_sparsity.cpp \
 	reverse.cpp \
-	rev_depend.cpp
+	rev_depend.cpp \
+	vector_op.cpp
 
 all: all-am
 
@@ -427,6 +430,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rev_depend.Po@am__quote@ # am--include-marker
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/reverse.Po@am__quote@ # am--include-marker
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tangent.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/vector_op.Po@am__quote@ # am--include-marker
 
 $(am__depfiles_remade):
 	@$(MKDIR_P) $(@D)
@@ -588,6 +592,7 @@ distclean: distclean-am
 	-rm -f ./$(DEPDIR)/rev_depend.Po
 	-rm -f ./$(DEPDIR)/reverse.Po
 	-rm -f ./$(DEPDIR)/tangent.Po
+	-rm -f ./$(DEPDIR)/vector_op.Po
 	-rm -f makefile
 distclean-am: clean-am distclean-compile distclean-generic \
 	distclean-tags
@@ -646,6 +651,7 @@ maintainer-clean: maintainer-clean-am
 	-rm -f ./$(DEPDIR)/rev_depend.Po
 	-rm -f ./$(DEPDIR)/reverse.Po
 	-rm -f ./$(DEPDIR)/tangent.Po
+	-rm -f ./$(DEPDIR)/vector_op.Po
 	-rm -f makefile
 maintainer-clean-am: distclean-am maintainer-clean-generic
 
diff --git a/example/atomic_three/norm_sq.cpp b/example/atomic_three/norm_sq.cpp
index 7cb6f9af7..711fcebea 100644
--- a/example/atomic_three/norm_sq.cpp
+++ b/example/atomic_three/norm_sq.cpp
@@ -1,5 +1,5 @@
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-18 Bradley M. Bell
+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.
@@ -50,10 +50,10 @@ private:
 $head for_type$$
 $srccode%cpp% */
     // calculate type_y
-    virtual bool for_type(
+    bool for_type(
         const vector<double>&               parameter_x ,
         const vector<CppAD::ad_type_enum>&  type_x      ,
-        vector<CppAD::ad_type_enum>&        type_y      )
+        vector<CppAD::ad_type_enum>&        type_y      ) override
     {   assert( parameter_x.size() == type_x.size() );
         bool ok = type_x.size() == 2; // n
         ok     &= type_y.size() == 1; // m
@@ -66,14 +66,14 @@ $srccode%cpp% */
 $head forward$$
 $srccode%cpp% */
     // forward mode routine called by CppAD
-    virtual bool forward(
+    bool forward(
         const vector<double>&              parameter_x ,
         const vector<CppAD::ad_type_enum>& type_x      ,
         size_t                             need_y      ,
         size_t                             p           ,
         size_t                             q           ,
         const vector<double>&              tx          ,
-        vector<double>&                    ty          )
+        vector<double>&                    ty          ) override
     {
 # ifndef NDEBUG
         size_t n = tx.size() / (q+1);
@@ -117,14 +117,14 @@ $srccode%cpp% */
 $head reverse$$
 $srccode%cpp% */
     // reverse mode routine called by CppAD
-    virtual bool reverse(
+    bool reverse(
         const vector<double>&               parameter_x ,
         const vector<CppAD::ad_type_enum>&  type_x      ,
         size_t                              q           ,
         const vector<double>&               tx          ,
         const vector<double>&               ty          ,
         vector<double>&                     px          ,
-        const vector<double>&               py          )
+        const vector<double>&               py          ) override
     {
 # ifndef NDEBUG
         size_t n = tx.size() / (q+1);
@@ -158,13 +158,13 @@ $srccode%cpp% */
 $head jac_sparsity$$
 $srccode%cpp% */
     // Jacobian sparsity routine called by CppAD
-    virtual bool jac_sparsity(
+    bool jac_sparsity(
         const vector<double>&               parameter_x ,
         const vector<CppAD::ad_type_enum>&  type_x      ,
         bool                                dependency  ,
         const vector<bool>&                 select_x    ,
         const vector<bool>&                 select_y    ,
-        CppAD::sparse_rc< vector<size_t> >& pattern_out )
+        CppAD::sparse_rc< vector<size_t> >& pattern_out ) override
     {   size_t n = select_x.size();
         size_t m = select_y.size();
         assert( n == 2 );
@@ -194,12 +194,12 @@ $srccode%cpp% */
 $head hes_sparsity$$
 $srccode%cpp% */
     // Hessian sparsity routine called by CppAD
-    virtual bool hes_sparsity(
+    bool hes_sparsity(
         const vector<double>&               parameter_x ,
         const vector<CppAD::ad_type_enum>&  type_x      ,
         const vector<bool>&                 select_x    ,
         const vector<bool>&                 select_y    ,
-        CppAD::sparse_rc< vector<size_t> >& pattern_out )
+        CppAD::sparse_rc< vector<size_t> >& pattern_out ) override
     {   size_t n = select_x.size();
         assert( n == 2 );
         assert( select_y.size() == 1 ); // m
diff --git a/example/atomic_three/reciprocal.cpp b/example/atomic_three/reciprocal.cpp
index e4f6bb6c6..8196d9344 100644
--- a/example/atomic_three/reciprocal.cpp
+++ b/example/atomic_three/reciprocal.cpp
@@ -1,5 +1,5 @@
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-18 Bradley M. Bell
+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.
@@ -45,10 +45,10 @@ private:
 $head for_type$$
 $srccode%cpp% */
     // calculate type_y
-    virtual bool for_type(
+    bool for_type(
         const vector<double>&               parameter_x ,
         const vector<CppAD::ad_type_enum>&  type_x      ,
-        vector<CppAD::ad_type_enum>&        type_y      )
+        vector<CppAD::ad_type_enum>&        type_y      ) override
     {   assert( parameter_x.size() == type_x.size() );
         bool ok = type_x.size() == 1; // n
         ok     &= type_y.size() == 1; // m
@@ -61,14 +61,14 @@ $srccode%cpp% */
 $head forward$$
 $srccode%cpp% */
     // forward mode routine called by CppAD
-    virtual bool forward(
+    bool forward(
         const vector<double>&              parameter_x ,
         const vector<CppAD::ad_type_enum>& type_x      ,
         size_t                             need_y      ,
         size_t                             p           ,
         size_t                             q           ,
         const vector<double>&              tx          ,
-        vector<double>&                    ty          )
+        vector<double>&                    ty          ) override
     {
 # ifndef NDEBUG
         size_t n = tx.size() / (q + 1);
@@ -117,14 +117,14 @@ $srccode%cpp% */
 $head reverse$$
 $srccode%cpp% */
     // reverse mode routine called by CppAD
-    virtual bool reverse(
+    bool reverse(
         const vector<double>&               parameter_x ,
         const vector<CppAD::ad_type_enum>&  type_x      ,
         size_t                              q           ,
         const vector<double>&               tx           ,
         const vector<double>&               ty           ,
         vector<double>&                     px           ,
-        const vector<double>&               py           )
+        const vector<double>&               py           ) override
     {
 # ifndef NDEBUG
         size_t n = tx.size() / (q + 1);
@@ -188,13 +188,13 @@ $srccode%cpp% */
 $head jac_sparsity$$
 $srccode%cpp% */
     // Jacobian sparsity routine called by CppAD
-    virtual bool jac_sparsity(
+    bool jac_sparsity(
         const vector<double>&               parameter_x ,
         const vector<CppAD::ad_type_enum>&  type_x      ,
         bool                                dependency  ,
         const vector<bool>&                 select_x    ,
         const vector<bool>&                 select_y    ,
-        CppAD::sparse_rc< vector<size_t> >& pattern_out )
+        CppAD::sparse_rc< vector<size_t> >& pattern_out ) override
     {
         size_t n = select_x.size();
         size_t m = select_y.size();
@@ -222,12 +222,12 @@ $srccode%cpp% */
 $head hes_sparsity$$
 $srccode%cpp% */
     // Hessian sparsity routine called by CppAD
-    virtual bool hes_sparsity(
+    bool hes_sparsity(
         const vector<double>&               parameter_x ,
         const vector<CppAD::ad_type_enum>&  type_x      ,
         const vector<bool>&                 select_x    ,
         const vector<bool>&                 select_y    ,
-        CppAD::sparse_rc< vector<size_t> >& pattern_out )
+        CppAD::sparse_rc< vector<size_t> >& pattern_out ) override
     {
         assert( parameter_x.size() == select_x.size() );
         assert( select_y.size() == 1 );
diff --git a/example/atomic_three/rev_depend.cpp b/example/atomic_three/rev_depend.cpp
index bb380f255..bf40b91e3 100644
--- a/example/atomic_three/rev_depend.cpp
+++ b/example/atomic_three/rev_depend.cpp
@@ -1,5 +1,5 @@
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 Bradley M. Bell
+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.
@@ -49,10 +49,10 @@ private:
 $head for_type$$
 $srccode%cpp% */
     // calculate type_y
-    virtual bool for_type(
+    bool for_type(
         const vector<double>&               parameter_x ,
         const vector<CppAD::ad_type_enum>&  type_x      ,
-        vector<CppAD::ad_type_enum>&        type_y      )
+        vector<CppAD::ad_type_enum>&        type_y      ) override
     {   assert( parameter_x.size() == type_x.size() );
         bool ok = type_x.size() == 3; // n
         ok     &= type_y.size() == 3; // m
@@ -67,11 +67,11 @@ $srccode%cpp% */
 $head rev_depend$$
 $srccode%cpp% */
     // calculate depend_x
-    virtual bool rev_depend(
+    bool rev_depend(
         const vector<double>&               parameter_x ,
         const vector<CppAD::ad_type_enum>&  type_x      ,
         vector<bool>&                       depend_x    ,
-        const vector<bool>&                 depend_y    )
+        const vector<bool>&                 depend_y    ) override
     {   assert( parameter_x.size() == depend_x.size() );
         bool ok = depend_x.size() == 3; // n
         ok     &= depend_y.size() == 3; // m
@@ -86,7 +86,7 @@ $srccode%cpp% */
 $head forward$$
 $srccode%cpp% */
     // forward mode routine called by CppAD
-    virtual bool forward(
+    bool forward(
         const vector<double>&               parameter_x ,
         const vector<CppAD::ad_type_enum>&  type_x      ,
         size_t                              need_y      ,
@@ -94,7 +94,7 @@ $srccode%cpp% */
         size_t                              order_up    ,
         const vector<double>&               taylor_x    ,
         vector<double>&                     taylor_y
-    )
+    ) override
     {
 # ifndef NDEBUG
         size_t n = taylor_x.size() / (order_up + 1);
diff --git a/example/atomic_three/reverse.cpp b/example/atomic_three/reverse.cpp
index 12e75c115..e669afcfa 100644
--- a/example/atomic_three/reverse.cpp
+++ b/example/atomic_three/reverse.cpp
@@ -1,5 +1,5 @@
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-18 Bradley M. Bell
+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.
@@ -77,10 +77,10 @@ private:
 $head for_type$$
 $srccode%cpp% */
     // calculate type_y
-    virtual bool for_type(
+    bool for_type(
         const vector<double>&               parameter_x ,
         const vector<CppAD::ad_type_enum>&  type_x      ,
-        vector<CppAD::ad_type_enum>&        type_y      )
+        vector<CppAD::ad_type_enum>&        type_y      ) override
     {   assert( parameter_x.size() == type_x.size() );
         bool ok = type_x.size() == 3; // n
         ok     &= type_y.size() == 2; // m
@@ -94,14 +94,14 @@ $srccode%cpp% */
 $head forward$$
 $srccode%cpp% */
     // forward mode routine called by CppAD
-    virtual bool forward(
+    bool forward(
         const vector<double>&                   parameter_x ,
         const vector<CppAD::ad_type_enum>&      type_x      ,
         size_t                                  need_y      ,
         size_t                                  order_low   ,
         size_t                                  order_up    ,
         const vector<double>&                   taylor_x    ,
-        vector<double>&                         taylor_y    )
+        vector<double>&                         taylor_y    ) override
     {
         size_t q1 = order_up + 1;
 # ifndef NDEBUG
@@ -151,14 +151,14 @@ $srccode%cpp% */
 $head reverse$$
 $srccode%cpp% */
     // reverse mode routine called by CppAD
-    virtual bool reverse(
+    bool reverse(
         const vector<double>&               parameter_x ,
         const vector<CppAD::ad_type_enum>&  type_x      ,
         size_t                              order_up    ,
         const vector<double>&               taylor_x    ,
         const vector<double>&               taylor_y    ,
         vector<double>&                     partial_x   ,
-        const vector<double>&               partial_y   )
+        const vector<double>&               partial_y   ) override
     {
         size_t q1 = order_up + 1;
         size_t n = taylor_x.size() / q1;
diff --git a/example/atomic_three/tangent.cpp b/example/atomic_three/tangent.cpp
index 5470e28dd..10352b859 100644
--- a/example/atomic_three/tangent.cpp
+++ b/example/atomic_three/tangent.cpp
@@ -1,5 +1,5 @@
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-18 Bradley M. Bell
+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.
@@ -52,10 +52,10 @@ private:
 $head for_type$$
 $srccode%cpp% */
     // calculate type_y
-    virtual bool for_type(
+    bool for_type(
         const vector<float>&                parameter_x ,
         const vector<CppAD::ad_type_enum>&  type_x      ,
-        vector<CppAD::ad_type_enum>&        type_y      )
+        vector<CppAD::ad_type_enum>&        type_y      ) override
     {   assert( parameter_x.size() == type_x.size() );
         bool ok = type_x.size() == 1; // n
         ok     &= type_y.size() == 2; // m
@@ -69,14 +69,14 @@ $srccode%cpp% */
 $head forward$$
 $srccode%cpp% */
     // forward mode routine called by CppAD
-    virtual bool forward(
+    bool forward(
         const vector<float>&               parameter_x ,
         const vector<CppAD::ad_type_enum>& type_x      ,
         size_t                             need_y      ,
         size_t                             p           ,
         size_t                             q           ,
         const vector<float>&               tx          ,
-        vector<float>&                     tzy         )
+        vector<float>&                     tzy         ) override
     {   size_t q1 = q + 1;
 # ifndef NDEBUG
         size_t n  = tx.size()  / q1;
@@ -123,14 +123,14 @@ $srccode%cpp% */
 $head reverse$$
 $srccode%cpp% */
     // reverse mode routine called by CppAD
-    virtual bool reverse(
+    bool reverse(
         const vector<float>&               parameter_x ,
         const vector<CppAD::ad_type_enum>& type_x      ,
         size_t                             q           ,
         const vector<float>&               tx          ,
         const vector<float>&               tzy         ,
         vector<float>&                     px          ,
-        const vector<float>&               pzy         )
+        const vector<float>&               pzy         ) override
     {   size_t q1 = q + 1;
 # ifndef NDEBUG
         size_t n  = tx.size()  / q1;
@@ -182,13 +182,13 @@ $srccode%cpp% */
 $head jac_sparsity$$
 $srccode%cpp% */
     // Jacobian sparsity routine called by CppAD
-    virtual bool jac_sparsity(
+    bool jac_sparsity(
         const vector<float>&                parameter_x ,
         const vector<CppAD::ad_type_enum>&  type_x      ,
         bool                                dependency  ,
         const vector<bool>&                 select_x    ,
         const vector<bool>&                 select_y    ,
-        CppAD::sparse_rc< vector<size_t> >& pattern_out )
+        CppAD::sparse_rc< vector<size_t> >& pattern_out ) override
     {
         size_t n = select_x.size();
         size_t m = select_y.size();
@@ -222,12 +222,12 @@ $srccode%cpp% */
 $head hes_sparsity$$
 $srccode%cpp% */
     // Hessian sparsity routine called by CppAD
-    virtual bool hes_sparsity(
+    bool hes_sparsity(
         const vector<float>&                parameter_x ,
         const vector<CppAD::ad_type_enum>&  type_x      ,
         const vector<bool>&                 select_x    ,
         const vector<bool>&                 select_y    ,
-        CppAD::sparse_rc< vector<size_t> >& pattern_out )
+        CppAD::sparse_rc< vector<size_t> >& pattern_out ) override
     {
         assert( parameter_x.size() == select_x.size() );
         assert( select_y.size() == 2 );
diff --git a/example/atomic_two/makefile.in b/example/atomic_two/makefile.in
index 8ecc3670e..a73023753 100644
--- a/example/atomic_two/makefile.in
+++ b/example/atomic_two/makefile.in
@@ -276,7 +276,6 @@ 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@
@@ -331,6 +330,7 @@ pdfdir = @pdfdir@
 prefix = @prefix@
 program_transform_name = @program_transform_name@
 psdir = @psdir@
+runstatedir = @runstatedir@
 sbindir = @sbindir@
 sharedstatedir = @sharedstatedir@
 srcdir = @srcdir@
diff --git a/example/chkpoint_two/makefile.in b/example/chkpoint_two/makefile.in
index 3eb7188e8..d4b450876 100644
--- a/example/chkpoint_two/makefile.in
+++ b/example/chkpoint_two/makefile.in
@@ -274,7 +274,6 @@ 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@
@@ -329,6 +328,7 @@ pdfdir = @pdfdir@
 prefix = @prefix@
 program_transform_name = @program_transform_name@
 psdir = @psdir@
+runstatedir = @runstatedir@
 sbindir = @sbindir@
 sharedstatedir = @sharedstatedir@
 srcdir = @srcdir@
diff --git a/example/general/CMakeLists.txt b/example/general/CMakeLists.txt
index 3c134c09e..24264968c 100644
--- a/example/general/CMakeLists.txt
+++ b/example/general/CMakeLists.txt
@@ -1,5 +1,5 @@
 # -----------------------------------------------------------------------------
-# CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
+# 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.
@@ -76,6 +76,8 @@ SET(source_list
     forward_order.cpp
     fun_assign.cpp
     fun_check.cpp
+    fun_property.cpp
+    function_name.cpp
     general.cpp
     hes_lagrangian.cpp
     hes_lu_det.cpp
@@ -109,14 +111,14 @@ SET(source_list
     ode_stiff.cpp
     opt_val_hes.cpp
     pow.cpp
+    pow_nan.cpp
     print_for.cpp
+    rev_checkpoint.cpp
     rev_one.cpp
     rev_two.cpp
-    rev_checkpoint.cpp
     reverse_one.cpp
     reverse_three.cpp
     reverse_two.cpp
-    seq_property.cpp
     sign.cpp
     sin.cpp
     sinh.cpp
diff --git a/example/general/atan2.cpp b/example/general/atan2.cpp
index b18c30db7..5a740da1f 100644
--- a/example/general/atan2.cpp
+++ b/example/general/atan2.cpp
@@ -1,5 +1,5 @@
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
+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.
@@ -27,61 +27,68 @@ $end
 // BEGIN C++
 
 # include <cppad/cppad.hpp>
+# define N_THETA 20
 
 bool atan2(void)
 {   bool ok = true;
-
+    //
     using CppAD::AD;
     using CppAD::NearEqual;
     double eps99 = 99.0 * std::numeric_limits<double>::epsilon();
-
-    // domain space vector
-    size_t n  = 1;
-    double x0 = 0.5;
-    CPPAD_TESTVECTOR(AD<double>) x(n);
-    x[0]      = x0;
-
-    // declare independent variables and start tape recording
-    CppAD::Independent(x);
-
-    // a temporary value
-    AD<double> sin_of_x0 = CppAD::sin(x[0]);
-    AD<double> cos_of_x0 = CppAD::cos(x[0]);
-
-    // range space vector
-    size_t m = 1;
-    CPPAD_TESTVECTOR(AD<double>) y(m);
-    y[0] = CppAD::atan2(sin_of_x0, cos_of_x0);
-
-    // create f: x -> y and stop tape recording
-    CppAD::ADFun<double> f(x, y);
-
-    // check value
-    ok &= NearEqual(y[0] , x0, eps99, eps99);
-
-    // forward computation of first partial w.r.t. x[0]
-    CPPAD_TESTVECTOR(double) dx(n);
-    CPPAD_TESTVECTOR(double) dy(m);
-    dx[0] = 1.;
-    dy    = f.Forward(1, dx);
-    ok   &= NearEqual(dy[0], 1., eps99, eps99);
-
-    // reverse computation of derivative of y[0]
-    CPPAD_TESTVECTOR(double)  w(m);
-    CPPAD_TESTVECTOR(double) dw(n);
-    w[0]  = 1.;
-    dw    = f.Reverse(1, w);
-    ok   &= NearEqual(dw[0], 1., eps99, eps99);
-
-    // use a VecAD<Base>::reference object with atan2
-    CppAD::VecAD<double> v(2);
-    AD<double> zero(0);
-    AD<double> one(1);
-    v[zero]           = sin_of_x0;
-    v[one]            = cos_of_x0;
-    AD<double> result = CppAD::atan2(v[zero], v[one]);
-    ok               &= NearEqual(result, x0, eps99, eps99);
-
+    double pi    = 2.0 * std::atan(1.0);
+    //
+    for(size_t k = 0; k < N_THETA; ++k)
+    {   // theta
+        double theta =  2.0 * pi * double(k+1) / double(N_THETA) - pi;
+        //
+        // radius
+        double radius = 1.0 + double(k) / double(N_THETA);
+        //
+        // x, y
+        double x = radius * std::cos(theta);
+        double y = radius * std::sin(theta);
+        //
+        // au
+        CPPAD_TESTVECTOR(AD<double>) au(2);
+        au[0] = x;
+        au[1] = y;
+        CppAD::Independent(au);
+        //
+        // av
+        CPPAD_TESTVECTOR(AD<double>) av(1);
+        av[0] = CppAD::atan2(au[1], au[0]);
+        //
+        // f(x, y) = atan2(y, x)
+        CppAD::ADFun<double> f(au, av);
+        //
+        // check value
+        ok &= NearEqual(av[0] , theta, eps99, eps99);
+        //
+        // partial_x, partial_y
+        // see https://en.wikipedia.org/wiki/Atan2#Derivative
+        double partial_x = - y / (radius * radius);
+        double partial_y =   x / (radius * radius);
+        //
+        // check forward mode
+        CPPAD_TESTVECTOR(double) du(2), dv(1);
+        du[0] = 1.0;
+        du[1] = 0.0;
+        dv    = f.Forward(1, du);
+        ok   &= NearEqual(dv[0], partial_x, eps99, eps99);
+        du[0] = 0.0;
+        du[1] = 1.0;
+        dv    = f.Forward(1, du);
+        ok   &= NearEqual(dv[0], partial_y, eps99, eps99);
+        //
+        // check reverse mode
+        CPPAD_TESTVECTOR(double)  w(1);
+        CPPAD_TESTVECTOR(double) dw(2);
+        w[0]  = 1.;
+        dw    = f.Reverse(1, w);
+        ok   &= NearEqual(dw[0], partial_x, eps99, eps99);
+        ok   &= NearEqual(dw[1], partial_y, eps99, eps99);
+        //
+    }
     return ok;
 }
 
diff --git a/example/general/cond_exp.cpp b/example/general/cond_exp.cpp
index 45cebe568..210e8a8e6 100644
--- a/example/general/cond_exp.cpp
+++ b/example/general/cond_exp.cpp
@@ -1,5 +1,5 @@
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
+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.
@@ -36,7 +36,7 @@ using only one $cref ADFun$$ object.
 Note that $latex x_j \log ( x_j ) \rightarrow 0 $$
 as $latex x_j \downarrow 0$$ and
 we need to handle the case $latex x_j = 0$$
-in a special way to avoid multiplying zero by infinity.
+in a special way to avoid returning zero times minus infinity.
 
 $srcthisfile%0%// BEGIN C++%// END C++%1%$$
 
@@ -107,23 +107,20 @@ bool CondExp(void)
     // a case where x[3] is equal to zero
     check -= x[3] * log( x[3] );
     x[3]   = 0.;
+    ok &= std::isnan( x[3] * log( x[3] ) );
 
     // function value
     y   = f.Forward(0, x);
     ok &= NearEqual(y[0], check, eps, eps);
 
     // check derivative of y[0]
-    f.check_for_nan(false);
     w[0] = 1.;
     dw   = f.Reverse(1, w);
     for(j = 0; j < n; j++)
     {   if( x[j] > 0 )
             ok &= NearEqual(dw[j], log(x[j]) + 1., eps, eps);
         else
-        {   // Note that in case where dw has type AD<double> and is a variable
-            // this dw[j] can be nan (zero times nan is not zero).
             ok &= NearEqual(dw[j], 0.0, eps, eps);
-        }
     }
 
     return ok;
diff --git a/example/general/fabs.cpp b/example/general/fabs.cpp
index f4f026c11..7e3e82fea 100644
--- a/example/general/fabs.cpp
+++ b/example/general/fabs.cpp
@@ -1,5 +1,5 @@
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
+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.
@@ -33,88 +33,69 @@ bool fabs(void)
 
     using CppAD::AD;
     using CppAD::NearEqual;
-    double eps99 = 99.0 * std::numeric_limits<double>::epsilon();
 
     // domain space vector
     size_t n = 1;
-    CPPAD_TESTVECTOR(AD<double>) x(n);
-    x[0]     = 0.;
+    CPPAD_TESTVECTOR(AD<double>) ax(n);
+    ax[0] = 0.;
 
     // declare independent variables and start tape recording
-    CppAD::Independent(x);
+    CppAD::Independent(ax);
 
     // range space vector
-    size_t m = 6;
-    CPPAD_TESTVECTOR(AD<double>) y(m);
-    y[0]     = fabs(x[0] - 1.);
-    y[1]     = fabs(x[0]);
-    y[2]     = fabs(x[0] + 1.);
+    size_t m = 3;
+    CPPAD_TESTVECTOR(AD<double>) ay(m);
+    ay[0]     = fabs(ax[0] - 1.);
+    ay[1]     = fabs(ax[0]);
+    ay[2]     = fabs(ax[0] + 1.);
     //
-    y[3]     = fabs(x[0] - 1.);
-    y[4]     = fabs(x[0]);
-    y[5]     = fabs(x[0] + 1.);
-
     // create f: x -> y and stop tape recording
-    CppAD::ADFun<double> f(x, y);
+    CppAD::ADFun<double> f(ax, ay);
 
     // check values
-    ok &= (y[0] == 1.);
-    ok &= (y[1] == 0.);
-    ok &= (y[2] == 1.);
+    ok &= (ay[0] == 1.);
+    ok &= (ay[1] == 0.);
+    ok &= (ay[2] == 1.);
     //
-    ok &= (y[3] == 1.);
-    ok &= (y[4] == 0.);
-    ok &= (y[5] == 1.);
-
     // forward computation of partials w.r.t. a positive x[0] direction
     size_t p = 1;
     CPPAD_TESTVECTOR(double) dx(n), dy(m);
     dx[0] = 1.;
     dy    = f.Forward(p, dx);
     ok  &= (dy[0] == - dx[0]);
-    ok  &= (dy[1] ==   0.   ); // used to be (dy[1] == + dx[0]);
+    ok  &= (dy[1] ==   0.   );
     ok  &= (dy[2] == + dx[0]);
     //
-    ok  &= (dy[3] == - dx[0]);
-    ok  &= (dy[4] ==   0.   ); // used to be (dy[1] == + dx[0]);
-    ok  &= (dy[5] == + dx[0]);
-
     // forward computation of partials w.r.t. a negative x[0] direction
     dx[0] = -1.;
     dy    = f.Forward(p, dx);
     ok  &= (dy[0] == - dx[0]);
-    ok  &= (dy[1] ==   0.   ); // used to be (dy[1] == - dx[0]);
+    ok  &= (dy[1] ==   0.   );
     ok  &= (dy[2] == + dx[0]);
     //
-    ok  &= (dy[3] == - dx[0]);
-    ok  &= (dy[4] ==   0.   ); // used to be (dy[1] == - dx[0]);
-    ok  &= (dy[5] == + dx[0]);
-
     // reverse computation of derivative of y[0]
     p    = 1;
     CPPAD_TESTVECTOR(double)  w(m), dw(n);
-    w[0] = 1.; w[1] = 0.; w[2] = 0.; w[3] = 0.; w[4] = 0.; w[5] = 0.;
+    w[0] = 1.; w[1] = 0.; w[2] = 0;
     dw   = f.Reverse(p, w);
     ok  &= (dw[0] == -1.);
 
     // reverse computation of derivative of y[1]
-    w[0] = 0.; w[1] = 1.;
+    w[0] = 0.; w[1] = 1.; w[2] = 0;
     dw   = f.Reverse(p, w);
     ok  &= (dw[0] == 0.);
 
-    // reverse computation of derivative of y[5]
-    w[1] = 0.; w[5] = 1.;
+    // reverse computation of derivative of y[3]
+    w[0] = 0.; w[1] = 0.; w[2] = 1;
     dw   = f.Reverse(p, w);
     ok  &= (dw[0] == 1.);
 
-    // use a VecAD<Base>::reference object with abs and fabs
-    CppAD::VecAD<double> v(1);
-    AD<double> zero(0);
-    v[zero]           = -1;
-    AD<double> result = fabs(v[zero]);
-    ok    &= NearEqual(result, 1., eps99, eps99);
-    result = fabs(v[zero]);
-    ok    &= NearEqual(result, 1., eps99, eps99);
+    // use a VecAD<Base>::reference object with fabs
+    CppAD::VecAD<double> av(1);
+    AD<double> az(0);
+    av[az]   = -1;
+    AD<double> a_result = fabs(av[az]);
+    ok  &= a_result == 1.0;
 
     return ok;
 }
diff --git a/example/general/seq_property.cpp b/example/general/fun_property.cpp
similarity index 96%
rename from example/general/seq_property.cpp
rename to example/general/fun_property.cpp
index b068bc95a..b68adbb1f 100644
--- a/example/general/seq_property.cpp
+++ b/example/general/fun_property.cpp
@@ -1,5 +1,5 @@
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
+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.
@@ -11,7 +11,7 @@ in the Eclipse Public License, Version 2.0 are satisfied:
 ---------------------------------------------------------------------------- */
 
 /*
-$begin seq_property.cpp$$
+$begin fun_property.cpp$$
 $spell
     op
     arg
@@ -20,7 +20,7 @@ $spell
     VecAD
 $$
 
-$section ADFun Sequence Properties: Example and Test$$
+$section ADFun Function Properties: Example and Test$$
 
 $srcthisfile%0%// BEGIN C++%// END C++%1%$$
 
@@ -33,7 +33,7 @@ $end
 // Note that CPPAD_VEC_ENUM_TYPE is not part of CppAD API and may change
 # define CPPAD_VEC_ENUM_TYPE unsigned char
 
-bool seq_property(void)
+bool fun_property(void)
 {   bool ok = true;
     using CppAD::AD;
 
diff --git a/example/general/function_name.cpp b/example/general/function_name.cpp
new file mode 100644
index 000000000..5a01c5b89
--- /dev/null
+++ b/example/general/function_name.cpp
@@ -0,0 +1,61 @@
+/* --------------------------------------------------------------------------
+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 function_name.cpp$$
+$spell
+$$
+
+$section ADFun Function Name: Example and Test$$
+
+$srcthisfile%0%// BEGIN C++%// END C++%1%$$
+
+$end
+*/
+// BEGIN C++
+
+# include <cppad/cppad.hpp>
+
+bool function_name(void)
+{   bool ok = true;
+    using CppAD::AD;
+
+    // create empty function
+    CppAD::ADFun<double> f;
+
+    // check its name
+    ok &= f.function_name_get() == "";
+
+    // set and check a new name
+    f.function_name_set("empty_function");
+    ok &= f.function_name_get() == "empty_function";
+
+    // store an operation sequence in f
+    size_t nx = 1;
+    size_t ny = 1;
+    CPPAD_TESTVECTOR( AD<double> ) ax(nx), ay(ny);
+    ax[0] = 1.0;
+    CppAD::Independent(ax);
+    ay[0] = sin(ax[0]);
+    f.Dependent(ax, ay);
+
+    // check fucntion name has not changed
+    ok &= f.function_name_get() == "empty_function";
+
+    // now set a better name for this function
+    f.function_name_set("sin");
+    ok &= f.function_name_get() == "sin";
+
+    return ok;
+}
+
+// END C++
diff --git a/example/general/general.cpp b/example/general/general.cpp
index 90ca7985a..f3a64a864 100644
--- a/example/general/general.cpp
+++ b/example/general/general.cpp
@@ -1,5 +1,5 @@
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
+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.
@@ -126,6 +126,8 @@ extern bool fabs(void);
 extern bool forward_dir(void);
 extern bool forward_order(void);
 extern bool fun_assign(void);
+extern bool fun_property(void);
+extern bool function_name(void);
 extern bool interp_onetape(void);
 extern bool interp_retape(void);
 extern bool log(void);
@@ -141,12 +143,12 @@ extern bool num_limits(void);
 extern bool number_skip(void);
 extern bool opt_val_hes(void);
 extern bool pow(void);
+extern bool pow_nan(void);
 extern bool print_for(void);
 extern bool rev_checkpoint(void);
 extern bool reverse_one(void);
 extern bool reverse_three(void);
 extern bool reverse_two(void);
-extern bool seq_property(void);
 extern bool sign(void);
 extern bool taylor_ode(void);
 extern bool vec_ad(void);
@@ -238,6 +240,8 @@ int main(void)
     Run( forward_dir,       "forward_dir"      );
     Run( forward_order,     "forward_order"    );
     Run( fun_assign,        "fun_assign"       );
+    Run( fun_property,      "fun_property"     );
+    Run( function_name,     "function_name"    );
     Run( interp_onetape,    "interp_onetape"   );
     Run( interp_retape,     "interp_retape"    );
     Run( log,               "log"              );
@@ -251,11 +255,11 @@ int main(void)
     Run( number_skip,       "number_skip"      );
     Run( opt_val_hes,       "opt_val_hes"      );
     Run( pow,               "pow"              );
+    Run( pow_nan,           "pow_nan"          );
     Run( rev_checkpoint,    "rev_checkpoint"   );
     Run( reverse_one,       "reverse_one"      );
     Run( reverse_three,     "reverse_three"    );
     Run( reverse_two,       "reverse_two"      );
-    Run( seq_property,      "seq_property"     );
     Run( sign,              "sign"             );
     Run( taylor_ode,        "ode_taylor"       );
     Run( vec_ad,            "vec_ad"           );
diff --git a/example/general/makefile.am b/example/general/makefile.am
index 9ccb61e42..78ebf1f46 100644
--- a/example/general/makefile.am
+++ b/example/general/makefile.am
@@ -1,5 +1,5 @@
 # -----------------------------------------------------------------------------
-# CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
+# 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.
@@ -48,29 +48,29 @@ AM_CXXFLAGS =  \
 #
 LDADD        =  $(ADOLC_LIB)
 #
+# BEGIN_SORT_THIS_LINE_PLUS_5
 general_SOURCES   = \
 	$(ADOLC_SRC_FILES) \
 	$(EIGEN_SRC_FILES) \
 	\
 	abort_recording.cpp \
-	base2ad.cpp \
-	fabs.cpp \
 	acos.cpp \
 	acosh.cpp \
 	ad_assign.cpp \
 	ad_ctor.cpp \
-	add.cpp \
-	add_eq.cpp \
 	ad_fun.cpp \
 	ad_in_c.cpp \
 	ad_input.cpp \
 	ad_output.cpp \
+	add.cpp \
+	add_eq.cpp \
 	asin.cpp \
 	asinh.cpp \
-	atan2.cpp \
 	atan.cpp \
+	atan2.cpp \
 	atanh.cpp \
 	azmul.cpp \
+	base2ad.cpp \
 	base_alloc.hpp \
 	base_require.cpp \
 	bender_quad.cpp \
@@ -78,9 +78,10 @@ general_SOURCES   = \
 	capacity_order.cpp \
 	change_param.cpp \
 	check_for_nan.cpp \
-	compare_change.cpp \
 	compare.cpp \
+	compare_change.cpp \
 	complex_poly.cpp \
+	con_dyn_var.cpp \
 	cond_exp.cpp \
 	cos.cpp \
 	cosh.cpp \
@@ -89,9 +90,9 @@ general_SOURCES   = \
 	equal_op_seq.cpp \
 	erf.cpp \
 	erfc.cpp \
-	general.cpp \
 	exp.cpp \
 	expm1.cpp \
+	fabs.cpp \
 	for_one.cpp \
 	for_two.cpp \
 	forward.cpp \
@@ -99,11 +100,14 @@ general_SOURCES   = \
 	forward_order.cpp \
 	fun_assign.cpp \
 	fun_check.cpp \
+	fun_property.cpp \
+	function_name.cpp \
+	general.cpp \
 	hes_lagrangian.cpp \
 	hes_lu_det.cpp \
 	hes_minor_det.cpp \
-	hessian.cpp \
 	hes_times_dir.cpp \
+	hessian.cpp \
 	independent.cpp \
 	integer.cpp \
 	interface2c.cpp\
@@ -112,9 +116,9 @@ general_SOURCES   = \
 	jac_lu_det.cpp \
 	jac_minor_det.cpp \
 	jacobian.cpp \
+	log.cpp \
 	log10.cpp \
 	log1p.cpp \
-	log.cpp \
 	lu_ratio.cpp \
 	lu_vec_ad.cpp \
 	lu_vec_ad.hpp \
@@ -125,22 +129,20 @@ general_SOURCES   = \
 	mul_level_ode.cpp \
 	near_equal_ext.cpp \
 	new_dynamic.cpp \
+	num_limits.cpp \
 	number_skip.cpp \
 	numeric_type.cpp \
-	num_limits.cpp \
 	ode_stiff.cpp \
-	taylor_ode.cpp \
 	opt_val_hes.cpp \
-	con_dyn_var.cpp \
 	pow.cpp \
+	pow_nan.cpp \
 	print_for.cpp \
 	rev_checkpoint.cpp \
+	rev_one.cpp \
+	rev_two.cpp \
 	reverse_one.cpp \
 	reverse_three.cpp \
 	reverse_two.cpp \
-	rev_one.cpp \
-	rev_two.cpp \
-	seq_property.cpp \
 	sign.cpp \
 	sin.cpp \
 	sinh.cpp \
@@ -151,11 +153,13 @@ general_SOURCES   = \
 	tan.cpp \
 	tanh.cpp \
 	tape_index.cpp \
+	taylor_ode.cpp \
 	unary_minus.cpp \
 	unary_plus.cpp \
 	value.cpp \
 	var2par.cpp \
 	vec_ad.cpp
+# END_SORT_THIS_LINE_MINUS_2
 
 test: check
 	./general
diff --git a/example/general/makefile.in b/example/general/makefile.in
index c4bf37c14..28572ebd0 100644
--- a/example/general/makefile.in
+++ b/example/general/makefile.in
@@ -98,74 +98,75 @@ mkinstalldirs = $(install_sh) -d
 CONFIG_CLEAN_FILES =
 CONFIG_CLEAN_VPATH_FILES =
 am__general_SOURCES_DIST = mul_level_adolc.cpp mul_level_adolc_ode.cpp \
-	eigen_det.cpp eigen_array.cpp abort_recording.cpp base2ad.cpp \
-	fabs.cpp acos.cpp acosh.cpp ad_assign.cpp ad_ctor.cpp add.cpp \
-	add_eq.cpp ad_fun.cpp ad_in_c.cpp ad_input.cpp ad_output.cpp \
-	asin.cpp asinh.cpp atan2.cpp atan.cpp atanh.cpp azmul.cpp \
+	eigen_det.cpp eigen_array.cpp abort_recording.cpp acos.cpp \
+	acosh.cpp ad_assign.cpp ad_ctor.cpp ad_fun.cpp ad_in_c.cpp \
+	ad_input.cpp ad_output.cpp add.cpp add_eq.cpp asin.cpp \
+	asinh.cpp atan.cpp atan2.cpp atanh.cpp azmul.cpp base2ad.cpp \
 	base_alloc.hpp base_require.cpp bender_quad.cpp bool_fun.cpp \
 	capacity_order.cpp change_param.cpp check_for_nan.cpp \
-	compare_change.cpp compare.cpp complex_poly.cpp cond_exp.cpp \
-	cos.cpp cosh.cpp div.cpp div_eq.cpp equal_op_seq.cpp erf.cpp \
-	erfc.cpp general.cpp exp.cpp expm1.cpp for_one.cpp for_two.cpp \
-	forward.cpp forward_dir.cpp forward_order.cpp fun_assign.cpp \
-	fun_check.cpp hes_lagrangian.cpp hes_lu_det.cpp \
-	hes_minor_det.cpp hessian.cpp hes_times_dir.cpp \
-	independent.cpp integer.cpp interface2c.cpp interp_onetape.cpp \
-	interp_retape.cpp jac_lu_det.cpp jac_minor_det.cpp \
-	jacobian.cpp log10.cpp log1p.cpp log.cpp lu_ratio.cpp \
-	lu_vec_ad.cpp lu_vec_ad.hpp lu_vec_ad_ok.cpp mul.cpp \
-	mul_eq.cpp mul_level.cpp mul_level_ode.cpp near_equal_ext.cpp \
-	new_dynamic.cpp number_skip.cpp numeric_type.cpp \
-	num_limits.cpp ode_stiff.cpp taylor_ode.cpp opt_val_hes.cpp \
-	con_dyn_var.cpp pow.cpp print_for.cpp rev_checkpoint.cpp \
-	reverse_one.cpp reverse_three.cpp reverse_two.cpp rev_one.cpp \
-	rev_two.cpp seq_property.cpp sign.cpp sin.cpp sinh.cpp \
+	compare.cpp compare_change.cpp complex_poly.cpp \
+	con_dyn_var.cpp cond_exp.cpp cos.cpp cosh.cpp div.cpp \
+	div_eq.cpp equal_op_seq.cpp erf.cpp erfc.cpp exp.cpp expm1.cpp \
+	fabs.cpp for_one.cpp for_two.cpp forward.cpp forward_dir.cpp \
+	forward_order.cpp fun_assign.cpp fun_check.cpp \
+	fun_property.cpp function_name.cpp general.cpp \
+	hes_lagrangian.cpp hes_lu_det.cpp hes_minor_det.cpp \
+	hes_times_dir.cpp hessian.cpp independent.cpp integer.cpp \
+	interface2c.cpp interp_onetape.cpp interp_retape.cpp \
+	jac_lu_det.cpp jac_minor_det.cpp jacobian.cpp log.cpp \
+	log10.cpp log1p.cpp lu_ratio.cpp lu_vec_ad.cpp lu_vec_ad.hpp \
+	lu_vec_ad_ok.cpp mul.cpp mul_eq.cpp mul_level.cpp \
+	mul_level_ode.cpp near_equal_ext.cpp new_dynamic.cpp \
+	num_limits.cpp number_skip.cpp numeric_type.cpp ode_stiff.cpp \
+	opt_val_hes.cpp pow.cpp pow_nan.cpp print_for.cpp \
+	rev_checkpoint.cpp rev_one.cpp rev_two.cpp reverse_one.cpp \
+	reverse_three.cpp reverse_two.cpp sign.cpp sin.cpp sinh.cpp \
 	sqrt.cpp stack_machine.cpp sub.cpp sub_eq.cpp tan.cpp tanh.cpp \
-	tape_index.cpp unary_minus.cpp unary_plus.cpp value.cpp \
-	var2par.cpp vec_ad.cpp
+	tape_index.cpp taylor_ode.cpp unary_minus.cpp unary_plus.cpp \
+	value.cpp var2par.cpp vec_ad.cpp
 @CppAD_ADOLC_TRUE@am__objects_1 = mul_level_adolc.$(OBJEXT) \
 @CppAD_ADOLC_TRUE@	mul_level_adolc_ode.$(OBJEXT)
 @CppAD_EIGEN_TRUE@am__objects_2 = eigen_det.$(OBJEXT) \
 @CppAD_EIGEN_TRUE@	eigen_array.$(OBJEXT)
 am_general_OBJECTS = $(am__objects_1) $(am__objects_2) \
-	abort_recording.$(OBJEXT) base2ad.$(OBJEXT) fabs.$(OBJEXT) \
-	acos.$(OBJEXT) acosh.$(OBJEXT) ad_assign.$(OBJEXT) \
-	ad_ctor.$(OBJEXT) add.$(OBJEXT) add_eq.$(OBJEXT) \
-	ad_fun.$(OBJEXT) ad_in_c.$(OBJEXT) ad_input.$(OBJEXT) \
-	ad_output.$(OBJEXT) asin.$(OBJEXT) asinh.$(OBJEXT) \
-	atan2.$(OBJEXT) atan.$(OBJEXT) atanh.$(OBJEXT) azmul.$(OBJEXT) \
-	base_require.$(OBJEXT) bender_quad.$(OBJEXT) \
+	abort_recording.$(OBJEXT) acos.$(OBJEXT) acosh.$(OBJEXT) \
+	ad_assign.$(OBJEXT) ad_ctor.$(OBJEXT) ad_fun.$(OBJEXT) \
+	ad_in_c.$(OBJEXT) ad_input.$(OBJEXT) ad_output.$(OBJEXT) \
+	add.$(OBJEXT) add_eq.$(OBJEXT) asin.$(OBJEXT) asinh.$(OBJEXT) \
+	atan.$(OBJEXT) atan2.$(OBJEXT) atanh.$(OBJEXT) azmul.$(OBJEXT) \
+	base2ad.$(OBJEXT) base_require.$(OBJEXT) bender_quad.$(OBJEXT) \
 	bool_fun.$(OBJEXT) capacity_order.$(OBJEXT) \
 	change_param.$(OBJEXT) check_for_nan.$(OBJEXT) \
-	compare_change.$(OBJEXT) compare.$(OBJEXT) \
-	complex_poly.$(OBJEXT) cond_exp.$(OBJEXT) cos.$(OBJEXT) \
-	cosh.$(OBJEXT) div.$(OBJEXT) div_eq.$(OBJEXT) \
-	equal_op_seq.$(OBJEXT) erf.$(OBJEXT) erfc.$(OBJEXT) \
-	general.$(OBJEXT) exp.$(OBJEXT) expm1.$(OBJEXT) \
+	compare.$(OBJEXT) compare_change.$(OBJEXT) \
+	complex_poly.$(OBJEXT) con_dyn_var.$(OBJEXT) \
+	cond_exp.$(OBJEXT) cos.$(OBJEXT) cosh.$(OBJEXT) div.$(OBJEXT) \
+	div_eq.$(OBJEXT) equal_op_seq.$(OBJEXT) erf.$(OBJEXT) \
+	erfc.$(OBJEXT) exp.$(OBJEXT) expm1.$(OBJEXT) fabs.$(OBJEXT) \
 	for_one.$(OBJEXT) for_two.$(OBJEXT) forward.$(OBJEXT) \
 	forward_dir.$(OBJEXT) forward_order.$(OBJEXT) \
 	fun_assign.$(OBJEXT) fun_check.$(OBJEXT) \
-	hes_lagrangian.$(OBJEXT) hes_lu_det.$(OBJEXT) \
-	hes_minor_det.$(OBJEXT) hessian.$(OBJEXT) \
-	hes_times_dir.$(OBJEXT) independent.$(OBJEXT) \
-	integer.$(OBJEXT) interface2c.$(OBJEXT) \
+	fun_property.$(OBJEXT) function_name.$(OBJEXT) \
+	general.$(OBJEXT) hes_lagrangian.$(OBJEXT) \
+	hes_lu_det.$(OBJEXT) hes_minor_det.$(OBJEXT) \
+	hes_times_dir.$(OBJEXT) hessian.$(OBJEXT) \
+	independent.$(OBJEXT) integer.$(OBJEXT) interface2c.$(OBJEXT) \
 	interp_onetape.$(OBJEXT) interp_retape.$(OBJEXT) \
 	jac_lu_det.$(OBJEXT) jac_minor_det.$(OBJEXT) \
-	jacobian.$(OBJEXT) log10.$(OBJEXT) log1p.$(OBJEXT) \
-	log.$(OBJEXT) lu_ratio.$(OBJEXT) lu_vec_ad.$(OBJEXT) \
+	jacobian.$(OBJEXT) log.$(OBJEXT) log10.$(OBJEXT) \
+	log1p.$(OBJEXT) lu_ratio.$(OBJEXT) lu_vec_ad.$(OBJEXT) \
 	lu_vec_ad_ok.$(OBJEXT) mul.$(OBJEXT) mul_eq.$(OBJEXT) \
 	mul_level.$(OBJEXT) mul_level_ode.$(OBJEXT) \
 	near_equal_ext.$(OBJEXT) new_dynamic.$(OBJEXT) \
-	number_skip.$(OBJEXT) numeric_type.$(OBJEXT) \
-	num_limits.$(OBJEXT) ode_stiff.$(OBJEXT) taylor_ode.$(OBJEXT) \
-	opt_val_hes.$(OBJEXT) con_dyn_var.$(OBJEXT) pow.$(OBJEXT) \
-	print_for.$(OBJEXT) rev_checkpoint.$(OBJEXT) \
-	reverse_one.$(OBJEXT) reverse_three.$(OBJEXT) \
-	reverse_two.$(OBJEXT) rev_one.$(OBJEXT) rev_two.$(OBJEXT) \
-	seq_property.$(OBJEXT) sign.$(OBJEXT) sin.$(OBJEXT) \
-	sinh.$(OBJEXT) sqrt.$(OBJEXT) stack_machine.$(OBJEXT) \
-	sub.$(OBJEXT) sub_eq.$(OBJEXT) tan.$(OBJEXT) tanh.$(OBJEXT) \
-	tape_index.$(OBJEXT) unary_minus.$(OBJEXT) \
+	num_limits.$(OBJEXT) number_skip.$(OBJEXT) \
+	numeric_type.$(OBJEXT) ode_stiff.$(OBJEXT) \
+	opt_val_hes.$(OBJEXT) pow.$(OBJEXT) pow_nan.$(OBJEXT) \
+	print_for.$(OBJEXT) rev_checkpoint.$(OBJEXT) rev_one.$(OBJEXT) \
+	rev_two.$(OBJEXT) reverse_one.$(OBJEXT) \
+	reverse_three.$(OBJEXT) reverse_two.$(OBJEXT) sign.$(OBJEXT) \
+	sin.$(OBJEXT) sinh.$(OBJEXT) sqrt.$(OBJEXT) \
+	stack_machine.$(OBJEXT) sub.$(OBJEXT) sub_eq.$(OBJEXT) \
+	tan.$(OBJEXT) tanh.$(OBJEXT) tape_index.$(OBJEXT) \
+	taylor_ode.$(OBJEXT) unary_minus.$(OBJEXT) \
 	unary_plus.$(OBJEXT) value.$(OBJEXT) var2par.$(OBJEXT) \
 	vec_ad.$(OBJEXT)
 general_OBJECTS = $(am_general_OBJECTS)
@@ -209,7 +210,8 @@ am__depfiles_remade = ./$(DEPDIR)/abort_recording.Po \
 	./$(DEPDIR)/for_one.Po ./$(DEPDIR)/for_two.Po \
 	./$(DEPDIR)/forward.Po ./$(DEPDIR)/forward_dir.Po \
 	./$(DEPDIR)/forward_order.Po ./$(DEPDIR)/fun_assign.Po \
-	./$(DEPDIR)/fun_check.Po ./$(DEPDIR)/general.Po \
+	./$(DEPDIR)/fun_check.Po ./$(DEPDIR)/fun_property.Po \
+	./$(DEPDIR)/function_name.Po ./$(DEPDIR)/general.Po \
 	./$(DEPDIR)/hes_lagrangian.Po ./$(DEPDIR)/hes_lu_det.Po \
 	./$(DEPDIR)/hes_minor_det.Po ./$(DEPDIR)/hes_times_dir.Po \
 	./$(DEPDIR)/hessian.Po ./$(DEPDIR)/independent.Po \
@@ -227,11 +229,11 @@ am__depfiles_remade = ./$(DEPDIR)/abort_recording.Po \
 	./$(DEPDIR)/new_dynamic.Po ./$(DEPDIR)/num_limits.Po \
 	./$(DEPDIR)/number_skip.Po ./$(DEPDIR)/numeric_type.Po \
 	./$(DEPDIR)/ode_stiff.Po ./$(DEPDIR)/opt_val_hes.Po \
-	./$(DEPDIR)/pow.Po ./$(DEPDIR)/print_for.Po \
-	./$(DEPDIR)/rev_checkpoint.Po ./$(DEPDIR)/rev_one.Po \
-	./$(DEPDIR)/rev_two.Po ./$(DEPDIR)/reverse_one.Po \
-	./$(DEPDIR)/reverse_three.Po ./$(DEPDIR)/reverse_two.Po \
-	./$(DEPDIR)/seq_property.Po ./$(DEPDIR)/sign.Po \
+	./$(DEPDIR)/pow.Po ./$(DEPDIR)/pow_nan.Po \
+	./$(DEPDIR)/print_for.Po ./$(DEPDIR)/rev_checkpoint.Po \
+	./$(DEPDIR)/rev_one.Po ./$(DEPDIR)/rev_two.Po \
+	./$(DEPDIR)/reverse_one.Po ./$(DEPDIR)/reverse_three.Po \
+	./$(DEPDIR)/reverse_two.Po ./$(DEPDIR)/sign.Po \
 	./$(DEPDIR)/sin.Po ./$(DEPDIR)/sinh.Po ./$(DEPDIR)/sqrt.Po \
 	./$(DEPDIR)/stack_machine.Po ./$(DEPDIR)/sub.Po \
 	./$(DEPDIR)/sub_eq.Po ./$(DEPDIR)/tan.Po ./$(DEPDIR)/tanh.Po \
@@ -321,7 +323,7 @@ CXX_FLAGS = @CXX_FLAGS@
 CYGPATH_W = @CYGPATH_W@
 
 # -----------------------------------------------------------------------------
-# CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
+# 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.
@@ -404,7 +406,6 @@ 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@
@@ -459,6 +460,7 @@ pdfdir = @pdfdir@
 prefix = @prefix@
 program_transform_name = @program_transform_name@
 psdir = @psdir@
+runstatedir = @runstatedir@
 sbindir = @sbindir@
 sharedstatedir = @sharedstatedir@
 srcdir = @srcdir@
@@ -493,29 +495,29 @@ AM_CXXFLAGS = \
 #
 LDADD = $(ADOLC_LIB)
 #
+# BEGIN_SORT_THIS_LINE_PLUS_5
 general_SOURCES = \
 	$(ADOLC_SRC_FILES) \
 	$(EIGEN_SRC_FILES) \
 	\
 	abort_recording.cpp \
-	base2ad.cpp \
-	fabs.cpp \
 	acos.cpp \
 	acosh.cpp \
 	ad_assign.cpp \
 	ad_ctor.cpp \
-	add.cpp \
-	add_eq.cpp \
 	ad_fun.cpp \
 	ad_in_c.cpp \
 	ad_input.cpp \
 	ad_output.cpp \
+	add.cpp \
+	add_eq.cpp \
 	asin.cpp \
 	asinh.cpp \
-	atan2.cpp \
 	atan.cpp \
+	atan2.cpp \
 	atanh.cpp \
 	azmul.cpp \
+	base2ad.cpp \
 	base_alloc.hpp \
 	base_require.cpp \
 	bender_quad.cpp \
@@ -523,9 +525,10 @@ general_SOURCES = \
 	capacity_order.cpp \
 	change_param.cpp \
 	check_for_nan.cpp \
-	compare_change.cpp \
 	compare.cpp \
+	compare_change.cpp \
 	complex_poly.cpp \
+	con_dyn_var.cpp \
 	cond_exp.cpp \
 	cos.cpp \
 	cosh.cpp \
@@ -534,9 +537,9 @@ general_SOURCES = \
 	equal_op_seq.cpp \
 	erf.cpp \
 	erfc.cpp \
-	general.cpp \
 	exp.cpp \
 	expm1.cpp \
+	fabs.cpp \
 	for_one.cpp \
 	for_two.cpp \
 	forward.cpp \
@@ -544,11 +547,14 @@ general_SOURCES = \
 	forward_order.cpp \
 	fun_assign.cpp \
 	fun_check.cpp \
+	fun_property.cpp \
+	function_name.cpp \
+	general.cpp \
 	hes_lagrangian.cpp \
 	hes_lu_det.cpp \
 	hes_minor_det.cpp \
-	hessian.cpp \
 	hes_times_dir.cpp \
+	hessian.cpp \
 	independent.cpp \
 	integer.cpp \
 	interface2c.cpp\
@@ -557,9 +563,9 @@ general_SOURCES = \
 	jac_lu_det.cpp \
 	jac_minor_det.cpp \
 	jacobian.cpp \
+	log.cpp \
 	log10.cpp \
 	log1p.cpp \
-	log.cpp \
 	lu_ratio.cpp \
 	lu_vec_ad.cpp \
 	lu_vec_ad.hpp \
@@ -570,22 +576,20 @@ general_SOURCES = \
 	mul_level_ode.cpp \
 	near_equal_ext.cpp \
 	new_dynamic.cpp \
+	num_limits.cpp \
 	number_skip.cpp \
 	numeric_type.cpp \
-	num_limits.cpp \
 	ode_stiff.cpp \
-	taylor_ode.cpp \
 	opt_val_hes.cpp \
-	con_dyn_var.cpp \
 	pow.cpp \
+	pow_nan.cpp \
 	print_for.cpp \
 	rev_checkpoint.cpp \
+	rev_one.cpp \
+	rev_two.cpp \
 	reverse_one.cpp \
 	reverse_three.cpp \
 	reverse_two.cpp \
-	rev_one.cpp \
-	rev_two.cpp \
-	seq_property.cpp \
 	sign.cpp \
 	sin.cpp \
 	sinh.cpp \
@@ -596,6 +600,7 @@ general_SOURCES = \
 	tan.cpp \
 	tanh.cpp \
 	tape_index.cpp \
+	taylor_ode.cpp \
 	unary_minus.cpp \
 	unary_plus.cpp \
 	value.cpp \
@@ -697,6 +702,8 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/forward_order.Po@am__quote@ # am--include-marker
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fun_assign.Po@am__quote@ # am--include-marker
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fun_check.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fun_property.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/function_name.Po@am__quote@ # am--include-marker
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/general.Po@am__quote@ # am--include-marker
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hes_lagrangian.Po@am__quote@ # am--include-marker
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hes_lu_det.Po@am__quote@ # am--include-marker
@@ -731,6 +738,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ode_stiff.Po@am__quote@ # am--include-marker
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/opt_val_hes.Po@am__quote@ # am--include-marker
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pow.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pow_nan.Po@am__quote@ # am--include-marker
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/print_for.Po@am__quote@ # am--include-marker
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rev_checkpoint.Po@am__quote@ # am--include-marker
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rev_one.Po@am__quote@ # am--include-marker
@@ -738,7 +746,6 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/reverse_one.Po@am__quote@ # am--include-marker
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/reverse_three.Po@am__quote@ # am--include-marker
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/reverse_two.Po@am__quote@ # am--include-marker
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/seq_property.Po@am__quote@ # am--include-marker
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sign.Po@am__quote@ # am--include-marker
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sin.Po@am__quote@ # am--include-marker
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sinh.Po@am__quote@ # am--include-marker
@@ -951,6 +958,8 @@ distclean: distclean-am
 	-rm -f ./$(DEPDIR)/forward_order.Po
 	-rm -f ./$(DEPDIR)/fun_assign.Po
 	-rm -f ./$(DEPDIR)/fun_check.Po
+	-rm -f ./$(DEPDIR)/fun_property.Po
+	-rm -f ./$(DEPDIR)/function_name.Po
 	-rm -f ./$(DEPDIR)/general.Po
 	-rm -f ./$(DEPDIR)/hes_lagrangian.Po
 	-rm -f ./$(DEPDIR)/hes_lu_det.Po
@@ -985,6 +994,7 @@ distclean: distclean-am
 	-rm -f ./$(DEPDIR)/ode_stiff.Po
 	-rm -f ./$(DEPDIR)/opt_val_hes.Po
 	-rm -f ./$(DEPDIR)/pow.Po
+	-rm -f ./$(DEPDIR)/pow_nan.Po
 	-rm -f ./$(DEPDIR)/print_for.Po
 	-rm -f ./$(DEPDIR)/rev_checkpoint.Po
 	-rm -f ./$(DEPDIR)/rev_one.Po
@@ -992,7 +1002,6 @@ distclean: distclean-am
 	-rm -f ./$(DEPDIR)/reverse_one.Po
 	-rm -f ./$(DEPDIR)/reverse_three.Po
 	-rm -f ./$(DEPDIR)/reverse_two.Po
-	-rm -f ./$(DEPDIR)/seq_property.Po
 	-rm -f ./$(DEPDIR)/sign.Po
 	-rm -f ./$(DEPDIR)/sin.Po
 	-rm -f ./$(DEPDIR)/sinh.Po
@@ -1102,6 +1111,8 @@ maintainer-clean: maintainer-clean-am
 	-rm -f ./$(DEPDIR)/forward_order.Po
 	-rm -f ./$(DEPDIR)/fun_assign.Po
 	-rm -f ./$(DEPDIR)/fun_check.Po
+	-rm -f ./$(DEPDIR)/fun_property.Po
+	-rm -f ./$(DEPDIR)/function_name.Po
 	-rm -f ./$(DEPDIR)/general.Po
 	-rm -f ./$(DEPDIR)/hes_lagrangian.Po
 	-rm -f ./$(DEPDIR)/hes_lu_det.Po
@@ -1136,6 +1147,7 @@ maintainer-clean: maintainer-clean-am
 	-rm -f ./$(DEPDIR)/ode_stiff.Po
 	-rm -f ./$(DEPDIR)/opt_val_hes.Po
 	-rm -f ./$(DEPDIR)/pow.Po
+	-rm -f ./$(DEPDIR)/pow_nan.Po
 	-rm -f ./$(DEPDIR)/print_for.Po
 	-rm -f ./$(DEPDIR)/rev_checkpoint.Po
 	-rm -f ./$(DEPDIR)/rev_one.Po
@@ -1143,7 +1155,6 @@ maintainer-clean: maintainer-clean-am
 	-rm -f ./$(DEPDIR)/reverse_one.Po
 	-rm -f ./$(DEPDIR)/reverse_three.Po
 	-rm -f ./$(DEPDIR)/reverse_two.Po
-	-rm -f ./$(DEPDIR)/seq_property.Po
 	-rm -f ./$(DEPDIR)/sign.Po
 	-rm -f ./$(DEPDIR)/sin.Po
 	-rm -f ./$(DEPDIR)/sinh.Po
@@ -1194,6 +1205,7 @@ uninstall-am:
 
 .PRECIOUS: makefile
 
+# END_SORT_THIS_LINE_MINUS_2
 
 test: check
 	./general
diff --git a/example/general/pow_nan.cpp b/example/general/pow_nan.cpp
new file mode 100644
index 000000000..c92ead512
--- /dev/null
+++ b/example/general/pow_nan.cpp
@@ -0,0 +1,91 @@
+/* --------------------------------------------------------------------------
+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 pow_nan.cpp$$
+$spell
+$$
+
+$section pow: Nan in Result of Pow Function: Example and Test$$
+
+$head Purpose$$
+The $cref%pow(x, y)%pow%$$ function will work when $latex x < 0$$ and
+$latex y$$  is a parameter. It will often generate nan or infinity when
+$latex x < 0$$ and one tries to compute a derivatives
+(even if $latex y$$ is a positive integer).
+This is because the derivative of the log is $latex 1 / x$$
+and the power function uses the representation
+$latex \[
+    \R{pow}(x, y) = \exp [ y \cdot \log(x) ]
+\] $$
+
+$head Problem$$
+There is a problem with this representation when $latex y$$ is a parameter
+and $latex x = 0$$. For example,
+when $latex x = 0$$ and $latex y = 1$$, it returns zero for the derivative,
+but the actual derivative w.r.t $latex x$$ is one.
+
+$srcthisfile%0%// BEGIN C++%// END C++%1%$$
+
+$end
+*/
+// BEGIN C++
+# include <cppad/cppad.hpp>
+# include <cmath>
+
+bool pow_nan(void)
+{   bool ok = true;
+
+    using std::cout;
+    using CppAD::AD;
+    using CppAD::vector;
+    //
+    vector<double>       x(2), y(2), dx(2), dy(2), ddx(2), ddy(2);
+    vector< AD<double> > ax(2), ay(2);
+    //
+    // variable vector
+    ax[0] = x[0]  = -1.0;
+    ax[1] = x[1] = 2.0;
+    //
+    CppAD::Independent(ax);
+    //
+    ay[0] = pow( ax[0], ax[1] );
+    ay[1] = pow( ax[0], 2.0 );
+    //
+    CppAD::ADFun<double> f(ax, ay);
+    //
+    // check_for_nan is set false so it does not generate an assert
+    // when compiling with debugging
+    f.check_for_nan(false);
+    //
+    // Zero order forward does not generate nan
+    y  = f.Forward(0, x);
+    ok &= y[0] == 1.0;
+    ok &= y[1] == 1.0;
+    //
+    // First order forward generates a nan
+    dx[0] = 1.0;
+    dx[1] = 1.0;
+    dy = f.Forward(1, dx);
+    ok &= std::isnan( dy[0] );
+    ok &= dy[1] == -2.0;
+    //
+    // Second order Taylor coefficient is 1/2 times second derivative
+    ddx[0] = 0.0;
+    ddx[1] = 0.0;
+    ddy = f.Forward(2, ddx);
+    ok &= std::isnan( ddy[0] );
+    ok &= ddy[1] == 1.0;
+    //
+    return ok;
+}
+// END C++
diff --git a/example/general/var2par.cpp b/example/general/var2par.cpp
index 82a377018..84f2f25d9 100644
--- a/example/general/var2par.cpp
+++ b/example/general/var2par.cpp
@@ -1,5 +1,5 @@
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
+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.
@@ -17,7 +17,7 @@ $spell
     Cpp
 $$
 
-$section Convert an AD Variable to a Parameter: Example and Test$$
+$section Convert a Variable or Dynamic Parameter a Constant: Example and Test$$
 
 
 $srcthisfile%0%// BEGIN C++%// END C++%1%$$
@@ -35,40 +35,53 @@ bool Var2Par(void)
     using CppAD::Value;
     using CppAD::Var2Par;
 
-    // domain space vector
-    size_t n = 2;
-    CPPAD_TESTVECTOR(AD<double>) x(n);
-    x[0] = 3.;
-    x[1] = 4.;
+    // independent variables
+    size_t nx = 2;
+    CPPAD_TESTVECTOR(AD<double>) ax(nx);
+    ax[0] = 3.;
+    ax[1] = 4.;
 
-    // declare independent variables and start tape recording
-    CppAD::Independent(x);
+    // independent dynamic paramers
+    size_t np = 1;
+    CPPAD_TESTVECTOR(AD<double>) ap(np);
+    ap[0] = 5.;
 
-    // range space vector
-    size_t m = 1;
-    CPPAD_TESTVECTOR(AD<double>) y(m);
-    y[0] = - x[1] * Var2Par(x[0]);    // same as y[0] = -x[1] * 3.;
+    // declare independent variables and dynamic parameters
+    CppAD::Independent(ax, ap);
 
-    // cannot call Value(x[j]) or Value(y[0]) here (currently variables)
-    ok &= ( Value( Var2Par(x[0]) ) == 3. );
-    ok &= ( Value( Var2Par(x[1]) ) == 4. );
-    ok &= ( Value( Var2Par(y[0]) ) == -12. );
+    // range space vector
+    size_t ny = 2;
+    CPPAD_TESTVECTOR(AD<double>) ay(ny);
+    ay[0] = - ax[1] * Var2Par(ax[0]);    // same as ay[0] = -ax[1] * 3.;
+    ay[1] = - ax[1] * Var2Par(ap[0]);    // same as ay[1] = -ax[1] * 5.;
+
+    // Must convert these objects to constants before calling Value
+    ok &= ( Value( Var2Par(ax[0]) ) == 3. );
+    ok &= ( Value( Var2Par(ax[1]) ) == 4. );
+    ok &= ( Value( Var2Par(ap[0]) ) == 5. );
+    ok &= ( Value( Var2Par(ay[0]) ) == -12. );
+    ok &= ( Value( Var2Par(ay[1]) ) == -20. );
 
     // create f: x -> y and stop tape recording
-    CppAD::ADFun<double> f(x, y);
-
-    // can call Value(x[j]) or Value(y[0]) here (currently parameters)
-    ok &= (Value(x[0]) ==  3.);
-    ok &= (Value(x[1]) ==  4.);
-    ok &= (Value(y[0]) == -12.);
-
-    // evaluate derivative of y w.r.t x
-    CPPAD_TESTVECTOR(double) w(m);
-    CPPAD_TESTVECTOR(double) dw(n);
-    w[0] = 1.;
-    dw   = f.Reverse(1, w);
-    ok  &= (dw[0] == 0.);  // derivative of y[0] w.r.t x[0] is zero
-    ok  &= (dw[1] == -3.); // derivative of y[0] w.r.t x[1] is 3
+    CppAD::ADFun<double> f(ax, ay);
+
+    // All AD object are currently constants
+    ok &= (Value(ax[0]) ==  3.);
+    ok &= (Value(ax[1]) ==  4.);
+    ok &= (Value(ap[0]) ==  5.);
+    ok &= (Value(ay[0]) == -12.);
+    ok &= (Value(ay[1]) == -20.);
+
+    // evaluate zero order forward mode
+    // (note that the only real variable in this recording is x[1])
+    CPPAD_TESTVECTOR(double) x(nx), p(np), y(ny);
+    x[0] = 6.;
+    x[1] = 7.;
+    p[0] = 8.;
+    f.new_dynamic(p);
+    y    = f.Forward(0, x);
+    ok  &= y[0] == - x[1] * 3.0;
+    ok  &= y[1] == - x[1] * 5.0;
 
     return ok;
 }
diff --git a/example/get_started/makefile.in b/example/get_started/makefile.in
index a3c446cc9..2bc8047ac 100644
--- a/example/get_started/makefile.in
+++ b/example/get_started/makefile.in
@@ -270,7 +270,6 @@ 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@
@@ -325,6 +324,7 @@ pdfdir = @pdfdir@
 prefix = @prefix@
 program_transform_name = @program_transform_name@
 psdir = @psdir@
+runstatedir = @runstatedir@
 sbindir = @sbindir@
 sharedstatedir = @sharedstatedir@
 srcdir = @srcdir@
diff --git a/example/graph/CMakeLists.txt b/example/graph/CMakeLists.txt
index 8e9274707..cd2d80a66 100644
--- a/example/graph/CMakeLists.txt
+++ b/example/graph/CMakeLists.txt
@@ -1,5 +1,5 @@
 # -----------------------------------------------------------------------------
-# CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 Bradley M. Bell
+# CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
 #
 # CppAD is distributed under the terms of the
 #              Eclipse Public License Version 2.0.
@@ -13,6 +13,7 @@
 # BEGIN_SORT_THIS_LINE_PLUS_2
 SET(source_list
     add_op.cpp
+    atom4_op.cpp
     atom_op.cpp
     azmul_op.cpp
     cexp_op.cpp
@@ -22,6 +23,7 @@ SET(source_list
     graph.cpp
     mul_op.cpp
     pow_op.cpp
+    print_graph.cpp
     print_op.cpp
     sub_op.cpp
     sum_op.cpp
diff --git a/example/graph/atom4_op.cpp b/example/graph/atom4_op.cpp
new file mode 100644
index 000000000..55a51f4cc
--- /dev/null
+++ b/example/graph/atom4_op.cpp
@@ -0,0 +1,161 @@
+/* --------------------------------------------------------------------------
+CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
+
+CppAD is distributed under the terms of the
+             Eclipse Public License Version 2.0.
+
+This Source Code may also be made available under the following
+Secondary License when the conditions 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 graph_atom4_op.cpp$$
+$spell
+    atom
+    Json
+$$
+
+$section C++ AD Graph Atomic Four Functions: Example and Test$$
+
+$head Source Code$$
+$srcthisfile%0%// BEGIN C++%// END C++%1%$$
+
+$end
+*/
+// BEGIN C++
+# include <cppad/cppad.hpp>
+
+namespace {
+    class atomic_int_pow : public CppAD::atomic_four<double> {
+    public:
+        atomic_int_pow(void) : CppAD::atomic_four<double>("int_pow")
+        { }
+    private:
+        // for_type
+        bool for_type(
+            size_t                                     call_id     ,
+            const CppAD::vector<CppAD::ad_type_enum>&  type_x      ,
+            CppAD::vector<CppAD::ad_type_enum>&        type_y      ) override
+        {   type_y[0] = type_x[0];
+            return true;
+        }
+        // forward
+        bool forward(
+            size_t                              call_id      ,
+            const CppAD::vector<bool>&          select_y     ,
+            size_t                              order_low    ,
+            size_t                              order_up     ,
+            const CppAD::vector<double>&        taylor_x     ,
+            CppAD::vector<double>&              taylor_y     ) override
+        {
+            // order_up
+            if( order_up != 0 )
+                return false;
+            //
+            // taylor_y
+            taylor_y[0] = 1.0;
+            for(size_t i = 0; i < call_id; ++i)
+                taylor_y[0] *= taylor_x[0];
+            //
+            return true;
+        }
+    };
+}
+
+bool atom4_op(void)
+{   bool ok = true;
+    using std::string;
+    //
+    // reciprocal
+    atomic_int_pow int_pow;
+    // -----------------------------------------------------------------------
+    //
+    // This function has an atomic function operator with name int_pow
+    // node_1 : p[0]
+    // node_2 : x[0]
+    // node_3 : p[0] + x[0]
+    // node_4 : int_pow( p[0] + x[0] )
+    // y[0]   = ( p[0] + x[0] ) ** call_id
+    //
+    // call_id
+    size_t call_id = 2;
+    //
+    // C++ graph object
+    CppAD::cpp_graph graph_obj;
+    graph_obj.initialize();
+    //
+    // operator being used
+    CppAD::graph::graph_op_enum op_enum;
+    //
+    graph_obj.function_name_set("g(p; x)");
+    graph_obj.n_dynamic_ind_set(1);
+    graph_obj.n_variable_ind_set(1);
+    //
+    // node_3 : p[0] + x[0]
+    op_enum = CppAD::graph::add_graph_op;
+    graph_obj.operator_vec_push_back(op_enum);
+    graph_obj.operator_arg_push_back(1);
+    graph_obj.operator_arg_push_back(2);
+    //
+    // node_4 : f( p[0] + x[0] )
+    //
+    // name_index, n_result, n_arg come before first_node
+    size_t name_index = graph_obj.atomic_name_vec_size();
+    graph_obj.atomic_name_vec_push_back("int_pow");
+    //
+    op_enum = CppAD::graph::atom4_graph_op;
+    graph_obj.operator_vec_push_back(op_enum);
+    graph_obj.operator_arg_push_back(name_index);  // name_index
+    graph_obj.operator_arg_push_back(call_id);     // call_id
+    graph_obj.operator_arg_push_back(1);           // n_result
+    graph_obj.operator_arg_push_back(1);           // n_node_arg
+    graph_obj.operator_arg_push_back(3);           // first and last node arg
+    //
+    // y[0]  = int_pow( p[0] + x[0] ) = ( p[0] + x[0] ) ** call_id
+    graph_obj.dependent_vec_push_back(4);
+    // ------------------------------------------------------------------------
+    CppAD::ADFun<double> g;
+    g.from_graph(graph_obj);
+    // ------------------------------------------------------------------------
+    ok &= g.Domain() == 1;
+    ok &= g.Range() == 1;
+    ok &= g.size_dyn_ind() == 1;
+    //
+    // set p in g(p; x)
+    CPPAD_TESTVECTOR(double) p(1);
+    p[0] = 2.0;
+    g.new_dynamic(p);
+    //
+    // evalute g(p; x)
+    CPPAD_TESTVECTOR(double) x(1), y(1);
+    x[0] = 3.0;
+    y    = g.Forward(0, x);
+    //
+    // check value
+    double eps99 = 99.0 * std::numeric_limits<double>::epsilon();
+    double check = std::pow( p[0] + x[0], double(call_id) );
+    ok &= CppAD::NearEqual(y[0], check, eps99, eps99);
+    // ------------------------------------------------------------------------
+    g.to_graph(graph_obj);
+    g.from_graph(graph_obj);
+    // ------------------------------------------------------------------------
+    ok &= g.Domain() == 1;
+    ok &= g.Range() == 1;
+    ok &= g.size_dyn_ind() == 1;
+    //
+    // set p in g(p; x)
+    p[0] = 4.0;
+    g.new_dynamic(p);
+    //
+    // evalute g(p; x)
+    x[0] = 5.0;
+    y    = g.Forward(0, x);
+    //
+    // check value
+    check = std::pow( p[0] + x[0], double(call_id) );
+    ok &= CppAD::NearEqual(y[0], check, eps99, eps99);
+    // ------------------------------------------------------------------------
+    return ok;
+}
+// END C++
diff --git a/example/graph/atom_op.cpp b/example/graph/atom_op.cpp
index ca19f5620..450da8674 100644
--- a/example/graph/atom_op.cpp
+++ b/example/graph/atom_op.cpp
@@ -1,5 +1,5 @@
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
+CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
 
 CppAD is distributed under the terms of the
              Eclipse Public License Version 2.0.
@@ -16,7 +16,7 @@ $spell
     Json
 $$
 
-$section C++ AD Graph Atomic Functions: Example and Test$$
+$section C++ AD Graph Atomic Three Functions: Example and Test$$
 
 $head Source Code$$
 $srcthisfile%0%// BEGIN C++%// END C++%1%$$
diff --git a/example/graph/graph.cpp b/example/graph/graph.cpp
index 3481a48a1..322b64ac5 100644
--- a/example/graph/graph.cpp
+++ b/example/graph/graph.cpp
@@ -1,5 +1,5 @@
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 Bradley M. Bell
+CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
 
 CppAD is distributed under the terms of the
              Eclipse Public License Version 2.0.
@@ -28,6 +28,7 @@ in the Eclipse Public License, Version 2.0 are satisfied:
 // BEGIN_SORT_THIS_LINE_PLUS_2
 // external compiled tests
 extern bool add_op(void);
+extern bool atom4_op(void);
 extern bool atom_op(void);
 extern bool azmul_op(void);
 extern bool cexp_op(void);
@@ -36,6 +37,7 @@ extern bool discrete_op(void);
 extern bool div_op(void);
 extern bool mul_op(void);
 extern bool pow_op(void);
+extern bool print_graph(void);
 extern bool print_op(void);
 extern bool sub_op(void);
 extern bool sum_op(void);
@@ -45,7 +47,7 @@ extern bool unary_op(void);
 
 // main program that runs all the tests
 int main(void)
-{   std::string group = "test_more/graph";
+{   std::string group = "example/graph";
     size_t      width = 20;
     CppAD::test_boolofvoid Run(group, width);
 
@@ -54,14 +56,16 @@ int main(void)
     // BEGIN_SORT_THIS_LINE_PLUS_2
     // external compiled tests
     Run( add_op,               "add_op"          );
+    Run( atom4_op,             "atom4_op"        );
     Run( atom_op,              "atom_op"         );
     Run( azmul_op,             "azmul_op"        );
     Run( cexp_op,              "cexp_op"         );
     Run( comp_op,              "comp_op"         );
-    Run( div_op,               "div_op"          );
     Run( discrete_op,          "discrete_op"     );
+    Run( div_op,               "div_op"          );
     Run( mul_op,               "mul_op"          );
     Run( pow_op,               "pow_op"          );
+    Run( print_graph,          "print_graph"     );
     Run( print_op,             "print_op"        );
     Run( sub_op,               "sub_op"          );
     Run( sum_op,               "sum_op"          );
diff --git a/example/graph/print_graph.cpp b/example/graph/print_graph.cpp
new file mode 100644
index 000000000..a6f129c63
--- /dev/null
+++ b/example/graph/print_graph.cpp
@@ -0,0 +1,85 @@
+/* --------------------------------------------------------------------------
+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 print_graph.cpp$$
+$spell
+    Json
+$$
+
+$section Print a C++ AD Graph: Example and Test$$
+
+$head Source Code$$
+$srcthisfile%0%// BEGIN C++%// END C++%1%$$
+
+$end
+*/
+// BEGIN C++
+# include <cppad/cppad.hpp>
+
+bool print_graph(void)
+{   bool ok = true;
+    using std::string;
+    //
+    // AD graph example
+    // node_1 : p[0]
+    // node_2 : p[1]
+    // node_3 : x[0]
+    // node_4 : p[0] + p[1]
+    // node_5 : x[0] + ( p[0] + p[1] )
+    // y[0]   = x[0] + ( p[0] + p[1] )
+    //
+    // C++ graph object
+    CppAD::cpp_graph graph_obj;
+    //
+    // operator being used
+    CppAD::graph::graph_op_enum op_enum;
+    //
+    // set scalars
+    graph_obj.function_name_set("print_graph example");
+    size_t n_dynamic_ind = 2;
+    graph_obj.n_dynamic_ind_set(n_dynamic_ind);
+    size_t n_variable_ind = 1;
+    graph_obj.n_variable_ind_set(n_variable_ind);
+    //
+    // node_4 : p[0] + p[1]
+    op_enum = CppAD::graph::add_graph_op;
+    graph_obj.operator_vec_push_back(op_enum);
+    graph_obj.operator_arg_push_back(1);
+    graph_obj.operator_arg_push_back(2);
+    //
+    // node_5 : x[0] + ( p[0] + p[1] )
+    graph_obj.operator_vec_push_back(op_enum);
+    graph_obj.operator_arg_push_back(3);
+    graph_obj.operator_arg_push_back(4);
+    //
+    // y[0]   = x[0] + ( p[0] + p[1] )
+    graph_obj.dependent_vec_push_back(5);
+    //
+    // get output of print command
+    std::stringstream os;
+    graph_obj.print(os);
+    //
+    std::string check =
+        "print_graph example\n"
+        "          1      p[0]\n"
+        "          2      p[1]\n"
+        "          3      x[0]\n"
+        "          4       add    1    2\n"
+        "          5       add    3    4\n"
+        "y nodes = 5\n"
+    ;
+    std::string str = os.str();
+    ok &= str == check;
+    //
+    return ok;
+}
+// END C++
diff --git a/example/ipopt_solve/makefile.in b/example/ipopt_solve/makefile.in
index 7d44a1f2e..27176fad9 100644
--- a/example/ipopt_solve/makefile.in
+++ b/example/ipopt_solve/makefile.in
@@ -276,7 +276,6 @@ 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@
@@ -331,6 +330,7 @@ pdfdir = @pdfdir@
 prefix = @prefix@
 program_transform_name = @program_transform_name@
 psdir = @psdir@
+runstatedir = @runstatedir@
 sbindir = @sbindir@
 sharedstatedir = @sharedstatedir@
 srcdir = @srcdir@
diff --git a/example/json/CMakeLists.txt b/example/json/CMakeLists.txt
index acb48fb52..47bffb4f0 100644
--- a/example/json/CMakeLists.txt
+++ b/example/json/CMakeLists.txt
@@ -1,5 +1,5 @@
 # -----------------------------------------------------------------------------
-# CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
+# CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
 #
 # CppAD is distributed under the terms of the
 #              Eclipse Public License Version 2.0.
@@ -13,6 +13,7 @@
 # BEGIN_SORT_THIS_LINE_PLUS_2
 SET(source_list
     add_op.cpp
+    atom4_op.cpp
     atom_op.cpp
     azmul_op.cpp
     cexp_op.cpp
diff --git a/example/json/atom4_op.cpp b/example/json/atom4_op.cpp
new file mode 100644
index 000000000..ac3412087
--- /dev/null
+++ b/example/json/atom4_op.cpp
@@ -0,0 +1,155 @@
+/* --------------------------------------------------------------------------
+CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
+
+CppAD is distributed under the terms of the
+             Eclipse Public License Version 2.0.
+
+This Source Code may also be made available under the following
+Secondary License when the conditions 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_atom4_op.cpp$$
+$spell
+    Json
+$$
+
+$section Json Atomic Function Operator: Example and Test$$
+
+$head Source Code$$
+$srcthisfile%0%// BEGIN C++%// END C++%1%$$
+
+$end
+*/
+// BEGIN C++
+# include <cppad/cppad.hpp>
+
+namespace {
+    class atomic_avg : public CppAD::atomic_four<double> {
+    public:
+        atomic_avg(void) : CppAD::atomic_four<double>("avg")
+        { }
+    private:
+        // for_type
+        bool for_type(
+            size_t                                     call_id     ,
+            const CppAD::vector<CppAD::ad_type_enum>&  type_x      ,
+            CppAD::vector<CppAD::ad_type_enum>&        type_y      ) override
+        {   type_y[0] = type_x[0];
+            return true;
+        }
+        // forward
+        bool forward(
+            size_t                              call_id      ,
+            const CppAD::vector<bool>&          select_y     ,
+            size_t                              order_low    ,
+            size_t                              order_up     ,
+            const CppAD::vector<double>&        taylor_x     ,
+            CppAD::vector<double>&              taylor_y     ) override
+        {
+            // order_up
+            if( order_up != 0 )
+                return false;
+            //
+            // n
+            size_t n = taylor_x.size();
+            if( n == 0 )
+                return false;
+            //
+            // taylor_y
+            double sum = 0.0;
+            for(size_t j = 0; j < n; ++j)
+                sum += taylor_x[j];
+            taylor_y[0] = sum / double(n);
+            //
+            return true;
+        }
+    };
+}
+
+bool atom4_op(void)
+{   bool ok = true;
+    using CppAD::vector;
+    using CppAD::AD;
+    //
+    // avg
+    atomic_avg avg;
+    //
+    // -----------------------------------------------------------------------
+    // g (p; x) = avg( [ p_0 * x_0, p_0 * x_1 ] )
+    //          = p_0 * (x_0 + x_1) / 2
+    //
+    // This function has an atomic function operator with name avg
+    // node_1 : p[0]
+    // node_2 : x[0]
+    // node_3 : x[1]
+    // node_4 : p[0] * x[0]
+    // node_5 : p[0] * x[1]
+    // node_6 : avg( p[0] * x[0], p[0] * x[1] )
+    // y[0]   = p[0] * ( x[0] + x[1] ) / 2
+    std::string json =
+        "{\n"
+        "   'function_name'  : 'g(p; x)',\n"
+        "   'op_define_vec'  : [ 2, [\n"
+        "       { 'op_code':1, 'name':'atom4'          } ,\n"
+        "       { 'op_code':2, 'name':'mul', 'n_arg':2 } ]\n"
+        "   ],\n"
+        "   'n_dynamic_ind'  : 1,\n"              // p[0]
+        "   'n_variable_ind' : 2,\n"              // x[0], x[1]
+        "   'constant_vec'   : [ 0, [ ] ],\n"
+        "   'op_usage_vec'   : [ 3, [\n"
+        "       [ 2, 1, 2 ]                      ,\n" // p[0] * x[0]
+        "       [ 2, 1, 3 ]                      ,\n" // p[0] * x[1]
+                // avg( p[0] * x[0], p[0] * x[1] )
+        "       [ 1, 'avg', 0, 1, 2, [ 4, 5 ] ]  ]\n"
+        "   ],\n"
+        "   'dependent_vec' : [ 1, [6] ] \n"
+        "}\n";
+    // Convert the single quote to double quote
+    for(size_t i = 0; i < json.size(); ++i)
+        if( json[i] == '\'' ) json[i] = '"';
+    // ------------------------------------------------------------------------
+    CppAD::ADFun<double> g;
+    g.from_json(json);
+    // ------------------------------------------------------------------------
+    ok &= g.Domain() == 2;
+    ok &= g.Range() == 1;
+    ok &= g.size_dyn_ind() == 1;
+    //
+    // set p in g(p; x)
+    vector<double> p(1);
+    p[0] = 2.0;
+    g.new_dynamic(p);
+    //
+    // evalute g(p; x)
+    vector<double> x(2), y(1);
+    x[0] = 3.0;
+    x[1] = 4.0;
+    y    = g.Forward(0, x);
+    //
+    // check value
+    ok &= y[0] == p[0] * (x[0] + x[1]) / 2.0;
+    // ------------------------------------------------------------------------
+    json = g.to_json();
+    g.from_json(json);
+    // ------------------------------------------------------------------------
+    ok &= g.Domain() == 2;
+    ok &= g.Range() == 1;
+    ok &= g.size_dyn_ind() == 1;
+    //
+    // set p in g(p; x)
+    p[0] = 5.0;
+    g.new_dynamic(p);
+    //
+    // evalute g(p; x)
+    x[0] = 6.0;
+    x[1] = 7.0;
+    y    = g.Forward(0, x);
+    //
+    // check value
+    ok &= y[0] == p[0] * (x[0] + x[1]) / 2.0;
+    // ------------------------------------------------------------------------
+    return ok;
+}
+// END C++
diff --git a/example/json/atom_op.cpp b/example/json/atom_op.cpp
index 5e5779843..2710aa775 100644
--- a/example/json/atom_op.cpp
+++ b/example/json/atom_op.cpp
@@ -1,5 +1,5 @@
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
+CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
 
 CppAD is distributed under the terms of the
              Eclipse Public License Version 2.0.
@@ -16,7 +16,7 @@ $spell
     Json
 $$
 
-$section Json Atomic Function Operator: Example and Test$$
+$section Json Atomic Function Three Operator: Example and Test$$
 
 $head Source Code$$
 $srcthisfile%0%// BEGIN C++%// END C++%1%$$
diff --git a/example/json/json.cpp b/example/json/json.cpp
index ba9a57ab5..5f6404789 100644
--- a/example/json/json.cpp
+++ b/example/json/json.cpp
@@ -1,5 +1,5 @@
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
+CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
 
 CppAD is distributed under the terms of the
              Eclipse Public License Version 2.0.
@@ -28,6 +28,7 @@ in the Eclipse Public License, Version 2.0 are satisfied:
 // BEGIN_SORT_THIS_LINE_PLUS_2
 // external compiled tests
 extern bool add_op(void);
+extern bool atom4_op(void);
 extern bool atom_op(void);
 extern bool azmul_op(void);
 extern bool cexp_op(void);
@@ -57,7 +58,7 @@ int main(void)
     // BEGIN_SORT_THIS_LINE_PLUS_2
     // external compiled tests
     Run( add_op,               "add_op"          );
-    Run( atom_op,              "atom_op"         );
+    Run( atom4_op,             "atom4_op"        );
     Run( azmul_op,             "azmul_op"        );
     Run( cexp_op,              "cexp_op"         );
     Run( comp_op,              "comp_op"         );
diff --git a/example/multi_thread/CMakeLists.txt b/example/multi_thread/CMakeLists.txt
index ae5b9d650..7531a94a6 100644
--- a/example/multi_thread/CMakeLists.txt
+++ b/example/multi_thread/CMakeLists.txt
@@ -1,5 +1,5 @@
 # -----------------------------------------------------------------------------
-# CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-18 Bradley M. Bell
+# 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.
@@ -55,10 +55,7 @@ int main(void)
     return 0;
 }"
     )
-    IF( DEFINED boost_multi_thread_ok )
-        MESSAGE( ERROR "boost_multi_thread_ok is defined before expected" )
-    ENDIF( DEFINED boost_multi_thread_ok )
-    CHECK_CXX_SOURCE_RUNS("${source}" boost_multi_thread_ok )
+    compile_source_test("${source}" boost_multi_thread_ok )
     #
     IF( boost_multi_thread_ok )
         ADD_SUBDIRECTORY(bthread)
@@ -76,7 +73,7 @@ IF( NOT( "${check_example_multi_thread_depends}" STREQUAL "" ) )
     MESSAGE(STATUS "make check_example_multi_thread: available")
     #
     # Change check depends in parent environment
-    add_to_list(check_depends check_example_multi_thread)
-    SET(check_depends "${check_depends}" PARENT_SCOPE)
+    add_to_list(check_example_depends check_example_multi_thread)
+    SET(check_example_depends "${check_example_depends}" PARENT_SCOPE)
     #
 ENDIF( NOT( "${check_example_multi_thread_depends}" STREQUAL "" ) )
diff --git a/example/multi_thread/bthread/CMakeLists.txt b/example/multi_thread/bthread/CMakeLists.txt
index 207bd52b4..3c800c1c7 100644
--- a/example/multi_thread/bthread/CMakeLists.txt
+++ b/example/multi_thread/bthread/CMakeLists.txt
@@ -1,5 +1,5 @@
 # -----------------------------------------------------------------------------
-# CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 Bradley M. Bell
+# 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.
@@ -19,7 +19,6 @@ INCLUDE_DIRECTORIES( ${CMAKE_CURRENT_SOURCE_DIR}/.. )
 #                 source1 source2 ... sourceN
 # )
 SET(source_list ../thread_test.cpp
-    ${CMAKE_SOURCE_DIR}/speed/src/microsoft_timer.cpp
     ../team_example.cpp
     ../harmonic.cpp
     ../multi_atomic_two.cpp
diff --git a/example/multi_thread/makefile.in b/example/multi_thread/makefile.in
index 98fc94d48..70a0da07e 100644
--- a/example/multi_thread/makefile.in
+++ b/example/multi_thread/makefile.in
@@ -326,7 +326,6 @@ 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@
@@ -381,6 +380,7 @@ pdfdir = @pdfdir@
 prefix = @prefix@
 program_transform_name = @program_transform_name@
 psdir = @psdir@
+runstatedir = @runstatedir@
 sbindir = @sbindir@
 sharedstatedir = @sharedstatedir@
 srcdir = @srcdir@
diff --git a/example/multi_thread/multi_atomic_three.cpp b/example/multi_thread/multi_atomic_three.cpp
index 1a18467b8..c2b4e3341 100644
--- a/example/multi_thread/multi_atomic_three.cpp
+++ b/example/multi_thread/multi_atomic_three.cpp
@@ -1,5 +1,5 @@
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
+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.
@@ -102,10 +102,10 @@ public:
     { }
 private:
     // for_type
-    virtual bool for_type(
+    bool for_type(
         const vector<double>&        parameter_u ,
         const vector<ad_type_enum>&  type_u      ,
-        vector<ad_type_enum>&        type_y      )
+        vector<ad_type_enum>&        type_y      ) override
     {   bool ok = parameter_u.size() == 3;
         ok     &= type_u.size() == 3;
         ok     &= type_y.size() == 1;
@@ -120,14 +120,14 @@ private:
         return true;
     }
     // forward
-    virtual bool forward(
+    bool forward(
         const vector<double>&        parameter_u ,
         const vector<ad_type_enum>&  type_u      ,
         size_t                       need_y      ,
         size_t                       order_low   ,
         size_t                       order_up    ,
         const vector<double>&        taylor_u    ,
-        vector<double>&              taylor_y    )
+        vector<double>&              taylor_y    ) override
     {
 # ifndef NDEBUG
         size_t n = taylor_u.size() / (order_up + 1);
diff --git a/example/multi_thread/multi_atomic_two.cpp b/example/multi_thread/multi_atomic_two.cpp
index 03c171e5d..ffa6f6552 100644
--- a/example/multi_thread/multi_atomic_two.cpp
+++ b/example/multi_thread/multi_atomic_two.cpp
@@ -1,5 +1,5 @@
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
+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.
@@ -101,13 +101,13 @@ public:
     { }
 private:
     // forward mode routine called by CppAD
-    virtual bool forward(
+    bool forward(
         size_t                   p   ,
         size_t                   q   ,
         const vector<bool>&      vu  ,
         vector<bool>&            vy  ,
         const vector<double>&    tu  ,
-        vector<double>&          ty  )
+        vector<double>&          ty  ) override
     {
 # ifndef NDEBUG
         size_t n = tu.size() / (q + 1);
diff --git a/example/multi_thread/openmp/CMakeLists.txt b/example/multi_thread/openmp/CMakeLists.txt
index 7fee8e945..ebe8c8f0b 100644
--- a/example/multi_thread/openmp/CMakeLists.txt
+++ b/example/multi_thread/openmp/CMakeLists.txt
@@ -1,5 +1,5 @@
 # -----------------------------------------------------------------------------
-# CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 Bradley M. Bell
+# 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.
@@ -23,7 +23,6 @@ ADD_DEFINITIONS( ${OpenMP_CXX_FLAGS} )
 #                 source1 source2 ... sourceN
 # )
 SET(source_list ../thread_test.cpp
-    ${CMAKE_SOURCE_DIR}/speed/src/microsoft_timer.cpp
     ../team_example.cpp
     ../harmonic.cpp
     ../multi_atomic_two.cpp
diff --git a/example/multi_thread/pthread/CMakeLists.txt b/example/multi_thread/pthread/CMakeLists.txt
index 156890e29..8e3bb7249 100644
--- a/example/multi_thread/pthread/CMakeLists.txt
+++ b/example/multi_thread/pthread/CMakeLists.txt
@@ -1,5 +1,5 @@
 # -----------------------------------------------------------------------------
-# CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 Bradley M. Bell
+# 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.
@@ -19,7 +19,6 @@ INCLUDE_DIRECTORIES( ${CMAKE_CURRENT_SOURCE_DIR}/.. )
 #                 source1 source2 ... sourceN
 # )
 SET(source_list ../thread_test.cpp
-    ${CMAKE_SOURCE_DIR}/speed/src/microsoft_timer.cpp
     ../team_example.cpp
     ../harmonic.cpp
     ../multi_atomic_two.cpp
diff --git a/example/optimize/makefile.in b/example/optimize/makefile.in
index c34a07829..bce4033ba 100644
--- a/example/optimize/makefile.in
+++ b/example/optimize/makefile.in
@@ -277,7 +277,6 @@ 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@
@@ -332,6 +331,7 @@ pdfdir = @pdfdir@
 prefix = @prefix@
 program_transform_name = @program_transform_name@
 psdir = @psdir@
+runstatedir = @runstatedir@
 sbindir = @sbindir@
 sharedstatedir = @sharedstatedir@
 srcdir = @srcdir@
diff --git a/example/print_for/makefile.in b/example/print_for/makefile.in
index 278ebe8ea..3cbbc0748 100644
--- a/example/print_for/makefile.in
+++ b/example/print_for/makefile.in
@@ -269,7 +269,6 @@ 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@
@@ -324,6 +323,7 @@ pdfdir = @pdfdir@
 prefix = @prefix@
 program_transform_name = @program_transform_name@
 psdir = @psdir@
+runstatedir = @runstatedir@
 sbindir = @sbindir@
 sharedstatedir = @sharedstatedir@
 srcdir = @srcdir@
diff --git a/example/sparse/makefile.in b/example/sparse/makefile.in
index acfed23e8..51be00b3a 100644
--- a/example/sparse/makefile.in
+++ b/example/sparse/makefile.in
@@ -310,7 +310,6 @@ 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@
@@ -365,6 +364,7 @@ pdfdir = @pdfdir@
 prefix = @prefix@
 program_transform_name = @program_transform_name@
 psdir = @psdir@
+runstatedir = @runstatedir@
 sbindir = @sbindir@
 sharedstatedir = @sharedstatedir@
 srcdir = @srcdir@
diff --git a/example/utility/cppad_vector.cpp b/example/utility/cppad_vector.cpp
index 2f53dc838..61e1f2347 100644
--- a/example/utility/cppad_vector.cpp
+++ b/example/utility/cppad_vector.cpp
@@ -1,5 +1,5 @@
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
+CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
 
 CppAD is distributed under the terms of the
              Eclipse Public License Version 2.0.
@@ -115,14 +115,20 @@ bool CppAD_vector(void)
     for(size_t i = 0; i < n; i++)
         ok &= vec[i] == Scalar(n - i);
 
-    // vector assignment OK when target has size zero
-    other.resize(0);
-    other = vec;
+    // vector assignment OK no matter what target size was before assignment
+    other[0] = vec[0] + 1;
+    ok &= other.size() < vec.size();
+    other    = vec;
+    ok &= other.size() == vec.size();
+    for(size_t i = 0; i < vec.size(); i++)
+        ok &= other[i] == vec[i];
 
     // create a const vector equal to vec
     const vector<Scalar> cvec = vec;
 
     // sort of vec (will reverse order of elements for this case)
+# ifndef _MSC_VER
+    // 2DO: Determine why this test fails with Visual Studio 2019
     std::sort(vec.begin(), vec.end());
     for(size_t i = 0; i < n ; ++i)
         ok &= vec[i] == Scalar(i + 1);
@@ -131,6 +137,10 @@ bool CppAD_vector(void)
     std::sort(other.data(), other.data() + other.size());
     for(size_t i = 0; i < n ; ++i)
         ok &= other[i] == Scalar(i + 1);
+# else
+    for(size_t i = 0; i < n ; ++i)
+        vec[i] = Scalar(i + 1);
+# endif
 
     // test direct use of iterator and const_iterator
     typedef vector<Scalar>::iterator       iterator;
@@ -146,29 +156,24 @@ bool CppAD_vector(void)
     citr = vec.begin();
     ok  &= *citr == vec[0];
 
+    // test use of [] operator with const_itr
+    for(size_t i = 0; i < n; ++i)
+        ok &= citr[i] == vec[i];
+
+    // test use of [] operator with iterator
+    itr = vec.begin();
+    for(size_t i = 0; i < n; ++i)
+        itr[i] = Scalar(i + 1);
+
     // Replace the default CppAD error handler with myhandler (defined above).
     // This replacement is in effect until info drops out of scope.
     CppAD::ErrorHandler info(myhandler);
 
 # ifndef NDEBUG
-    // -----------------------------------------------------------------------
-    // check that size mismatch throws an exception when NDEBUG not defined
-    other.resize(0);
-    bool detected_error = false;
-    try
-    {   another = other; }
-    catch(const std::string& file)
-    {   // This location for the error is not part of user API and may change
-        size_t pos    = file.find("/vector.hpp");
-        ok           &=  pos != std::string::npos;
-        detected_error = true;
-    }
-    ok &= detected_error;
     // -----------------------------------------------------------------------
     // check that iterator access out of range generates an error
-    itr = vec.begin();
     ok  &= *itr == Scalar(1);  // this access OK
-    detected_error = false;
+    bool detected_error = false;
     try
     {   vec.clear();
         // The iterator knows that the vector has changed and that
diff --git a/example/utility/makefile.in b/example/utility/makefile.in
index 573d7acc4..29f2e0ed3 100644
--- a/example/utility/makefile.in
+++ b/example/utility/makefile.in
@@ -295,7 +295,6 @@ 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@
@@ -350,6 +349,7 @@ pdfdir = @pdfdir@
 prefix = @prefix@
 program_transform_name = @program_transform_name@
 psdir = @psdir@
+runstatedir = @runstatedir@
 sbindir = @sbindir@
 sharedstatedir = @sharedstatedir@
 srcdir = @srcdir@
diff --git a/example/utility/sparse_rc.cpp b/example/utility/sparse_rc.cpp
index 2e3cc8f6d..c5304c924 100644
--- a/example/utility/sparse_rc.cpp
+++ b/example/utility/sparse_rc.cpp
@@ -1,5 +1,5 @@
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
+CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
 
 CppAD is distributed under the terms of the
              Eclipse Public License Version 2.0.
@@ -54,18 +54,20 @@ bool sparse_rc(void)
     }
 
     // change to sparsity pattern for a 5 by 5 diagonal matrix
+    // using push_back instead of set
     nr  = 5;
     nc  = 5;
-    nnz = 5;
-    pattern.resize(nr, nc, nnz);
-    for(size_t k = 0; k < nnz; k++)
-    {   size_t r = nnz - k - 1; // reverse or row-major order
-        size_t c = nnz - k - 1;
-        pattern.set(k, r, c);
+    pattern.resize(nr, nc, 0);
+    for(size_t k = 0; k < nr; k++)
+    {   size_t r = nr - k - 1; // reverse or row-major order
+        size_t c = nr - k - 1;
+        pattern.push_back(r, c);
     }
+    nnz = pattern.nnz();
     SizeVector row_major = pattern.row_major();
 
-    // check row and column
+    // check nnz, row and column
+    ok &= nnz == nr;
     for(size_t k = 0; k < nnz; k++)
     {   ok &= row[ row_major[k] ] == k;
         ok &= col[ row_major[k] ] == k;
diff --git a/example/utility/sparse_rcv.cpp b/example/utility/sparse_rcv.cpp
index 605b721b4..9bb1a2d9e 100644
--- a/example/utility/sparse_rcv.cpp
+++ b/example/utility/sparse_rcv.cpp
@@ -1,5 +1,5 @@
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
+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.
@@ -102,6 +102,17 @@ bool sparse_rcv(void)
         ok &= matrix.col()[k] == other.col()[k];
         ok &= matrix.val()[k] == other.val()[k];
     }
+
+    // now use the copy constructor
+    CppAD::sparse_rcv<SizeVector, ValueVector> copy(matrix);
+    ok    &= copy.nr()  == matrix.nr();
+    ok    &= copy.nc()  == matrix.nc();
+    ok    &= copy.nnz() == matrix.nnz();
+    for(size_t k = 0; k < nnz; k++)
+    {   ok &= matrix.row()[k] == copy.row()[k];
+        ok &= matrix.col()[k] == copy.col()[k];
+        ok &= matrix.val()[k] == copy.val()[k];
+    }
     return ok;
 }
 
diff --git a/example/utility/to_string.cpp b/example/utility/to_string.cpp
index 0d8a0663f..84ca4e047 100644
--- a/example/utility/to_string.cpp
+++ b/example/utility/to_string.cpp
@@ -1,5 +1,5 @@
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
+CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
 
 CppAD is distributed under the terms of the
              Eclipse Public License Version 2.0.
@@ -29,11 +29,14 @@ namespace {
     {   Integer result = 0;
         size_t index   = 0;
         if( s[0] == '-' )
-            ++index;
-        while( index < s.size() )
-            result = Integer( 10 * result + (s[index++] - '0') );
-        if( s[0] == '-' )
-            return - result;
+        {   ++index;
+            while( index < s.size() )
+                result = Integer(10) * result - Integer(s[index++] - '0' );
+        }
+        else
+        {   while( index < s.size() )
+                result = Integer(10) * result + Integer(s[index++] - '0' );
+        }
         return result;
     }
     template <class Integer>
diff --git a/include/cppad/CMakeLists.txt b/include/cppad/CMakeLists.txt
index 7c5e6f3e7..88fe3f8a3 100644
--- a/include/cppad/CMakeLists.txt
+++ b/include/cppad/CMakeLists.txt
@@ -1,5 +1,5 @@
 # -----------------------------------------------------------------------------
-# CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
+# 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.
@@ -22,6 +22,12 @@ MACRO(check_match match_variable match_constant output_variable)
     print_variable(${output_variable})
 ENDMACRO(check_match)
 # -----------------------------------------------------------------------------
+# CMAKE_REQUIRED_name
+SET(CMAKE_REQUIRED_DEFINITIONS "")
+SET(CMAKE_REQUIRED_FLAGS       "")
+SET(CMAKE_REQUIRED_INCLUDES    "")
+SET(CMAKE_REQUIRED_LIBRARIES   "")
+# -----------------------------------------------------------------------------
 # compiler_has_conversion_warn
 SET( clang_or_gnu 0 )
 IF( "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" )
@@ -31,13 +37,14 @@ 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(CMAKE_REQUIRED_FLAGS
+        "${cppad_cxx_flags} -Wfloat-conversion -Wconversion -Werror"
+    )
     #
     SET(source "int main(void) { return 0; }")
-    run_source_test("${source}" compiler_has_conversion_warn )
+    compile_source_test("${source}" compiler_has_conversion_warn )
     #
-    SET(cppad_cxx_flags "${backup}")
+    SET(CMAKE_REQUIRED_FLAGS "")
 ELSE( clang_or_gnu )
     SET( compiler_has_conversion_warn 0 )
 ENDIF( clang_or_gnu )
@@ -60,7 +67,7 @@ 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 )
@@ -77,8 +84,6 @@ IF( cppad_eigenvector )
         )
     ENDIF( NOT include_eigen )
 ENDIF( cppad_eigenvector )
-#
-print_variable(cppad_cplusplus_201100_ok)
 # -----------------------------------------------------------------------------
 # cppad_has_gettimeofday
 #
@@ -90,65 +95,31 @@ int main(void)
     return 0;
 }"
 )
-run_source_test("${source}" cppad_has_gettimeofday)
+compile_source_test("${source}" cppad_has_gettimeofday)
 # -----------------------------------------------------------------------------
-# cppad_tape_addr_type, cppad_tape_id_type
-#
+# Warn user of the following types are signed:
+#   cppad_tape_addr_type, cppad_tape_id_type
 FOREACH(cmake_var cppad_tape_id_type cppad_tape_addr_type )
     SET(source "
 # include <limits>
+# include <cstddef>
 int main(void)
-{   bool is_unsigned = ! std::numeric_limits<${${cmake_var}}>::is_signed;
-    return int(! is_unsigned);
+{   static_assert(
+        ! std::numeric_limits<${${cmake_var}}>::is_signed ,
+        \"${cmake_var} is a signed type\"
+    );
+    return 0;
 }
 "
     )
-    run_source_test("${source}" ${cmake_var}_is_unsigned)
-    IF( ${cmake_var}_is_unsigned STREQUAL 0  )
+    compile_source_test("${source}" ${cmake_var}_is_unsigned)
+    IF( NOT ${${cmake_var}_is_unsigned} )
         MESSAGE(STATUS
-"Warning: using a signed ${cmake_var} is for CppAD developers only !"
-    )
-    ENDIF( ${cmake_var}_is_unsigned STREQUAL 0  )
+"Warning: using a signed type for ${cmake_var} is for CppAD developers only !"
+        )
+    ENDIF( NOT ${${cmake_var}_is_unsigned} )
 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 "
@@ -161,7 +132,7 @@ int main(void)
     return 0;
 }
 " )
-run_source_test("${source}" cppad_has_mkstemp )
+compile_source_test("${source}" cppad_has_mkstemp )
 # -----------------------------------------------------------------------------
 # cppad_has_tmpname_s
 #
@@ -174,7 +145,7 @@ int main(void)
     return 0;
 }
 " )
-run_source_test("${source}" cppad_has_tmpnam_s )
+compile_source_test("${source}" cppad_has_tmpnam_s )
 # -----------------------------------------------------------------------------
 # configure.hpp
 CONFIGURE_FILE(
diff --git a/include/cppad/core/abs_normal_fun.hpp b/include/cppad/core/abs_normal_fun.hpp
index c5a124b7c..bf9541ed2 100644
--- a/include/cppad/core/abs_normal_fun.hpp
+++ b/include/cppad/core/abs_normal_fun.hpp
@@ -507,6 +507,7 @@ void ADFun<Base,RecBase>::abs_normal_fun(ADFun& g, ADFun& a) const
             case Expm1Op:
             case LogOp:
             case Log1pOp:
+            case NegOp:
             case SignOp:
             case SinOp:
             case SinhOp:
@@ -540,14 +541,7 @@ void ADFun<Base,RecBase>::abs_normal_fun(ADFun& g, ADFun& a) const
             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_NARG_NRES(op, 2, 1);
             CPPAD_ASSERT_UNKNOWN( size_t( f2g_var[ arg[0] ] ) < num_var );
             new_arg[0] = f2g_var[ arg[0] ];
             new_arg[1] = arg[1]; // parameter
diff --git a/include/cppad/core/ad.hpp b/include/cppad/core/ad.hpp
index 99acdabb2..a7c72de76 100644
--- a/include/cppad/core/ad.hpp
+++ b/include/cppad/core/ad.hpp
@@ -1,7 +1,7 @@
 # ifndef CPPAD_CORE_AD_HPP
 # define CPPAD_CORE_AD_HPP
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
+CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
 
 CppAD is distributed under the terms of the
              Eclipse Public License Version 2.0.
@@ -135,6 +135,7 @@ private :
     friend class ADFun<Base>;
     friend class atomic_base<Base>;
     friend class atomic_three<Base>;
+    friend class atomic_four<Base>;
     friend class discrete<Base>;
     friend class VecAD<Base>;
     friend class VecAD_reference<Base>;
diff --git a/include/cppad/core/ad_ctor.hpp b/include/cppad/core/ad_ctor.hpp
index 27506f366..b970a4d62 100644
--- a/include/cppad/core/ad_ctor.hpp
+++ b/include/cppad/core/ad_ctor.hpp
@@ -1,7 +1,7 @@
 # ifndef CPPAD_CORE_AD_CTOR_HPP
 # define CPPAD_CORE_AD_CTOR_HPP
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-18 Bradley M. Bell
+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.
@@ -189,7 +189,7 @@ is the object that is being converted from T to AD<Base>.
 template <class Base>
 template <class T>
 AD<Base>::AD(const T &t)
-: value_(Base(t))
+: value_( Base( double(t) ) )
 , tape_id_(0)
 , taddr_(0)
 , ad_type_(constant_enum)
diff --git a/include/cppad/core/ad_fun.hpp b/include/cppad/core/ad_fun.hpp
index 6dd5885a0..840ea833d 100644
--- a/include/cppad/core/ad_fun.hpp
+++ b/include/cppad/core/ad_fun.hpp
@@ -1,7 +1,7 @@
 # ifndef CPPAD_CORE_AD_FUN_HPP
 # define CPPAD_CORE_AD_FUN_HPP
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
+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.
@@ -39,7 +39,7 @@ 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/ad_fun.omh%
     include/cppad/core/optimize.hpp%
     include/cppad/core/fun_check.hpp%
     include/cppad/core/check_for_nan.hpp
@@ -665,6 +665,12 @@ public:
     size_t Range(void) const
     {   return dep_taddr_.size(); }
 
+    /// set and get function name
+    void function_name_set(const std::string& function_name)
+    {   function_name_ = function_name; }
+    std::string function_name_get(void)
+    {   return function_name_; }
+
     /// is variable a parameter
     bool Parameter(size_t i)
     {   CPPAD_ASSERT_KNOWN(
diff --git a/omh/adfun.omh b/include/cppad/core/ad_fun.omh
similarity index 96%
rename from omh/adfun.omh
rename to include/cppad/core/ad_fun.omh
index dfb79b0df..b49f44fdc 100644
--- a/omh/adfun.omh
+++ b/include/cppad/core/ad_fun.omh
@@ -1,5 +1,5 @@
 -------------------------------------------------------------------------------
-  CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
+  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.
@@ -20,7 +20,8 @@ $childtable%
     include/cppad/core/fun_construct.hpp%
     include/cppad/core/dependent.hpp%
     include/cppad/core/abort_recording.hpp%
-    omh/seq_property.omh
+    include/cppad/core/fun_property.omh%
+    include/cppad/core/function_name.omh
 %$$
 
 $end
diff --git a/include/cppad/core/ad_type.hpp b/include/cppad/core/ad_type.hpp
index 4b1194c47..408d9dfa3 100644
--- a/include/cppad/core/ad_type.hpp
+++ b/include/cppad/core/ad_type.hpp
@@ -1,7 +1,7 @@
 # ifndef CPPAD_CORE_AD_TYPE_HPP
 # define CPPAD_CORE_AD_TYPE_HPP
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
+CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
 
 CppAD is distributed under the terms of the
              Eclipse Public License Version 2.0.
@@ -14,7 +14,50 @@ in the Eclipse Public License, Version 2.0 are satisfied:
 
 # include <cppad/local/is_pod.hpp>
 
-namespace CppAD { // BEGIN_CPPAD_NAMESPACE
+# ifdef NDEBUG
+# define CPPAD_ASSERT_AD_TYPE(ad_obj)
+# else
+# define CPPAD_ASSERT_AD_TYPE(ad_obj)                 \
+    switch(ad_obj.ad_type_)                           \
+    {   case constant_enum:                           \
+        CPPAD_ASSERT_UNKNOWN( ad_obj.tape_id_ == 0 ); \
+        break;                                        \
+                                                      \
+        case dynamic_enum:                            \
+        case variable_enum:                           \
+        break;                                        \
+                                                      \
+        default:                                      \
+        CPPAD_ASSERT_UNKNOWN(false);                  \
+    }                                                 \
+    CPPAD_ASSERT_UNKNOWN(                             \
+        ad_obj.tape_id_ == 0 ||                       \
+        ad_obj.ad_type_ == dynamic_enum ||            \
+        ad_obj.ad_type_ == variable_enum              \
+    );
+# endif
+
+
+namespace CppAD {
+    // BEGIN TYPEDEF
+    typedef enum {
+        identical_zero_enum,      // identically zero
+        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;
+    // END TYPEDEF
+
+    // BEGIN IS_POD
+    namespace local {
+        template <> inline bool
+        is_pod<ad_type_enum>(void) { return true; }
+    }
+    // END IS_POD
+}
+
+
 /*
 $begin ad_type_enum$$
 $spell
@@ -22,38 +65,42 @@ $spell
     typedef
     CppAD
     namespace
+    obj
 $$
 
 $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;
-/* %$$
+$srcthisfile%0%// BEGIN TYPEDEF%// END TYPEDEF%0%$$
 
 $head is_pod$$
 The following informs $cref is_pod$$ that this is plain old data.
-$srccode%hpp% */
-    namespace local {
-        template <> inline bool
-        is_pod<ad_type_enum>(void) { return true; }
-    }
-/* %$$
+$srcthisfile%0%// BEGIN IS_POD%// END IS_POD%0%$$
+
+$head Atomic Function$$
+Only some of the values are valid for the user atomic function API; see
+$cref/atomic_three/atomic_three_define/ad_type/$$ and
+$cref/atomic_four/atomic_four_for_type/ad_type/$$.
+
+$head ASSERT_AD_TYPE$$
+If $icode ad_obj$$ is an $codei%AD<%Base%>%$$ object, the syntax
+$codei%
+    CPPAD_ASSERT_AD_TYPE(%ad_obj%)
+%$$
+check that $icode ad_obj$$ satisfies the following conditions:
+
+$list number$$
+$icode%ad_obj%.ad_type_%$$ is one of the following:
+$code constant_enum$$, $code dynamic_enum$$, $code variable_enum$$.
+$lnext
+$icode%ad_obj%.ad_type_%$$ is $code constant_enum$$, then
+$icode%ad_obj%.tape_id_ == 0%$$.
+$lend
+
 $end
 */
 
-} // END_CPPAD_NAMESPACE
 
 
 # endif
diff --git a/include/cppad/core/ad_valued.hpp b/include/cppad/core/ad_valued.hpp
index 5db4344ac..ea518b206 100644
--- a/include/cppad/core/ad_valued.hpp
+++ b/include/cppad/core/ad_valued.hpp
@@ -1,7 +1,7 @@
 # ifndef CPPAD_CORE_AD_VALUED_HPP
 # define CPPAD_CORE_AD_VALUED_HPP
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 Bradley M. Bell
+CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
 
 CppAD is distributed under the terms of the
              Eclipse Public License Version 2.0.
@@ -41,10 +41,12 @@ $end
 # include <cppad/core/azmul.hpp>
 # include <cppad/core/cond_exp.hpp>
 # include <cppad/core/discrete/discrete.hpp>
-# include <cppad/core/atomic/atomic_three.hpp>
+# include <cppad/core/atomic/four/atomic.hpp>
+# include <cppad/core/atomic/three/atomic.hpp>
+# include <cppad/core/atomic/four/atomic.hpp>
 # include <cppad/core/chkpoint_two/chkpoint_two.hpp>
-# include <cppad/core/atomic/atomic_two.hpp>
-# include <cppad/core/atomic/atomic_one.hpp>
+# include <cppad/core/atomic/two/atomic.hpp>
+# include <cppad/core/atomic/one/atomic.hpp>
 # include <cppad/core/chkpoint_one/chkpoint_one.hpp>
 
 # endif
diff --git a/include/cppad/core/add.hpp b/include/cppad/core/add.hpp
index 9b41670f3..cb28ceca2 100644
--- a/include/cppad/core/add.hpp
+++ b/include/cppad/core/add.hpp
@@ -1,7 +1,7 @@
 # ifndef CPPAD_CORE_ADD_HPP
 # define CPPAD_CORE_ADD_HPP
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
+CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
 
 CppAD is distributed under the terms of the
              Eclipse Public License Version 2.0.
diff --git a/include/cppad/core/add_eq.hpp b/include/cppad/core/add_eq.hpp
index eb96b0b49..02c516667 100644
--- a/include/cppad/core/add_eq.hpp
+++ b/include/cppad/core/add_eq.hpp
@@ -1,7 +1,7 @@
 # ifndef CPPAD_CORE_ADD_EQ_HPP
 # define CPPAD_CORE_ADD_EQ_HPP
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
+CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
 
 CppAD is distributed under the terms of the
              Eclipse Public License Version 2.0.
diff --git a/include/cppad/core/atomic/atomic.omh b/include/cppad/core/atomic/atomic.omh
index 30dc4b198..5af650954 100644
--- a/include/cppad/core/atomic/atomic.omh
+++ b/include/cppad/core/atomic/atomic.omh
@@ -1,5 +1,5 @@
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-18 Bradley M. Bell
+CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
 
   CppAD is distributed under the terms of the
                Eclipse Public License Version 2.0.
@@ -14,7 +14,8 @@ $begin atomic$$
 $section Atomic AD Functions$$
 
 $childtable%
-    include/cppad/core/atomic/atomic_three.hpp%
+    include/cppad/core/atomic/four/atomic.omh%
+    include/cppad/core/atomic/three/atomic.omh%
     include/cppad/core/chkpoint_two/chkpoint_two.hpp
 %$$
 
diff --git a/include/cppad/core/atomic/four/atomic.hpp b/include/cppad/core/atomic/four/atomic.hpp
new file mode 100644
index 000000000..30aa82404
--- /dev/null
+++ b/include/cppad/core/atomic/four/atomic.hpp
@@ -0,0 +1,398 @@
+# ifndef CPPAD_CORE_ATOMIC_FOUR_ATOMIC_HPP
+# define CPPAD_CORE_ATOMIC_FOUR_ATOMIC_HPP
+/* --------------------------------------------------------------------------
+CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
+
+CppAD is distributed under the terms of the
+             Eclipse Public License Version 2.0.
+
+This Source Code may also be made available under the following
+Secondary License when the conditions 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_four_define$$
+$spell
+    taylor
+    ctor
+    afun
+    arg
+    jac
+    hes
+    CppAD
+    enum
+    mul
+    hpp
+    const
+$$
+
+$section Defining Atomic Functions: Fourth Generation$$
+
+$head Syntax$$
+
+$subhead Define Class$$
+$codei%class %atomic_user% : public CppAD::atomic_four<%Base%> {
+    %...%
+};%$$
+
+$subhead Constructor$$
+$icode%atomic_user% %afun%(%ctor_arg_list%)%$$
+
+$subhead Call$$
+$icode%afun%(%ax%, %ay%)
+%$$
+$icode%afun%(%call_id%, %ax%, %ay%)
+%$$
+
+$subhead Callbacks$$
+$icode%ok% = %afun%.for_type(
+    %call_id%, %type_x%, %type_y%
+)
+%ok% = %afun%.forward(
+    %call_id%, %select_y%, %order_low%, %order_up%, %taylor_x%, %taylor_y%
+)
+%ok% = %afun%.reverse(
+    %call_id%, %select_x%,
+    %order_up%, %taylor_x%, %taylor_y%, %partial_x%, %partial_y%
+)
+%ok% = %afun%.jac_sparsity(
+    %call_id%, %dependency%, %select_x% %select_y%, %pattern_out%
+)
+%ok% = %afun%.hes_sparsity(
+    %call_id%, %select_x% %select_y%, %pattern_out%
+)
+%ok% = %afun%.rev_depend(
+    %call_id%, %depend_x%, %depend_y%
+)%$$
+
+$head See Also$$
+$cref chkpoint_two$$, $cref atomic_three$$
+
+$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_four%<%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 used many times during the recording
+of an $cref ADFun$$ object,
+an atomic version of $latex g(x)$$ removes the need for repeated
+copies of the corresponding $codei%AD<%Base%>%$$ operations and variables
+in the recording.
+
+$head Virtual Functions$$
+The $cref/callback functions/atomic_four_define/Syntax/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_four_for_type/$$
+and $cref/forward/atomic_four_forward/$$ function
+(for the case $icode%order_up% == 0%$$) are used by an atomic function
+$cref/call/atomic_four_define/Syntax/Call/$$.
+Hence, they are required for one to use an atomic function.
+Other functions and orders are only required if they are used
+for your calculations.
+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.
+
+$childtable%include/cppad/core/atomic/four/ctor.hpp
+    %include/cppad/core/atomic/four/call.hpp
+    %include/cppad/core/atomic/four/for_type.hpp
+    %include/cppad/core/atomic/four/forward.hpp
+    %include/cppad/core/atomic/four/reverse.hpp
+    %include/cppad/core/atomic/four/jac_sparsity.hpp
+    %include/cppad/core/atomic/four/hes_sparsity.hpp
+    %include/cppad/core/atomic/four/rev_depend.hpp
+%$$
+
+$end
+-------------------------------------------------------------------------------
+*/
+
+# include <set>
+# include <cppad/core/cppad_assert.hpp>
+# include <cppad/local/atomic_index.hpp>
+
+// needed before one can use in_parallel
+# include <cppad/utility/thread_alloc.hpp>
+
+namespace CppAD { // BEGIN_CPPAD_NAMESPACE
+/*!
+\file atomic_four.hpp
+Base class for atomic function operations.
+*/
+
+template <class Base>
+class atomic_four {
+// ===================================================================
+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 call member functions, declared here
+    // to avoid memory allocation/deallocation for each call
+    struct work_struct {
+        vector<ad_type_enum>        type_x;
+        vector<ad_type_enum>        type_y;
+        //
+        vector<Base>                taylor_x;
+        vector<Base>                taylor_y;
+        //
+        vector< AD<Base> >          ataylor_x;
+        vector< AD<Base> >          ataylor_y;
+        //
+        vector<bool>                select_y;
+    };
+    // Use pointers, to avoid false sharing between threads.
+    // Not using: vector<work_struct*> 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/four_ctor.hpp
+    atomic_four(void);
+    atomic_four(const std::string& name);
+
+    // ------------------------------------------------------------------------
+    template <class ADVector> void operator()(
+        size_t           call_id ,
+        const ADVector&  ax      ,
+              ADVector&  ay
+    );
+    template <class ADVector> void operator()(
+        const ADVector&  ax      ,
+              ADVector&  ay
+    );
+    // ------------------------------------------------------------------------
+    // type: doxygen in atomic/four_for_type.hpp
+    virtual bool for_type(
+        size_t                       call_id     ,
+        const vector<ad_type_enum>&  type_x      ,
+        vector<ad_type_enum>&        type_y
+    );
+    // ------------------------------------------------------------------------
+    // type: doxygen in atomic/four_rev_depend.hpp
+    virtual bool rev_depend(
+        size_t                       call_id     ,
+        vector<bool>&                depend_x    ,
+        const vector<bool>&          depend_y
+    );
+    // ------------------------------------------------------------------------
+    // forward
+    virtual bool forward(
+        size_t                       call_id     ,
+        const vector<bool>&          select_y    ,
+        size_t                       order_low   ,
+        size_t                       order_up    ,
+        const vector<Base>&          taylor_x    ,
+        vector<Base>&                taylor_y
+    );
+    virtual bool forward(
+        size_t                       call_id      ,
+        const vector<bool>&          select_y    ,
+        size_t                       order_low    ,
+        size_t                       order_up     ,
+        const vector< AD<Base> >&    ataylor_x    ,
+        vector< AD<Base> >&          ataylor_y
+    );
+    // ------------------------------------------------------------------------
+    // reverse
+    virtual bool reverse(
+        size_t                       call_id     ,
+        const vector<bool>&          select_x    ,
+        size_t                       order_up    ,
+        const vector<Base>&          taylor_x    ,
+        const vector<Base>&          taylor_y    ,
+        vector<Base>&                partial_x   ,
+        const vector<Base>&          partial_y
+    );
+    virtual bool reverse(
+        size_t                       call_id     ,
+        const vector<bool>&          select_x    ,
+        size_t                       order_up    ,
+        const vector< AD<Base> >&    ataylor_x   ,
+        const vector< AD<Base> >&    ataylor_y   ,
+        vector< AD<Base> >&          apartial_x  ,
+        const vector< AD<Base> >&    apartial_y
+    );
+    // ------------------------------------------------------------
+    // jac_sparsity
+    virtual bool jac_sparsity(
+        size_t                       call_id     ,
+        bool                         dependency  ,
+        const vector<bool>&          select_x    ,
+        const vector<bool>&          select_y    ,
+        sparse_rc< vector<size_t> >& pattern_out
+    );
+    template <class InternalSparsity>
+    bool for_jac_sparsity(
+        bool                             dependency   ,
+        size_t                           call_id      ,
+        const local::pod_vector<size_t>& x_index      ,
+        const local::pod_vector<size_t>& y_index      ,
+        InternalSparsity&                var_sparsity
+    );
+    template <class InternalSparsity>
+    bool rev_jac_sparsity(
+        bool                             dependency   ,
+        size_t                           call_id      ,
+        const local::pod_vector<size_t>& x_index      ,
+        const local::pod_vector<size_t>& y_index      ,
+        InternalSparsity&                var_sparsity
+    );
+    // ------------------------------------------------------------
+    // hes_sparsity
+    virtual bool hes_sparsity(
+        size_t                                  call_id      ,
+        const vector<bool>&                     select_x     ,
+        const vector<bool>&                     select_y     ,
+        sparse_rc< vector<size_t> >&            pattern_out
+    );
+    template <class InternalSparsity>
+    bool for_hes_sparsity(
+        size_t                           call_id          ,
+        const local::pod_vector<size_t>& x_index          ,
+        const local::pod_vector<size_t>& y_index          ,
+        size_t                           np1              ,
+        size_t                           numvar           ,
+        const InternalSparsity&          rev_jac_sparsity ,
+        InternalSparsity&                for_sparsity
+    );
+    template <class InternalSparsity>
+    bool rev_hes_sparsity(
+        size_t                           call_id          ,
+        const local::pod_vector<size_t>& x_index          ,
+        const local::pod_vector<size_t>& y_index          ,
+        const InternalSparsity&          for_jac_pattern  ,
+        bool*                            rev_jac_flag     ,
+        InternalSparsity&                hes_sparsity
+    );
+
+    // =====================================================================
+    // Not in User API
+    // =====================================================================
+
+    /// Name corresponding to a atomic_four 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<Base>(set_null, index_, type, &name, v_ptr);
+        CPPAD_ASSERT_UNKNOWN( type == 4 );
+        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_four(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<Base>(set_null, index_, type, name, v_ptr);
+        CPPAD_ASSERT_UNKNOWN( type == 4 );
+        //
+        // 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<work_struct*>( 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<void*>(work_[thread])
+            );
+            // mark this thread as not allocated
+            work_[thread] = nullptr;
+        }
+        return;
+    }
+    /// atomic_four function object corresponding to a certain index
+    static atomic_four* 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<Base>(set_null, index, type, name, v_ptr);
+        CPPAD_ASSERT_UNKNOWN( type == 4 );
+        return reinterpret_cast<atomic_four*>( v_ptr );
+    }
+    /// atomic_four 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<Base>(set_null, index, type, &name, v_ptr);
+        CPPAD_ASSERT_UNKNOWN( type == 4 );
+        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 <cppad/core/atomic/four/ctor.hpp>
+# include <cppad/core/atomic/four/call.hpp>
+# include <cppad/core/atomic/four/for_type.hpp>
+# include <cppad/core/atomic/four/rev_depend.hpp>
+# include <cppad/core/atomic/four/forward.hpp>
+# include <cppad/core/atomic/four/reverse.hpp>
+# include <cppad/core/atomic/four/jac_sparsity.hpp>
+# include <cppad/core/atomic/four/hes_sparsity.hpp>
+
+# endif
diff --git a/include/cppad/core/atomic/four/atomic.omh b/include/cppad/core/atomic/four/atomic.omh
new file mode 100644
index 000000000..b9bca3bf3
--- /dev/null
+++ b/include/cppad/core/atomic/four/atomic.omh
@@ -0,0 +1,21 @@
+/* --------------------------------------------------------------------------
+CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
+
+  CppAD is distributed under the terms of the
+               Eclipse Public License Version 2.0.
+
+  This Source Code may also be made available under the following
+  Secondary License when the conditions 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_four$$
+
+$section Atomic AD Functions: Fourth Generation$$
+
+$childtable%
+    include/cppad/core/atomic/four/atomic.hpp%
+    example/atomic_four/atomic_four.omh
+%$$
+
+$end
diff --git a/include/cppad/core/atomic/four/call.hpp b/include/cppad/core/atomic/four/call.hpp
new file mode 100644
index 000000000..b7376711e
--- /dev/null
+++ b/include/cppad/core/atomic/four/call.hpp
@@ -0,0 +1,252 @@
+# ifndef CPPAD_CORE_ATOMIC_FOUR_CALL_HPP
+# define CPPAD_CORE_ATOMIC_FOUR_CALL_HPP
+/* --------------------------------------------------------------------------
+CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
+
+CppAD is distributed under the terms of the
+             Eclipse Public License Version 2.0.
+
+This Source Code may also be made available under the following
+Secondary License when the conditions 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_four_call$$
+
+$spell
+    sq
+    mul
+    afun
+    const
+    CppAD
+    mat_mul.cpp
+    std
+    cppad
+$$
+
+$section Calling an Atomic Function$$
+
+$head Syntax$$
+$icode%afun%(%ax%, %ay%)
+%$$
+$icode%ay% = %afun%(%call_id%, %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 $cref/Base/atomic_four_ctor/atomic_four/Base/$$
+in the $icode afun$$ constructor.
+It is also the $icode Base$$ type of the elements of
+$icode ax$$ and $icode ay$$ in the atomic function call.
+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_four_ctor/atomic_user/$$ object
+and this $icode afun$$ function call is implemented by the
+$cref/atomic_four/atomic_four_ctor/atomic_four/$$ class.
+
+$head ax$$
+The size of this vector determines$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.
+
+$head ay$$
+The size of this vector determines $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)$$.
+
+$head call_id$$
+This optional argument has default value zero.
+It can be used to specify additional information about this call to
+$icode afun$$. For example, it could specify the index in vector of structures
+in the $icode afun$$ object where the actual information is placed.
+
+$subhead Restriction$$
+The value of $icode call_id$$ must be less than or equal
+$codei%
+    std::numeric_limits<%cppad_tape_id_type%>::max()
+%$$
+see $cref/cppad_tape_id_type/cmake/cppad_tape_id_type/$$.
+
+$end
+-----------------------------------------------------------------------------
+*/
+
+namespace CppAD { // BEGIN_CPPAD_NAMESPACE
+
+// BEGIN_PROTOTYPE
+template <class Base> template <class ADVector>
+void atomic_four<Base>::operator()(
+    size_t           call_id ,
+    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_four: call " + atomic_name() + " ";
+    if( (n == 0) | (m == 0) )
+    {   msg += "ax.size() or ay.size() is zero";
+        CPPAD_ASSERT_KNOWN(false, msg.c_str() );
+    }
+# endif
+    //
+    // type_x, type_y, taylor_x, taylor_y, select_y
+    size_t thread = thread_alloc::thread_num();
+    allocate_work(thread);
+    vector<ad_type_enum>& type_x   = work_[thread]->type_x;
+    vector<ad_type_enum>& type_y   = work_[thread]->type_y;
+    vector<Base>&         taylor_x = work_[thread]->taylor_x;
+    vector<Base>&         taylor_y = work_[thread]->taylor_y;
+    vector<bool>&         select_y = work_[thread]->select_y;
+    type_x.resize(n);
+    taylor_x.resize(n);
+    type_y.resize(m);
+    taylor_y.resize(m);
+    select_y.resize(m);
+    //
+    // tape_id, tape, taylor_x, type_x
+    tape_id_t            tape_id  = 0;
+    local::ADTape<Base>* tape     = nullptr;
+    for(size_t j = 0; j < n; j++)
+    {   taylor_x[j]  = ax[j].value_;
+        if( IdenticalZero( ax[j] ) )
+            type_x[j] = identical_zero_enum;
+        else 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
+    for(size_t i = 0; i < m; ++i)
+        select_y[i] = true;
+    size_t order_low   = 0;
+    size_t order_up    = 0;
+# ifdef NDEBUG
+    forward(
+        call_id, select_y, order_low, order_up, taylor_x, taylor_y
+    );
+    for_type(call_id, type_x, type_y);
+# else
+    ok &= forward(
+        call_id, select_y, order_low, order_up, taylor_x, taylor_y
+    );
+    ok &= for_type(call_id, 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_, call_id, type_x, type_y, ax, ay
+        );
+    }
+    // case where result contains a variable
+    if( record_variable )
+    {   tape->Rec_.put_var_atomic(
+            tape_id, index_, call_id, type_x, type_y, ax, ay
+        );
+    }
+# ifndef NDEBUG
+    for(size_t i = 0; i < m; ++i) switch( type_y[i] )
+    {   //
+        case identical_zero_enum:
+        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_four: for_type: type_y[i]: is not a valid type"
+        );
+        break;
+    }
+# endif
+    return;
+}
+template <class Base> template <class ADVector>
+void atomic_four<Base>::operator()(
+    const ADVector&  ax      ,
+    ADVector&        ay      )
+{   size_t call_id = 0;
+    (*this)(call_id, ax, ay);
+}
+
+} // END_CPPAD_NAMESPACE
+# endif
diff --git a/include/cppad/core/atomic/four/ctor.hpp b/include/cppad/core/atomic/four/ctor.hpp
new file mode 100644
index 000000000..fb2bbb5c9
--- /dev/null
+++ b/include/cppad/core/atomic/four/ctor.hpp
@@ -0,0 +1,145 @@
+# ifndef CPPAD_CORE_ATOMIC_FOUR_CTOR_HPP
+# define CPPAD_CORE_ATOMIC_FOUR_CTOR_HPP
+/* --------------------------------------------------------------------------
+CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
+
+CppAD is distributed under the terms of the
+             Eclipse Public License Version 2.0.
+
+This Source Code may also be made available under the following
+Secondary License when the conditions 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_four_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_four<%Base%> {
+public:
+    %atomic_user%(%ctor_arg_list%) : CppAD::atomic_four<%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<Base>/ADFun/$$ object 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_four<%Base%>%$$.
+It should be declared as follows:
+$codei%
+    class %atomic_user% : public CppAD::atomic_four<%Base%> {
+    public:
+        %atomic_user%(%ctor_arg_list%) : atomic_four<%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_four$$ implementations replaced by
+$icode atomic_user$$ implementations.
+
+$head atomic_four$$
+
+$subhead Restrictions$$
+The $code atomic_four$$ constructor and destructor cannot be called in
+$cref/parallel/ta_in_parallel/$$ mode.
+
+$subhead Base$$
+The template parameter determines the
+$cref/Base/atomic_four_call/Base/$$
+type for this $codei%AD<%Base%>%$$ atomic operation.
+
+$subhead name$$
+This $code atomic_four$$ 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$$
+The following is an example constructor definition taken from
+$cref atomic_four_norm_sq.cpp$$:
+$srcfile%
+    example/atomic_four/norm_sq.cpp%
+    0%// BEGIN CONSTRUCTOR%// END CONSTRUCTOR%0
+%$$
+
+
+$end
+-------------------------------------------------------------------------------
+*/
+namespace CppAD { // BEGIN_CPPAD_NAMESPACE
+
+// atomic_four()
+template <class Base>
+atomic_four<Base>::atomic_four(void)
+{   CPPAD_ASSERT_KNOWN(false,
+        "Attempt to use the atomic_four default constructor"
+    );
+}
+
+// atomic_four(name)
+// BEGIN_PROTOTYPE
+template <class Base>
+atomic_four<Base>::atomic_four(const std::string& name )
+// END_PROTOTYPE
+{   CPPAD_ASSERT_KNOWN(
+        ! thread_alloc::in_parallel() ,
+        "atomic_four: constructor cannot be called in parallel mode."
+    );
+    //
+    // index_
+    bool        set_null  = false;
+    size_t      index     = 0;
+    size_t      type      = 4;
+    std::string copy_name = name;
+    void*       copy_this = reinterpret_cast<void*>( this );
+    index_  = local::atomic_index<Base>(
+        set_null, index, type, &copy_name, copy_this
+    );
+    //
+    // work_
+    for(size_t thread = 0; thread < CPPAD_MAX_NUM_THREADS; thread++)
+        work_[thread] = nullptr;
+}
+
+} // END_CPPAD_NAMESPACE
+# endif
diff --git a/include/cppad/core/atomic/four/devel/devel.omh b/include/cppad/core/atomic/four/devel/devel.omh
new file mode 100644
index 000000000..99c050f5d
--- /dev/null
+++ b/include/cppad/core/atomic/four/devel/devel.omh
@@ -0,0 +1,21 @@
+/* --------------------------------------------------------------------------
+CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
+
+CppAD is distributed under the terms of the
+             Eclipse Public License Version 2.0.
+
+This Source Code may also be made available under the following
+Secondary License when the conditions 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_four_devel$$
+
+$section atomic_four Developer Documentation$$
+
+$childtable%
+    include/cppad/core/atomic/four/devel/jac_sparsity.hpp
+%$$
+
+$end
diff --git a/include/cppad/core/atomic/four/devel/hes_sparsity.hpp b/include/cppad/core/atomic/four/devel/hes_sparsity.hpp
new file mode 100644
index 000000000..b6193524d
--- /dev/null
+++ b/include/cppad/core/atomic/four/devel/hes_sparsity.hpp
@@ -0,0 +1,320 @@
+# ifndef CPPAD_CORE_ATOMIC_FOUR_DEVEL_HES_SPARSITY_HPP
+# define CPPAD_CORE_ATOMIC_FOUR_DEVEL_HES_SPARSITY_HPP
+/* --------------------------------------------------------------------------
+CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
+
+CppAD is distributed under the terms of the
+             Eclipse Public License Version 2.0.
+
+This Source Code may also be made available under the following
+Secondary License when the conditions 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
+/*
+-----------------------------------------------------------------------------
+$begin atomic_four_for_hes_sparsity$$
+
+$section Link from Forward Hesswian Sparsity Sweep to atomic_four Callback$$
+
+$head Prototype$$
+$srcthisfile%0%// BEGIN_FOR_HES_SPARSITY%// END_FOR_HES_SPARSITY%1%$$
+
+$head InternalSparsity$$
+Is the used internaly for sparsity calculations; i.e.,
+sparse_pack or sparse_list.
+
+$head call_id [in]$$
+see $cref/call_id/atomic_four_call/call_id/$$.
+
+$head 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.
+
+$head 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.
+
+$head np1$$
+is the number of components of x plus one; i.e. $icode%n% + 1%$$.
+
+$head numvar$$
+is the total number of variables in the tape; i.e.,
+$icode%play%->num_var_rec()%$$.
+
+$head for_sparsity$$
+The sparsity patterns with index zero and index $icode np1$$ are empty
+(because they correspond to parameters).
+
+$subhead On Input$$
+On input, for j = 0, ... , n-1,
+the forward Jacobian sparsity for the $th j$$ arguemnt to the atomic fucntion
+is the sparsity pattern with index $icode%np1% + %x_index[j]%$$.
+In addition, the sparsity pattern with index $th j+1$$ contains
+the non-zero cross partial indices where $th j+1$$ is the other index.
+This Hessian does not include the atomic operation.
+
+$subhead On Output$$
+On output, for i = 0, ... , m-1,
+the forward Jacobian sparsity for the $th i$$ result of the atomic fucntion
+is the sparsity pattern with index $icode%np1% + %y_index[i]%$$.
+In addition, the sparsity pattern with index $th j+1$$ contains
+the non-zero cross partial indices where $th j+1$$ is the other index.
+This Hessian includes the atomic operation.
+
+$head 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.
+
+$head 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.
+
+$end
+*/
+template <class Base>
+template <class InternalSparsity>
+bool atomic_four<Base>::for_hes_sparsity(
+    size_t                           call_id          ,
+    const local::pod_vector<size_t>& x_index          ,
+    const local::pod_vector<size_t>& 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 );
+    CPPAD_ASSERT_UNKNOWN( for_sparsity.number_elements(0) == 0 );
+    CPPAD_ASSERT_UNKNOWN( for_sparsity.number_elements(np1) == 0 );
+    //
+    size_t n      = x_index.size();
+    size_t m      = y_index.size();
+    //
+    // select_x
+    vector<bool> 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<bool> 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<size_t> > pattern_out;
+    bool dependency = false;
+    bool ok = jac_sparsity(
+        call_id, 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<size_t>& row( pattern_out.row() );
+    const vector<size_t>& 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(
+        call_id, 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;
+}
+/*
+$begin atomic_four_rev_hes_sparsity$$
+
+$section Link from Reverse Hessian Sparsity Sweep to atomic_four Callback$$
+
+$head Prototype$$
+$srcthisfile%0%// BEGIN_REV_HES_SPARSITY%// END_REV_HES_SPARSITY%1%$$
+
+$head InternalSparsity$$
+Is the used internaly for sparsity calculations; i.e.,
+sparse_pack or sparse_list.
+
+
+$head call_id [in]$$
+see $cref/call_id/atomic_four_call/call_id/$$.
+
+$head 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.
+
+$head 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.
+
+$head 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.
+
+$head 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.
+
+$head 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.
+
+$end
+*/
+template <class Base>
+template <class InternalSparsity>
+bool atomic_four<Base>::rev_hes_sparsity(
+    size_t                           call_id          ,
+    const local::pod_vector<size_t>& x_index          ,
+    const local::pod_vector<size_t>& y_index          ,
+    const InternalSparsity&          for_jac_pattern  ,
+    bool*                            rev_jac_flag     ,
+    InternalSparsity&                hes_sparsity_rev )
+{   CPPAD_ASSERT_UNKNOWN( for_jac_pattern.number_elements(0) == 0 );
+    CPPAD_ASSERT_UNKNOWN( ! rev_jac_flag[0] );
+    //
+    size_t n      = x_index.size();
+    size_t m      = y_index.size();
+    //
+    // select_x
+    vector<bool> select_x(n);
+    for(size_t j = 0; j < n; j++)
+        select_x[j] = for_jac_pattern.number_elements( x_index[j] ) > 0;
+    //
+    // select_y
+    vector<bool> select_y(m);
+    for(size_t i = 0; i < m; i++)
+        select_y[i] = rev_jac_flag[ y_index[i] ];
+    //
+    // call atomic function for Jacobain sparsity
+    bool dependency = false;
+    sparse_rc< vector<size_t> > pattern_jac;
+    bool ok = jac_sparsity(
+        call_id, dependency, select_x, select_y, pattern_jac
+    );
+    const vector<size_t>& row_jac( pattern_jac.row() );
+    const vector<size_t>& 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<size_t> > pattern_hes;
+    ok = hes_sparsity(call_id, select_x, select_y, pattern_hes);
+    const vector<size_t>& row_hes( pattern_hes.row() );
+    const vector<size_t>& 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/include/cppad/core/atomic/four/devel/jac_sparsity.hpp b/include/cppad/core/atomic/four/devel/jac_sparsity.hpp
new file mode 100644
index 000000000..644c1d5a0
--- /dev/null
+++ b/include/cppad/core/atomic/four/devel/jac_sparsity.hpp
@@ -0,0 +1,252 @@
+# ifndef CPPAD_CORE_ATOMIC_FOUR_DEVEL_JAC_SPARSITY_HPP
+# define CPPAD_CORE_ATOMIC_FOUR_DEVEL_JAC_SPARSITY_HPP
+/* --------------------------------------------------------------------------
+CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
+
+CppAD is distributed under the terms of the
+             Eclipse Public License Version 2.0.
+
+This Source Code may also be made available under the following
+Secondary License when the conditions 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
+
+/*
+------------------------------------------------------------------------------
+$begin atomic_four_for_jac_sparsity$$
+$spell
+    Jacobian
+    var
+$$
+
+$section Link from Forward Jacobian Sparsity Sweep to atomic_four Callback$$
+
+$head Prototype$$
+$srcthisfile%0%// BEGIN_FOR_JAC_SPARSITY%// END_FOR_JAC_SPARSITY%1%$$
+
+$head InternalSparsity$$
+is the type used for internal sparsity calculations; i.e.,
+sparse_pack or sparse_list.
+
+$head dependency$$
+if true, calculate dependency pattern,
+otherwise calculate sparsity pattern.
+
+$head call_id$$
+see $cref/call_id/atomic_four_call/call_id/$$.
+
+$head x_index$$
+is the variable index, on the tape, for the arguments to this atomic function.
+This size of x_index is, the number of arguments to this atomic function.
+The index zero is used for parameters.
+
+$head 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.
+
+$head 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.
+
+$head Return Value$$
+is true if the computation succeeds.
+
+$end
+*/
+// BEGIN_FOR_JAC_SPARSITY
+template <class Base>
+template <class InternalSparsity>
+bool atomic_four<Base>::for_jac_sparsity(
+    bool                             dependency   ,
+    size_t                           call_id      ,
+    const local::pod_vector<size_t>& x_index      ,
+    const local::pod_vector<size_t>& y_index      ,
+    InternalSparsity&                var_sparsity )
+// END_FOR_JAC_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<bool> select_y(m);
+    for(size_t i = 0; i < m; ++i)
+        select_y[i] = y_index[i] != 0;
+
+    // determine select_x
+    vector<bool> select_x(n);
+    for(size_t j = 0; j < n; ++j)
+    {   if( x_index[j] == 0 )
+            select_x[j] = false;
+        else
+        {   // 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();
+        }
+    }
+    sparse_rc< vector<size_t> > pattern_out;
+    bool ok = jac_sparsity(
+        call_id, 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<size_t>& row( pattern_out.row() );
+    const vector<size_t>& 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;
+}
+
+/*
+------------------------------------------------------------------------------
+$begin atomic_four_rev_jac_sparsity$$
+$spell
+    Jacobian
+    var
+$$
+
+$section Link from Reverse Jacobian Sparsity Sweep to atomic_four Callback$$
+
+$head Prototype$$
+$srcthisfile%0%// BEGIN_REV_JAC_SPARSITY%// END_REV_JAC_SPARSITY%1%$$
+
+$head InternalSparsity$$
+Is the type used for internal sparsity calculations; i.e.,
+sparse_pack or sparse_list.
+
+$head dependency$$
+if true, calculate dependency pattern,
+otherwise calculate sparsity pattern.
+
+$head call_id$$
+see $cref/call_id/atomic_four_call/call_id/$$
+
+$head 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.
+
+$head 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.
+
+$head var_sparsity$$
+We are given a sparsity pattern an outer function G(y, x) and compute
+the pattern for an inner function H(x), which is the outer functions
+with the components of y treated as functions of x; i.e.
+H(x) = G( Y(x), x).
+
+$subhead y_index$$
+On input, for i = 0, ... , m-1, the sparsity pattern with index y_index[i],
+is the sparsity of the outer function with respect to the i-th
+result for this atomic function.
+
+$subhead x_index$$
+On input, for j = 0, ... , n-1, the sparsity pattern with index x_index[j],
+is the sparsity for the outer function with respect 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 inner function with respect to the j-th
+argument to this atomic function.
+
+$head Return Value$$
+is true if the computation succeeds.
+
+$end
+*/
+// BEGIN_REV_JAC_SPARSITY
+template <class Base>
+template <class InternalSparsity>
+bool atomic_four<Base>::rev_jac_sparsity(
+    bool                             dependency   ,
+    size_t                           call_id      ,
+    const local::pod_vector<size_t>& x_index      ,
+    const local::pod_vector<size_t>& y_index      ,
+    InternalSparsity&                var_sparsity )
+// END_REV_JAC_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<bool> select_x(n), select_y(m);
+
+    // select_x
+    for(size_t j = 0; j < n; ++j)
+        select_x[j] = x_index[j] != 0;
+
+    // determine select_y
+    for(size_t i = 0; i < m; ++i)
+    {   if( y_index[i] == 0 )
+            select_y[i] = false;
+        else
+        {   // 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<size_t> > pattern_out;
+    bool ok = jac_sparsity(
+        call_id, 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<size_t>& row( pattern_out.row() );
+    const vector<size_t>& 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/include/cppad/core/atomic/four/for_type.hpp b/include/cppad/core/atomic/four/for_type.hpp
new file mode 100644
index 000000000..1051caf0f
--- /dev/null
+++ b/include/cppad/core/atomic/four/for_type.hpp
@@ -0,0 +1,135 @@
+# ifndef CPPAD_CORE_ATOMIC_FOUR_FOR_TYPE_HPP
+# define CPPAD_CORE_ATOMIC_FOUR_FOR_TYPE_HPP
+/* --------------------------------------------------------------------------
+CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
+
+CppAD is distributed under the terms of the
+             Eclipse Public License Version 2.0.
+
+This Source Code may also be made available under the following
+Secondary License when the conditions 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_four_for_type$$
+$spell
+    afun
+    enum
+    cpp
+$$
+
+$section Atomic Function Forward Type Calculation$$
+
+$head Syntax$$
+$icode%ok% = %afun%.for_type(%call_id%, %type_x%, %type_y%)%$$
+
+$head 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 a
+$cref/call/atomic_four_call/$$ to an atomic function.
+
+$head Implementation$$
+This virtual function must be defined by the
+$cref/atomic_user/atomic_four_ctor/atomic_user/$$ derived class.
+
+$head vector$$
+is the $cref CppAD_vector$$ template class.
+
+$head Base$$
+See $cref/Base/atomic_four_call/Base/$$.
+
+$head call_id$$
+See $cref/call_id/atomic_four_call/call_id/$$.
+
+$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 identical_zero_enum$$  $pre  $$   $cnext identically zero $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,
+$codei%
+    identical_zero_enum < constant_enum < dynamic_enum < variable_enum
+%$$
+A value that is identically zero is also a constant parameter.
+In CppAD, multiplication of a variable by a value that is identically zero
+is sometimes treated like $tref azmul$$.
+This avoids having to record the operation.
+
+
+$head type_x$$
+This vector has size equal to the number of arguments in the
+atomic function call; i.e., the size of
+$cref/ax/atomic_four_call/ax/$$ which we denote by $icode n$$.
+For $icode%j% =0,%...%,%n%-1%$$, $icode%type_x%[%j%]%$$
+is the type of $icode%ax%[%j%]%$$.
+
+$head type_y$$
+This vector has size equal to the number of results in the
+atomic function call; i.e., the size of
+$cref/ay/atomic_four_call/ay/$$ which we denote by $icode m$$.
+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 identical_zero_enum$$ if $icode%ay%[%i%]%$$ is
+$cref/identically zero/base_identical/Identical/$$.
+$lnext
+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 $code for_type$$ definition taken from
+$cref atomic_four_norm_sq.cpp$$:
+$srcfile%
+    example/atomic_four/norm_sq.cpp%
+    0%// BEGIN FOR_TYPE%// END FOR_TYPE%0
+%$$
+
+$end
+-----------------------------------------------------------------------------
+*/
+
+namespace CppAD { // BEGIN_CPPAD_NAMESPACE
+
+// BEGIN_PROTOTYPE
+template <class Base>
+bool atomic_four<Base>::for_type(
+    size_t                       call_id     ,
+    const vector<ad_type_enum>&  type_x      ,
+    vector<ad_type_enum>&        type_y      )
+// END_PROTOTYPE
+{   return false; }
+
+} // END_CPPAD_NAMESPACE
+
+# endif
diff --git a/include/cppad/core/atomic/four/forward.hpp b/include/cppad/core/atomic/four/forward.hpp
new file mode 100644
index 000000000..132954859
--- /dev/null
+++ b/include/cppad/core/atomic/four/forward.hpp
@@ -0,0 +1,261 @@
+# ifndef CPPAD_CORE_ATOMIC_FOUR_FORWARD_HPP
+# define CPPAD_CORE_ATOMIC_FOUR_FORWARD_HPP
+/* --------------------------------------------------------------------------
+CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
+
+CppAD is distributed under the terms of the
+             Eclipse Public License Version 2.0.
+
+This Source Code may also be made available under the following
+Secondary License when the conditions 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_four_forward$$
+$spell
+    taylor
+    ataylor
+    af
+    afun
+    enum
+    CppAD
+    aparameter
+$$
+
+$section Atomic Function Forward Mode$$
+
+$head Syntax$$
+
+$subhead Base$$
+$icode%ok% = %afun%.forward(
+    %call_id%, %select_y%,
+    %order_low%, %order_up%, %type_x%, %taylor_x%, %taylor_y%
+)%$$
+
+$subhead AD<Base>$$
+$icode%ok% = %afun%.forward(
+    %call_id%, %select_y%,
+    %order_low%, %order_up%, %type_x%, %ataylor_x%, %ataylor_y%
+)%$$
+
+$head Prototype$$
+
+$subhead Base$$
+$srcthisfile%0%// BEGIN_PROTOTYPE_BASE%// END_PROTOTYPE_BASE%1
+%$$
+
+$subhead AD<Base>$$
+$srcthisfile%0%// BEGIN_PROTOTYPE_AD_BASE%// END_PROTOTYPE_AD_BASE%1
+%$$
+
+$head Base$$
+see $cref/Base/atomic_four_call/Base/$$.
+
+$head vector$$
+is the $cref CppAD_vector$$ template class.
+
+
+$head Usage$$
+
+$subhead Base$$
+The $icode Base$$ syntax and prototype are used by a
+$cref/call/atomic_four_call/$$ to the atomic function $icode afun$$.
+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 AD<Base>$$
+The $codei%AD<%Base%>%$$ 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 a function $icode af$$,
+created from $icode f$$ using $cref base2ad$$.
+
+$head Implementation$$
+The $icode taylor_x$$, $icode taylor_y$$ version of this function
+must be defined by the
+$cref/atomic_user/atomic_four_ctor/atomic_user/$$ class.
+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/forward/Forward/$$ mode calculations.
+Order zero must be implemented.
+
+$head call_id$$
+See $cref/call_id/atomic_four_call/call_id/$$.
+
+$head select_y$$
+This argument has size equal to the number of results to this
+atomic function; i.e. the size of $cref/ay/atomic_four_call/ay/$$.
+It specifies which components of $icode y$$ the corresponding
+Taylor coefficients must be computed.
+
+$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 is the highest order Taylor coefficient that we
+are computing ($icode%order_low% <= %order_up%$$).
+
+$subhead q$$
+We use the notation $icode%q% = %order_up% + 1%$$ below.
+This is the number of Taylor coefficients for each
+component of $icode x$$ and $icode y$$.
+
+$head taylor_x$$
+The size of $icode taylor_x$$ is $icode%q%*%n%$$.
+For $latex j = 0 , \ldots , n-1$$ and $latex k = 0 , \ldots , q-1$$,
+we use the Taylor coefficient notation
+$latex \[
+\begin{array}{rcl}
+    x_j^k    & = & \R{taylor\_x} [ j * q + k ]
+    \\
+    X_j (t)  & = & x_j^0 + x_j^1 t^1 + \cdots + x_j^{q-1} t^{q-1}
+\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$$ is a parameter,
+$codei%
+    %type_x%[%j%] < CppAD::variable_enum
+%$$
+In this case, for $icode%k% > 0%$$,
+$codei%
+    %taylor_x%[ %j% * %q% + %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 $icode%q%*%m%$$.
+Upon return,
+For $latex i = 0 , \ldots , m-1$$ and $latex k = 0 , \ldots , q-1$$,
+if $icode select_y[i]$$ is true,
+$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-1} t^{q-1} + o( t^{q-1} )
+    \\
+    \R{taylor\_y}  [ i * q + k ] & = & y_i^k
+\end{array}
+\] $$
+where $latex o( t^{q-1} ) / t^{q-1} \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 + 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 g^{(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 + k ] = y_i^k
+\] $$
+
+
+$head Example$$
+The following is an example $code forward$$ definition taken from
+$cref atomic_four_norm_sq.cpp$$:
+$srcfile%
+    example/atomic_four/norm_sq.cpp%
+    0%// BEGIN FORWARD%// END FORWARD%0
+%$$
+
+$end
+-----------------------------------------------------------------------------
+*/
+
+namespace CppAD { // BEGIN_CPPAD_NAMESPACE
+
+// BEGIN_PROTOTYPE_BASE
+template <class Base>
+bool atomic_four<Base>::forward(
+    size_t                       call_id     ,
+    const vector<bool>&          select_y    ,
+    size_t                       order_low   ,
+    size_t                       order_up    ,
+    const vector<Base>&          taylor_x    ,
+    vector<Base>&                taylor_y    )
+// END_PROTOTYPE_BASE
+{   return false; }
+
+// BEGIN_PROTOTYPE_AD_BASE
+template <class Base>
+bool atomic_four<Base>::forward(
+    size_t                       call_id      ,
+    const vector<bool>&          select_y    ,
+    size_t                       order_low    ,
+    size_t                       order_up     ,
+    const vector< AD<Base> >&    ataylor_x    ,
+    vector< AD<Base> >&          ataylor_y    )
+// END_PROTOTYPE_AD_BASE
+{   return false; }
+
+
+} // END_CPPAD_NAMESPACE
+# endif
diff --git a/include/cppad/core/atomic/four/hes_sparsity.hpp b/include/cppad/core/atomic/four/hes_sparsity.hpp
new file mode 100644
index 000000000..562a295aa
--- /dev/null
+++ b/include/cppad/core/atomic/four/hes_sparsity.hpp
@@ -0,0 +1,118 @@
+# ifndef CPPAD_CORE_ATOMIC_FOUR_HES_SPARSITY_HPP
+# define CPPAD_CORE_ATOMIC_FOUR_HES_SPARSITY_HPP
+/* --------------------------------------------------------------------------
+CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
+
+CppAD is distributed under the terms of the
+             Eclipse Public License Version 2.0.
+
+This Source Code may also be made available under the following
+Secondary License when the conditions 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 <cppad/core/atomic/four/devel/hes_sparsity.hpp>
+/*
+$begin atomic_four_hes_sparsity$$
+$spell
+    Hessian
+    afun
+    hes
+$$
+
+$section Atomic Function Hessian Sparsity Patterns$$
+
+$head Syntax$$
+$icode%ok% = %afun%.hes_sparsity(
+    %call_id%, %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_four_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_four_call/Base/$$.
+
+$head vector$$
+is the $cref CppAD_vector$$ template class.
+
+$head call_id$$
+See $cref/call_id/atomic_four_call/call_id/$$.
+
+$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 r$$, $icode c$$, and $icode k$$ such that
+$codei%
+    %pattern_out%.row()[%k%] == %r%
+    %pattern_out%.col()[%k%] == %c%
+%$$
+if and only if
+there exists an index $icode i$$ such that,
+$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.
+
+$head Example$$
+The following is an example $code hes_sparsity$$ definition taken from
+$cref atomic_four_norm_sq.cpp$$:
+$srcfile%
+    example/atomic_four/norm_sq.cpp%
+    0%// BEGIN HES_SPARSITY%// END HES_SPARSITY%0
+%$$
+
+$end
+-----------------------------------------------------------------------------
+*/
+namespace CppAD { // BEGIN_CPPAD_NAMESPACE
+// BEGIN_PROTOTYPE
+template <class Base>
+bool atomic_four<Base>::hes_sparsity(
+    size_t                                  call_id      ,
+    const vector<bool>&                     select_x     ,
+    const vector<bool>&                     select_y     ,
+    sparse_rc< vector<size_t> >&            pattern_out  )
+// END_PROTOTYPE
+{   return false; }
+
+} // END_CPPAD_NAMESPACE
+
+# endif
diff --git a/include/cppad/core/atomic/four/jac_sparsity.hpp b/include/cppad/core/atomic/four/jac_sparsity.hpp
new file mode 100644
index 000000000..e8d08aaa6
--- /dev/null
+++ b/include/cppad/core/atomic/four/jac_sparsity.hpp
@@ -0,0 +1,131 @@
+# ifndef CPPAD_CORE_ATOMIC_FOUR_JAC_SPARSITY_HPP
+# define CPPAD_CORE_ATOMIC_FOUR_JAC_SPARSITY_HPP
+/* --------------------------------------------------------------------------
+CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
+
+CppAD is distributed under the terms of the
+             Eclipse Public License Version 2.0.
+
+This Source Code may also be made available under the following
+Secondary License when the conditions 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 <cppad/core/atomic/four/devel/jac_sparsity.hpp>
+
+/*
+$begin atomic_four_jac_sparsity$$
+$spell
+    Jacobian
+    afun
+    jac
+$$
+
+$section Atomic Function Jacobian Sparsity Patterns$$
+
+$head Syntax$$
+$icode%ok% = %afun%.jac_sparsity(
+    %call_id%, %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_four_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
+requires Jacobian sparsity patterns.)
+
+$head Base$$
+See $cref/Base/atomic_four_call/Base/$$.
+
+$head vector$$
+is the $cref CppAD_vector$$ template class.
+
+$head call_id$$
+See $cref/call_id/atomic_four_call/call_id/$$.
+
+$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_four_ctor/atomic_user/afun/$$.
+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.
+
+$head Example$$
+The following is an example $code jac_sparsity$$ definition taken from
+$cref atomic_four_norm_sq.cpp$$:
+$srcfile%
+    example/atomic_four/norm_sq.cpp%
+    0%// BEGIN JAC_SPARSITY%// END JAC_SPARSITY%0
+%$$
+
+$end
+-----------------------------------------------------------------------------
+*/
+
+namespace CppAD { // BEGIN_CPPAD_NAMESPACE
+// BEGIN_PROTOTYPE
+template <class Base>
+bool atomic_four<Base>::jac_sparsity(
+    size_t                                  call_id      ,
+    bool                                    dependency   ,
+    const vector<bool>&                     select_x     ,
+    const vector<bool>&                     select_y     ,
+    sparse_rc< vector<size_t> >&            pattern_out  )
+// END_PROTOTYPE
+{   return false; }
+} // END_CPPAD_NAMESPACE
+
+# endif
diff --git a/include/cppad/core/atomic/four/rev_depend.hpp b/include/cppad/core/atomic/four/rev_depend.hpp
new file mode 100644
index 000000000..497cf3db5
--- /dev/null
+++ b/include/cppad/core/atomic/four/rev_depend.hpp
@@ -0,0 +1,103 @@
+# ifndef CPPAD_CORE_ATOMIC_FOUR_REV_DEPEND_HPP
+# define CPPAD_CORE_ATOMIC_FOUR_REV_DEPEND_HPP
+/* --------------------------------------------------------------------------
+CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
+
+CppAD is distributed under the terms of the
+             Eclipse Public License Version 2.0.
+
+This Source Code may also be made available under the following
+Secondary License when the conditions 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_four_rev_depend$$
+$spell
+    afun
+    enum
+    cpp
+    taylor.hpp
+$$
+
+$section Atomic Function Reverse Dependency$$
+
+$head Syntax$$
+$icode%ok% = %afun%.rev_depend(%call_id%, %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_four_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_four_call/Base/$$.
+
+$head vector$$
+is the $cref CppAD_vector$$ template class.
+
+$head call_id$$
+See $cref/call_id/atomic_four_call/call_id/$$.
+
+$head depend_x$$
+This vector has size equal to the number of arguments for this atomic function;
+i.e. $icode%n%=%ax%.size()%$$ (see $cref/ax/atomic_four_call/ax/$$).
+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 $icode ax[j]$$ in the corresponding atomic function call.
+
+$subhead Optimize$$
+Parameters and variables,
+that the values of interest do not depend on,
+may get removed by $cref/optimization/optimize/$$.
+The corresponding values in
+$cref/taylor_x/atomic_four_forward/taylor_x/$$
+(after optimization has removed them) are currently zero,
+but perhaps these should be changed back to nan.
+
+$head depend_y$$
+This vector has size equal to the number of results for this atomic function;
+i.e. $icode%m%=%ay%.size()%$$ (see $cref/ay/atomic_four_call/ay/$$).
+For $latex i = 0 , \ldots , m-1$$,
+$icode%depend_y%[%i%]%$$ is true if the values of interest depend
+on the value of $icode ay[i]$$ in the corresponding atomic function call.
+
+$head ok$$
+If this calculation succeeded, $icode ok$$ is true.
+Otherwise, it is false.
+
+$head Example$$
+The following is an example $code rev_depend$$ definition taken from
+$cref atomic_four_norm_sq.cpp$$:
+$srcfile%
+    example/atomic_four/norm_sq.cpp%
+    0%// BEGIN REV_DEPEND%// END REV_DEPEND%0
+%$$
+
+$end
+-----------------------------------------------------------------------------
+*/
+namespace CppAD { // BEGIN_CPPAD_NAMESPACE
+
+// BEGIN_PROTOTYPE
+template <class Base>
+bool atomic_four<Base>::rev_depend(
+    size_t                      call_id     ,
+    vector<bool>&               depend_x    ,
+    const vector<bool>&         depend_y    )
+// END_PROTOTYPE
+{   return false; }
+
+} // END_CPPAD_NAMESPACE
+
+# endif
diff --git a/include/cppad/core/atomic/four/reverse.hpp b/include/cppad/core/atomic/four/reverse.hpp
new file mode 100644
index 000000000..2469968dd
--- /dev/null
+++ b/include/cppad/core/atomic/four/reverse.hpp
@@ -0,0 +1,316 @@
+# ifndef CPPAD_CORE_ATOMIC_FOUR_REVERSE_HPP
+# define CPPAD_CORE_ATOMIC_FOUR_REVERSE_HPP
+/* --------------------------------------------------------------------------
+CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
+
+CppAD is distributed under the terms of the
+             Eclipse Public License Version 2.0.
+
+This Source Code may also be made available under the following
+Secondary License when the conditions 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_four_reverse$$
+$spell
+    sq
+    mul.hpp
+    afun
+    ty
+    px
+    py
+    Taylor
+    const
+    CppAD
+    atx
+    aty
+    apx
+    apy
+    af
+    aparameter
+    enum
+    azmul
+    ataylor
+    apartial
+$$
+
+$section Atomic Function Reverse Mode$$
+
+$head Syntax$$
+
+$subhead Base$$
+$icode%ok% = %afun%.reverse(
+    %call_id%, %select_x%,
+    %order_up%, %taylor_x%, %taylor_y%, %partial_x%, %partial_y%
+)
+%$$
+
+$subhead AD<Base>$$
+$icode%ok% = %afun%.reverse(
+    %call_id%, %select_x%,
+    %order_up%, %ataylor_x%, %ataylor_y%, %apartial_x%, %apartial_y%
+)
+%$$
+
+$head Prototype$$
+
+$subhead Base$$
+$srcthisfile%0%// BEGIN_PROTOTYPE_BASE%// END_PROTOTYPE_BASE%1
+%$$
+
+$subhead AD<Base>$$
+$srcthisfile%0%// BEGIN_PROTOTYPE_AD_BASE%// END_PROTOTYPE_AD_BASE%1
+%$$
+
+$head Base$$
+see $cref/Base/atomic_four_call/Base/$$.
+
+$head vector$$
+is the $cref CppAD_vector$$ template class.
+
+
+$head Usage$$
+
+$subhead Base$$
+This syntax is used by $icode%f%.Reverse%$$ where $icode f$$ has prototype
+$codei%
+    ADFun<%Base%> %f%
+%$$
+and atomic function $icode afun$$ is used in $icode f$$;
+see $cref/Base/atomic_four_call/Base/$$.
+
+$subhead AD<Base>$$
+This syntax is used by $icode%af%.Reverse%$$ where $icode af$$ has prototype
+$codei%
+    ADFun< AD<%Base%> , %Base% > %af%
+%$$
+and the atomic function $icode afun$$ is used in
+$icode af$$; see $cref base2ad$$.
+
+$head Implementation$$
+This function must be defined if
+$cref/afun/atomic_four_ctor/atomic_user/afun/$$ is
+used during the recording of 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 call_id$$
+See $cref/call_id/atomic_four_call/call_id/$$.
+
+$head select_x$$
+This argument has size equal to the number of arguments to this
+atomic function; i.e. the size of $cref/ax/atomic_four_call/ax/$$.
+It specifies which components of $icode x$$ the corresponding
+partial derivatives $icode partial_x$$ must be computed.
+
+$head order_up$$
+This argument is one greater than highest order Taylor coefficient that
+computing the derivative of.
+
+$head q$$
+We use the notation $icode%q% = %order_up% + 1%$$ below.
+This is one less than the number of Taylor coefficients for each component
+of $icode x$$ and $icode y$$.
+
+$head taylor_x$$
+The size of $icode taylor_x$$ is $icode%q%*%n%$$.
+For $latex j = 0 , \ldots , n-1$$ and $latex k = 0 , \ldots , q-1$$,
+we use the Taylor coefficient notation
+$latex \[
+\begin{array}{rcl}
+    x_j^k    & = & \R{taylor\_x} [ j * q + k ]
+    \\
+    X_j (t)  & = & x_j^0 + x_j^1 t^1 + \cdots + x_j^{q-1} t^{q-1}
+\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$$ is a parameter,
+$codei%
+    %type_x%[%j%] < CppAD::variable_enum
+%$$
+In this case, for $icode%k% > 0%$$,
+$codei%
+    %taylor_x%[ %j% * %q% + %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 $icode%q%*%m%$$.
+For $latex i = 0 , \ldots , m-1$$ and $latex k = 0 , \ldots , q-1$$,
+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-1} t^{q-1} + o ( t^{q-1} )
+    \\
+    y_i^k    & = & \R{taylor\_y} [ i * q + k ]
+\end{array}
+\] $$
+where $latex o( t^{q-1} ) / t^{q-1} \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}$$ for
+$latex \[
+    \{ x_j^k \W{:} j = 0 , \ldots , n-1, k = 0 , \ldots , q-1 \}
+\]$$
+We use the notation $latex \{ y_i^k \} \in \B{R}^{m \times q}$$ for
+$latex \[
+    \{ y_i^k \W{:} i = 0 , \ldots , m-1, k = 0 , \ldots , q-1 \}
+\]$$
+We use
+$latex F : \B{R}^{n \times q} \rightarrow \B{R}^{m \times q}$$ by
+to denote the function corresponding to the forward mode calculations
+$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$$; i.e.,
+it 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} \rightarrow \B{R}$$
+to denote an arbitrary scalar valued function of $latex \{ y_i^k \}$$.
+We use $latex H : \B{R}^{n \times q} \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 $icode%q%*%m%%$$.
+For $latex i = 0 , \ldots , m-1$$, $latex k = 0 , \ldots , q-1$$,
+$latex \[
+    \R{partial\_y} [ i * q + 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 $icode%q%*%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-1$$,
+$latex \[
+\begin{array}{rcl}
+\R{partial\_x} [ j * q + \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-1}
+\sum_{i=0}^{m-1}
+( \partial G / \partial y_i^k ) ( \partial y_i^k / \partial x_j^\ell )
+\\
+& = &
+\sum_{k=\ell}^{q-1}
+\sum_{i=0}^{m-1}
+\R{partial\_y}[ i * q + 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 azmul$$
+An $cref/optimized/optimize/$$ function will use zero
+for values in $icode taylor_x$$ and $icode taylor_y$$ that are
+not necessary in the current context.
+If you divide by these values when computing
+$latex ( \partial F_i^k / \partial x_j^\ell )$$ you could get an nan
+if the corresponding value in $icode partial_y$$ is zero.
+To be careful, if you do divide by
+$icode taylor_x$$ or $icode taylor_y$$, use $cref azmul$$
+for to avoid zero over zero calculations.
+
+$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.
+
+$head Example$$
+The following is an example $code reverse$$ definition taken from
+$cref atomic_four_norm_sq.cpp$$:
+$srcfile%
+    example/atomic_four/norm_sq.cpp%
+    0%// BEGIN REVERSE%// END REVERSE%0
+%$$
+
+$head Examples$$
+The file $cref atomic_four_norm_sq.cpp$$
+contains an example that defines this routine.
+
+$end
+-----------------------------------------------------------------------------
+*/
+
+namespace CppAD { // BEGIN_CPPAD_NAMESPACE
+
+// BEGIN_PROTOTYPE_BASE
+template <class Base>
+bool atomic_four<Base>::reverse(
+    size_t                      call_id     ,
+    const vector<bool>&         select_x    ,
+    size_t                      order_up    ,
+    const vector<Base>&         taylor_x    ,
+    const vector<Base>&         taylor_y    ,
+    vector<Base>&               partial_x   ,
+    const vector<Base>&         partial_y   )
+// END_PROTOTYPE_BASE
+{   return false; }
+
+// BEGIN_PROTOTYPE_AD_BASE
+template <class Base>
+bool atomic_four<Base>::reverse(
+    size_t                          call_id      ,
+    const vector<bool>&             select_x     ,
+    size_t                          order_up     ,
+    const vector< AD<Base> >&       ataylor_x    ,
+    const vector< AD<Base> >&       ataylor_y    ,
+    vector< AD<Base> >&             apartial_x   ,
+    const vector< AD<Base> >&       apartial_y   )
+// END_PROTOTYPE_AD_BASE
+{   return false; }
+
+} // END_CPPAD_NAMESPACE
+# endif
diff --git a/include/cppad/core/atomic/atomic_one.hpp b/include/cppad/core/atomic/one/atomic.hpp
similarity index 99%
rename from include/cppad/core/atomic/atomic_one.hpp
rename to include/cppad/core/atomic/one/atomic.hpp
index 9b0bd1552..f379eebe5 100644
--- a/include/cppad/core/atomic/atomic_one.hpp
+++ b/include/cppad/core/atomic/one/atomic.hpp
@@ -1,7 +1,7 @@
-# ifndef CPPAD_CORE_ATOMIC_ATOMIC_ONE_HPP
-# define CPPAD_CORE_ATOMIC_ATOMIC_ONE_HPP
+# ifndef CPPAD_CORE_ATOMIC_ONE_ATOMIC_HPP
+# define CPPAD_CORE_ATOMIC_ONE_ATOMIC_HPP
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-18 Bradley M. Bell
+CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
 
 CppAD is distributed under the terms of the
              Eclipse Public License Version 2.0.
diff --git a/include/cppad/core/atomic/three_afun.hpp b/include/cppad/core/atomic/three/afun.hpp
similarity index 95%
rename from include/cppad/core/atomic/three_afun.hpp
rename to include/cppad/core/atomic/three/afun.hpp
index 2e468105e..4c2785c51 100644
--- a/include/cppad/core/atomic/three_afun.hpp
+++ b/include/cppad/core/atomic/three/afun.hpp
@@ -1,7 +1,7 @@
 # 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: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
 
 CppAD is distributed under the terms of the
              Eclipse Public License Version 2.0.
@@ -213,11 +213,16 @@ void atomic_three<Base>::operator()(
     }
 # endif
     if( record_dynamic)
-    {   tape->Rec_.put_dyn_atomic(tape_id, index_, type_x, type_y, ax, ay);
+    {   size_t call_id = 0;
+        tape->Rec_.put_dyn_atomic(
+            tape_id, index_, call_id, 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);
+    {   size_t call_id = 0; // atomic_three does not user call_id
+        tape->Rec_.put_var_atomic(
+            tape_id, index_, call_id, type_x, type_y, ax, ay);
     }
 # ifndef NDEBUG
     for(size_t i = 0; i < m; ++i) switch( type_y[i] )
diff --git a/include/cppad/core/atomic/atomic_three.hpp b/include/cppad/core/atomic/three/atomic.hpp
similarity index 90%
rename from include/cppad/core/atomic/atomic_three.hpp
rename to include/cppad/core/atomic/three/atomic.hpp
index 1afae080f..5879bf51d 100644
--- a/include/cppad/core/atomic/atomic_three.hpp
+++ b/include/cppad/core/atomic/three/atomic.hpp
@@ -1,7 +1,7 @@
-# ifndef CPPAD_CORE_ATOMIC_ATOMIC_THREE_HPP
-# define CPPAD_CORE_ATOMIC_ATOMIC_THREE_HPP
+# ifndef CPPAD_CORE_ATOMIC_THREE_ATOMIC_HPP
+# define CPPAD_CORE_ATOMIC_THREE_ATOMIC_HPP
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
+CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
 
 CppAD is distributed under the terms of the
              Eclipse Public License Version 2.0.
@@ -12,7 +12,7 @@ in the Eclipse Public License, Version 2.0 are satisfied:
       GNU General Public License, Version 2.0 or later.
 ---------------------------------------------------------------------------- */
 /*
-$begin atomic_three$$
+$begin atomic_three_define$$
 $spell
     taylor
     ctor
@@ -83,9 +83,9 @@ 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
+If the function $latex g(x)$$ is used many times during the recording
 of an $cref ADFun$$ object,
-using an atomic version of $latex g(x)$$ removed the need for repeated
+using an atomic version of $latex g(x)$$ removes the need for repeated
 copies of the corresponding $codei%AD<%Base%>%$$ operations and variables
 in the recording.
 
@@ -108,7 +108,8 @@ In addition,
 $code constant_enum < dynamic_enum < variable_enum$$.
 
 $head Virtual Functions$$
-The $cref/callback functions/atomic_three/Syntax/Class Member Callbacks/$$
+The
+$cref/callback functions/atomic_three_define/Syntax/Class Member Callbacks/$$
 are implemented by defining the virtual functions in the
 $icode atomic_user$$ class.
 These functions compute derivatives,
@@ -126,9 +127,11 @@ $icode%ok% == false%$$ unless you require
 forward mode calculation of second derivatives.
 
 $head Base$$
-This is the type of the elements of
+This is the base 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.
+in the corresponding $icode%afun%(%ax%, %ay%)%$$ call; i.e.,
+the elements of $icode ax$$ and $icode ay$$ have type
+$codei%AD<%Base%>%$$.
 
 $head parameter_x$$
 All the virtual functions include this argument which has prototype
@@ -179,28 +182,14 @@ $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
+$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
@@ -474,13 +463,13 @@ public:
 } // END_CPPAD_NAMESPACE
 
 // member functions
-# 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_rev_depend.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/ctor.hpp>
+# include <cppad/core/atomic/three/afun.hpp>
+# include <cppad/core/atomic/three/for_type.hpp>
+# include <cppad/core/atomic/three/rev_depend.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>
 
 # endif
diff --git a/include/cppad/core/atomic/three/atomic.omh b/include/cppad/core/atomic/three/atomic.omh
new file mode 100644
index 000000000..a3721627e
--- /dev/null
+++ b/include/cppad/core/atomic/three/atomic.omh
@@ -0,0 +1,21 @@
+/* --------------------------------------------------------------------------
+CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
+
+  CppAD is distributed under the terms of the
+               Eclipse Public License Version 2.0.
+
+  This Source Code may also be made available under the following
+  Secondary License when the conditions 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$$
+
+$section Atomic AD Functions: Third Generation$$
+
+$childtable%
+    include/cppad/core/atomic/three/atomic.hpp%
+    example/atomic_three/atomic_three.omh
+%$$
+
+$end
diff --git a/include/cppad/core/atomic/three_ctor.hpp b/include/cppad/core/atomic/three/ctor.hpp
similarity index 98%
rename from include/cppad/core/atomic/three_ctor.hpp
rename to include/cppad/core/atomic/three/ctor.hpp
index 466720639..85a6149a6 100644
--- a/include/cppad/core/atomic/three_ctor.hpp
+++ b/include/cppad/core/atomic/three/ctor.hpp
@@ -1,7 +1,7 @@
 # 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: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
 
 CppAD is distributed under the terms of the
              Eclipse Public License Version 2.0.
diff --git a/include/cppad/core/atomic/three_for_type.hpp b/include/cppad/core/atomic/three/for_type.hpp
similarity index 93%
rename from include/cppad/core/atomic/three_for_type.hpp
rename to include/cppad/core/atomic/three/for_type.hpp
index cb1cc31eb..107f74abc 100644
--- a/include/cppad/core/atomic/three_for_type.hpp
+++ b/include/cppad/core/atomic/three/for_type.hpp
@@ -1,7 +1,7 @@
 # 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: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
 
 CppAD is distributed under the terms of the
              Eclipse Public License Version 2.0.
@@ -44,13 +44,13 @@ 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/$$.
+See $cref/Base/atomic_three_define/Base/$$.
 
 $head parameter_x$$
-See $cref/parameter_x/atomic_three/parameter_x/$$.
+See $cref/parameter_x/atomic_three_define/parameter_x/$$.
 
 $head type_x$$
-See $cref/type_x/atomic_three/type_x/$$.
+See $cref/type_x/atomic_three_define/type_x/$$.
 
 $head type_y$$
 This vector has size equal to the number of results for this atomic function;
diff --git a/include/cppad/core/atomic/three_forward.hpp b/include/cppad/core/atomic/three/forward.hpp
similarity index 97%
rename from include/cppad/core/atomic/three_forward.hpp
rename to include/cppad/core/atomic/three/forward.hpp
index f35654bb5..0f3b39823 100644
--- a/include/cppad/core/atomic/three_forward.hpp
+++ b/include/cppad/core/atomic/three/forward.hpp
@@ -1,7 +1,7 @@
 # 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: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
 
 CppAD is distributed under the terms of the
              Eclipse Public License Version 2.0.
@@ -77,15 +77,15 @@ $cref/forward/Forward/$$ mode calculations
 (order zero must be implemented).
 
 $head parameter_x$$
-See $cref/parameter_x/atomic_three/parameter_x/$$.
+See $cref/parameter_x/atomic_three_define/parameter_x/$$.
 
 $head aparameter_x$$
 The specifications for $icode aparameter_x$$
-is the same as for $cref/parameter_x/atomic_three/parameter_x/$$
+is the same as for $cref/parameter_x/atomic_three_define/parameter_x/$$
 (only the type of $icode ataylor_x$$ is different).
 
 $head type_x$$
-See $cref/type_x/atomic_three/type_x/$$.
+See $cref/type_x/atomic_three_define/type_x/$$.
 
 $head need_y$$
 One can ignore this argument and compute all the $icode taylor_y$$
@@ -218,7 +218,7 @@ 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)$$,
+its first derivative $latex g^{(1)} (x)$$,
 and it component wise Hessian $latex g_i^{(2)} (x)$$.
 Then you can compute $icode taylor_x$$ using the following formulas:
 $latex \[
diff --git a/include/cppad/core/atomic/three_hes_sparsity.hpp b/include/cppad/core/atomic/three/hes_sparsity.hpp
similarity index 98%
rename from include/cppad/core/atomic/three_hes_sparsity.hpp
rename to include/cppad/core/atomic/three/hes_sparsity.hpp
index 03445cbe2..d654e982c 100644
--- a/include/cppad/core/atomic/three_hes_sparsity.hpp
+++ b/include/cppad/core/atomic/three/hes_sparsity.hpp
@@ -1,7 +1,7 @@
 # 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: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
 
 CppAD is distributed under the terms of the
              Eclipse Public License Version 2.0.
@@ -40,10 +40,10 @@ $head Base$$
 See $cref/Base/atomic_three_afun/Base/$$.
 
 $head parameter_x$$
-See $cref/parameter_x/atomic_three/parameter_x/$$.
+See $cref/parameter_x/atomic_three_define/parameter_x/$$.
 
 $head type_x$$
-See $cref/type_x/atomic_three/type_x/$$.
+See $cref/type_x/atomic_three_define/type_x/$$.
 
 $head select_x$$
 This argument has size equal to the number of arguments to this
diff --git a/include/cppad/core/atomic/three_jac_sparsity.hpp b/include/cppad/core/atomic/three/jac_sparsity.hpp
similarity index 98%
rename from include/cppad/core/atomic/three_jac_sparsity.hpp
rename to include/cppad/core/atomic/three/jac_sparsity.hpp
index 234a3d672..ddaec793c 100644
--- a/include/cppad/core/atomic/three_jac_sparsity.hpp
+++ b/include/cppad/core/atomic/three/jac_sparsity.hpp
@@ -1,7 +1,7 @@
 # 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: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
 
 CppAD is distributed under the terms of the
              Eclipse Public License Version 2.0.
@@ -42,10 +42,10 @@ $head Base$$
 See $cref/Base/atomic_three_afun/Base/$$.
 
 $head parameter_x$$
-See $cref/parameter_x/atomic_three/parameter_x/$$.
+See $cref/parameter_x/atomic_three_define/parameter_x/$$.
 
 $head type_x$$
-See $cref/type_x/atomic_three/type_x/$$.
+See $cref/type_x/atomic_three_define/type_x/$$.
 
 $head dependency$$
 If $icode dependency$$ is true,
diff --git a/include/cppad/core/atomic/three_rev_depend.hpp b/include/cppad/core/atomic/three/rev_depend.hpp
similarity index 92%
rename from include/cppad/core/atomic/three_rev_depend.hpp
rename to include/cppad/core/atomic/three/rev_depend.hpp
index d05e91a17..2137c57a8 100644
--- a/include/cppad/core/atomic/three_rev_depend.hpp
+++ b/include/cppad/core/atomic/three/rev_depend.hpp
@@ -1,7 +1,7 @@
 # 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: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
 
 CppAD is distributed under the terms of the
              Eclipse Public License Version 2.0.
@@ -44,10 +44,10 @@ $head Base$$
 See $cref/Base/atomic_three_afun/Base/$$.
 
 $head parameter_x$$
-See $cref/parameter_x/atomic_three/parameter_x/$$.
+See $cref/parameter_x/atomic_three_define/parameter_x/$$.
 
 $head type_x$$
-See $cref/type_x/atomic_three/type_x/$$.
+See $cref/type_x/atomic_three_define/type_x/$$.
 
 $head depend_x$$
 This vector has size equal to the number of arguments for this atomic function;
@@ -58,10 +58,12 @@ 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,
+
+$subhead Optimize$$
+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/$$,
+The corresponding values in $cref/parameter_x/atomic_three_define/parameter_x/$$,
 and $cref/taylor_x/atomic_three_forward/taylor_x/$$
 (after optimization has removed them) are not specified.
 
diff --git a/include/cppad/core/atomic/three_reverse.hpp b/include/cppad/core/atomic/three/reverse.hpp
similarity index 92%
rename from include/cppad/core/atomic/three_reverse.hpp
rename to include/cppad/core/atomic/three/reverse.hpp
index 99dd6091d..58b31caa9 100644
--- a/include/cppad/core/atomic/three_reverse.hpp
+++ b/include/cppad/core/atomic/three/reverse.hpp
@@ -1,7 +1,7 @@
 # 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: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
 
 CppAD is distributed under the terms of the
              Eclipse Public License Version 2.0.
@@ -30,14 +30,13 @@ $spell
     af
     aparameter
     enum
-$$
-
-$section Atomic Function Reverse Mode$$
-$spell
+    azmul
     ataylor
     apartial
 $$
 
+$section Atomic Function Reverse Mode$$
+
 $head Base$$
 This syntax is used by $icode%f%.Reverse%$$ where $icode f$$ has prototype
 $codei%
@@ -86,15 +85,15 @@ 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/$$.
+See $cref/parameter_x/atomic_three_define/parameter_x/$$.
 
 $head aparameter_x$$
 The specifications for $icode aparameter_x$$
-is the same as for $cref/parameter_x/atomic_three/parameter_x/$$
+is the same as for $cref/parameter_x/atomic_three_define/parameter_x/$$
 (only the type of $icode ataylor_x$$ is different).
 
 $head type_x$$
-See $cref/type_x/atomic_three/type_x/$$.
+See $cref/type_x/atomic_three_define/type_x/$$.
 
 $head order_up$$
 This argument specifies the highest order Taylor coefficient that
@@ -141,7 +140,6 @@ The specifications for $icode ataylor_x$$ is the same as for $icode taylor_x$$
 
 $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 \[
@@ -239,7 +237,7 @@ 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
+For the $cref/Base/atomic_three_reverse/Base/$$ prototype, 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$$.
@@ -247,6 +245,18 @@ This can be used,
 in a similar way to $cref/need_y/atomic_three_forward/need_y/$$,
 to avoid unnecessary operations.
 
+$subhead azmul$$
+An $cref/optimized/optimize/$$ function will use zero
+for values in $icode taylor_x$$ and $icode taylor_y$$ that are
+not necessary in the current context.
+If you divide by these values when computing
+$latex ( \partial F_i^k / \partial x_j^\ell )$$ you could get an nan
+if the corresponding value in $icode partial_y$$ is zero.
+To be careful, if you do divide by
+$icode taylor_x$$ or $icode taylor_y$$, use $cref azmul$$
+for to avoid zero over zero calculations.
+
+
 $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).
diff --git a/include/cppad/core/atomic/two_afun.hpp b/include/cppad/core/atomic/two/afun.hpp
similarity index 99%
rename from include/cppad/core/atomic/two_afun.hpp
rename to include/cppad/core/atomic/two/afun.hpp
index 8aba0f376..576f74b51 100644
--- a/include/cppad/core/atomic/two_afun.hpp
+++ b/include/cppad/core/atomic/two/afun.hpp
@@ -1,7 +1,7 @@
 # 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: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
 
 CppAD is distributed under the terms of the
              Eclipse Public License Version 2.0.
diff --git a/include/cppad/core/atomic/atomic_two.hpp b/include/cppad/core/atomic/two/atomic.hpp
similarity index 94%
rename from include/cppad/core/atomic/atomic_two.hpp
rename to include/cppad/core/atomic/two/atomic.hpp
index 13418999f..c0dfa171a 100644
--- a/include/cppad/core/atomic/atomic_two.hpp
+++ b/include/cppad/core/atomic/two/atomic.hpp
@@ -1,7 +1,7 @@
-# ifndef CPPAD_CORE_ATOMIC_ATOMIC_TWO_HPP
-# define CPPAD_CORE_ATOMIC_ATOMIC_TWO_HPP
+# ifndef CPPAD_CORE_ATOMIC_TWO_ATOMIC_HPP
+# define CPPAD_CORE_ATOMIC_TWO_ATOMIC_HPP
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
+CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
 
 CppAD is distributed under the terms of the
              Eclipse Public License Version 2.0.
@@ -94,16 +94,16 @@ $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
+    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
@@ -598,16 +598,16 @@ public:
 } // END_CPPAD_NAMESPACE
 
 // functitons implemented in cppad/core/atomic_base files
-# 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_rev_depend.hpp>
-# include <cppad/core/atomic/two_clear.hpp>
+# 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/rev_depend.hpp>
+# include <cppad/core/atomic/two/clear.hpp>
 
 # endif
diff --git a/include/cppad/core/atomic/two_clear.hpp b/include/cppad/core/atomic/two/clear.hpp
similarity index 97%
rename from include/cppad/core/atomic/two_clear.hpp
rename to include/cppad/core/atomic/two/clear.hpp
index 0223be734..74475598f 100644
--- a/include/cppad/core/atomic/two_clear.hpp
+++ b/include/cppad/core/atomic/two/clear.hpp
@@ -1,7 +1,7 @@
 # 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: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
 
 CppAD is distributed under the terms of the
              Eclipse Public License Version 2.0.
diff --git a/include/cppad/core/atomic/two_ctor.hpp b/include/cppad/core/atomic/two/ctor.hpp
similarity index 98%
rename from include/cppad/core/atomic/two_ctor.hpp
rename to include/cppad/core/atomic/two/ctor.hpp
index c8f248012..120e735d5 100644
--- a/include/cppad/core/atomic/two_ctor.hpp
+++ b/include/cppad/core/atomic/two/ctor.hpp
@@ -1,7 +1,7 @@
 # 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: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
 
 CppAD is distributed under the terms of the
              Eclipse Public License Version 2.0.
diff --git a/include/cppad/core/atomic/two_for_sparse_hes.hpp b/include/cppad/core/atomic/two/for_sparse_hes.hpp
similarity index 99%
rename from include/cppad/core/atomic/two_for_sparse_hes.hpp
rename to include/cppad/core/atomic/two/for_sparse_hes.hpp
index e0f1ed408..64aac2d2d 100644
--- a/include/cppad/core/atomic/two_for_sparse_hes.hpp
+++ b/include/cppad/core/atomic/two/for_sparse_hes.hpp
@@ -1,7 +1,7 @@
 # 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: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
 
 CppAD is distributed under the terms of the
              Eclipse Public License Version 2.0.
diff --git a/include/cppad/core/atomic/two_for_sparse_jac.hpp b/include/cppad/core/atomic/two/for_sparse_jac.hpp
similarity index 99%
rename from include/cppad/core/atomic/two_for_sparse_jac.hpp
rename to include/cppad/core/atomic/two/for_sparse_jac.hpp
index 62fa426fe..582546e97 100644
--- a/include/cppad/core/atomic/two_for_sparse_jac.hpp
+++ b/include/cppad/core/atomic/two/for_sparse_jac.hpp
@@ -1,7 +1,7 @@
 # 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: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
 
 CppAD is distributed under the terms of the
              Eclipse Public License Version 2.0.
diff --git a/include/cppad/core/atomic/two_forward.hpp b/include/cppad/core/atomic/two/forward.hpp
similarity index 99%
rename from include/cppad/core/atomic/two_forward.hpp
rename to include/cppad/core/atomic/two/forward.hpp
index 0b4ed9c24..449a3b344 100644
--- a/include/cppad/core/atomic/two_forward.hpp
+++ b/include/cppad/core/atomic/two/forward.hpp
@@ -1,7 +1,7 @@
 # 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: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
 
 CppAD is distributed under the terms of the
              Eclipse Public License Version 2.0.
diff --git a/include/cppad/core/atomic/two_option.hpp b/include/cppad/core/atomic/two/option.hpp
similarity index 98%
rename from include/cppad/core/atomic/two_option.hpp
rename to include/cppad/core/atomic/two/option.hpp
index 5cb1990f8..aad832097 100644
--- a/include/cppad/core/atomic/two_option.hpp
+++ b/include/cppad/core/atomic/two/option.hpp
@@ -1,7 +1,7 @@
 # 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: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
 
 CppAD is distributed under the terms of the
              Eclipse Public License Version 2.0.
diff --git a/include/cppad/core/atomic/two_rev_depend.hpp b/include/cppad/core/atomic/two/rev_depend.hpp
similarity index 97%
rename from include/cppad/core/atomic/two_rev_depend.hpp
rename to include/cppad/core/atomic/two/rev_depend.hpp
index c6b02f2c4..4f979623c 100644
--- a/include/cppad/core/atomic/two_rev_depend.hpp
+++ b/include/cppad/core/atomic/two/rev_depend.hpp
@@ -1,7 +1,7 @@
 # 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: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
 
 CppAD is distributed under the terms of the
              Eclipse Public License Version 2.0.
diff --git a/include/cppad/core/atomic/two_rev_sparse_hes.hpp b/include/cppad/core/atomic/two/rev_sparse_hes.hpp
similarity index 99%
rename from include/cppad/core/atomic/two_rev_sparse_hes.hpp
rename to include/cppad/core/atomic/two/rev_sparse_hes.hpp
index 27ac3804d..8ccf7bd8b 100644
--- a/include/cppad/core/atomic/two_rev_sparse_hes.hpp
+++ b/include/cppad/core/atomic/two/rev_sparse_hes.hpp
@@ -1,7 +1,7 @@
 # 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: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
 
 CppAD is distributed under the terms of the
              Eclipse Public License Version 2.0.
diff --git a/include/cppad/core/atomic/two_rev_sparse_jac.hpp b/include/cppad/core/atomic/two/rev_sparse_jac.hpp
similarity index 99%
rename from include/cppad/core/atomic/two_rev_sparse_jac.hpp
rename to include/cppad/core/atomic/two/rev_sparse_jac.hpp
index 36d16a40c..070500fc7 100644
--- a/include/cppad/core/atomic/two_rev_sparse_jac.hpp
+++ b/include/cppad/core/atomic/two/rev_sparse_jac.hpp
@@ -1,7 +1,7 @@
 # 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: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
 
 CppAD is distributed under the terms of the
              Eclipse Public License Version 2.0.
diff --git a/include/cppad/core/atomic/two_reverse.hpp b/include/cppad/core/atomic/two/reverse.hpp
similarity index 99%
rename from include/cppad/core/atomic/two_reverse.hpp
rename to include/cppad/core/atomic/two/reverse.hpp
index 43270b17f..c02582e94 100644
--- a/include/cppad/core/atomic/two_reverse.hpp
+++ b/include/cppad/core/atomic/two/reverse.hpp
@@ -1,7 +1,7 @@
 # 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: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
 
 CppAD is distributed under the terms of the
              Eclipse Public License Version 2.0.
diff --git a/include/cppad/core/capacity_order.hpp b/include/cppad/core/capacity_order.hpp
index 2ec0ee245..4131ad13d 100644
--- a/include/cppad/core/capacity_order.hpp
+++ b/include/cppad/core/capacity_order.hpp
@@ -1,7 +1,7 @@
 # ifndef CPPAD_CORE_CAPACITY_ORDER_HPP
 # define CPPAD_CORE_CAPACITY_ORDER_HPP
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-18 Bradley M. Bell
+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.
@@ -28,7 +28,7 @@ $head Syntax$$
 $icode%f%.capacity_order(%c%)%$$
 
 $subhead See Also$$
-$cref seq_property$$
+$cref fun_property$$
 
 $head Purpose$$
 The Taylor coefficients calculated by $cref Forward$$ mode calculations
diff --git a/include/cppad/core/chkpoint_one/chkpoint_one.hpp b/include/cppad/core/chkpoint_one/chkpoint_one.hpp
index 7ce66cfc6..98cca826d 100644
--- a/include/cppad/core/chkpoint_one/chkpoint_one.hpp
+++ b/include/cppad/core/chkpoint_one/chkpoint_one.hpp
@@ -1,7 +1,7 @@
 # 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: C++ Algorithmic Differentiation: Copyright (C) 2003-21 Bradley M. Bell
 
 CppAD is distributed under the terms of the
              Eclipse Public License Version 2.0.
@@ -194,7 +194,7 @@ 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
+It is the $cref/size_var/fun_property/size_var/$$ for the
 $codei%ADFun<%Base%>%$$ object is used to store the operation sequence
 corresponding to $icode algo$$.
 
diff --git a/include/cppad/core/chkpoint_two/chkpoint_two.hpp b/include/cppad/core/chkpoint_two/chkpoint_two.hpp
index b89b0283e..5aadb267b 100644
--- a/include/cppad/core/chkpoint_two/chkpoint_two.hpp
+++ b/include/cppad/core/chkpoint_two/chkpoint_two.hpp
@@ -1,7 +1,7 @@
 # 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: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
 
 CppAD is distributed under the terms of the
              Eclipse Public License Version 2.0.
@@ -74,7 +74,7 @@ $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/$$
+$cref/virtual functions/atomic_three_define/Virtual Functions/$$
 and hence its source code,
 $codei%
     include/cppad/core/chkpoint_two/chkpoint_two.hpp
diff --git a/include/cppad/core/chkpoint_two/dynamic.hpp b/include/cppad/core/chkpoint_two/dynamic.hpp
index 6ce7f7025..97ad91960 100644
--- a/include/cppad/core/chkpoint_two/dynamic.hpp
+++ b/include/cppad/core/chkpoint_two/dynamic.hpp
@@ -1,7 +1,7 @@
 # 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: C++ Algorithmic Differentiation: Copyright (C) 2003-21 Bradley M. Bell
 
 CppAD is distributed under the terms of the
              Eclipse Public License Version 2.0.
@@ -48,7 +48,7 @@ $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/$$.
+$cref/fun.size_dyn_ind()/fun_property/size_dyn_par/$$.
 This only affects the copy of $icode fun$$ used by $icode chk_fun$$.
 
 $head Multi-Threading$$
diff --git a/include/cppad/core/con_dyn_var.hpp b/include/cppad/core/con_dyn_var.hpp
index b31db2828..47500a566 100644
--- a/include/cppad/core/con_dyn_var.hpp
+++ b/include/cppad/core/con_dyn_var.hpp
@@ -1,7 +1,7 @@
 # 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: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
 
 CppAD is distributed under the terms of the
              Eclipse Public License Version 2.0.
@@ -99,7 +99,7 @@ namespace CppAD {
     // Constant
     template <class Base>
     bool Constant(const AD<Base> &x)
-    {   CPPAD_ASSERT_UNKNOWN( x.tape_id_== 0 || x.ad_type_ != constant_enum );
+    {   CPPAD_ASSERT_AD_TYPE( x );
         if( x.tape_id_ == 0 )
             return true;
         //
@@ -109,7 +109,7 @@ namespace CppAD {
     //
     template <class Base>
     bool Constant(const VecAD<Base> &x)
-    {   CPPAD_ASSERT_UNKNOWN( x.tape_id_== 0 || x.ad_type_ != constant_enum );
+    {   CPPAD_ASSERT_AD_TYPE( x );
         if( x.tape_id_ == 0 )
             return true;
         //
@@ -120,7 +120,7 @@ namespace CppAD {
     // Dynamic
     template <class Base>
     bool Dynamic(const AD<Base> &x)
-    {   CPPAD_ASSERT_UNKNOWN( x.tape_id_ == 0 || x.ad_type_ != constant_enum );
+    {   CPPAD_ASSERT_AD_TYPE( x );
         if( (x.tape_id_ == 0) | (x.ad_type_ != dynamic_enum) )
             return false;
         //
@@ -130,7 +130,7 @@ namespace CppAD {
     //
     template <class Base>
     bool Dynamic(const VecAD<Base> &x)
-    {   CPPAD_ASSERT_UNKNOWN( x.tape_id_ == 0 || x.ad_type_ != constant_enum );
+    {   CPPAD_ASSERT_AD_TYPE( x );
         if( (x.tape_id_ == 0) | (x.ad_type_ != dynamic_enum) )
             return false;
         //
@@ -141,7 +141,7 @@ namespace CppAD {
     // Parameter
     template <class Base>
     bool Parameter(const AD<Base> &x)
-    {   CPPAD_ASSERT_UNKNOWN( x.tape_id_ == 0 || x.ad_type_ != constant_enum );
+    {   CPPAD_ASSERT_AD_TYPE( x );
         if( (x.tape_id_ == 0) | (x.ad_type_ == dynamic_enum) )
             return true;
         //
@@ -151,7 +151,7 @@ namespace CppAD {
     //
     template <class Base>
     bool Parameter(const VecAD<Base> &x)
-    {   CPPAD_ASSERT_UNKNOWN( x.tape_id_ == 0 || x.ad_type_ != constant_enum );
+    {   CPPAD_ASSERT_AD_TYPE( x );
         if( (x.tape_id_ == 0) | (x.ad_type_ == dynamic_enum) )
             return true;
         //
@@ -162,7 +162,7 @@ namespace CppAD {
     // Variable
     template <class Base>
     bool Variable(const AD<Base> &x)
-    {   CPPAD_ASSERT_UNKNOWN( x.tape_id_ == 0 || x.ad_type_ != constant_enum );
+    {   CPPAD_ASSERT_AD_TYPE( x );
         if( (x.tape_id_ == 0) | (x.ad_type_ != variable_enum) )
             return false;
         //
@@ -172,7 +172,7 @@ namespace CppAD {
     //
     template <class Base>
     bool Variable(const VecAD<Base> &x)
-    {   CPPAD_ASSERT_UNKNOWN( x.tape_id_ == 0 || x.ad_type_ != constant_enum );
+    {   CPPAD_ASSERT_AD_TYPE( x );
         if( (x.tape_id_ == 0) | (x.ad_type_ != variable_enum) )
             return false;
         //
diff --git a/include/cppad/core/dependent.hpp b/include/cppad/core/dependent.hpp
index 96d4219df..0e266705b 100644
--- a/include/cppad/core/dependent.hpp
+++ b/include/cppad/core/dependent.hpp
@@ -1,7 +1,7 @@
 # ifndef CPPAD_CORE_DEPENDENT_HPP
 # define CPPAD_CORE_DEPENDENT_HPP
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
+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.
@@ -45,9 +45,9 @@ $latex \[
 \] $$
 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.
+$cref/domain/fun_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
+$cref/range/fun_property/Range/$$ space for the operation sequence
 (which is determined by the size of $icode y$$).
 
 $head f$$
diff --git a/include/cppad/core/div.hpp b/include/cppad/core/div.hpp
index 2d36d4453..db714ee46 100644
--- a/include/cppad/core/div.hpp
+++ b/include/cppad/core/div.hpp
@@ -1,7 +1,7 @@
 # ifndef CPPAD_CORE_DIV_HPP
 # define CPPAD_CORE_DIV_HPP
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
+CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
 
 CppAD is distributed under the terms of the
              Eclipse Public License Version 2.0.
diff --git a/include/cppad/core/div_eq.hpp b/include/cppad/core/div_eq.hpp
index 00ccc87b7..365b90e9d 100644
--- a/include/cppad/core/div_eq.hpp
+++ b/include/cppad/core/div_eq.hpp
@@ -1,7 +1,7 @@
 # ifndef CPPAD_CORE_DIV_EQ_HPP
 # define CPPAD_CORE_DIV_EQ_HPP
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
+CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
 
 CppAD is distributed under the terms of the
              Eclipse Public License Version 2.0.
diff --git a/include/cppad/core/for_one.hpp b/include/cppad/core/for_one.hpp
index 0162a0a1d..35a05e202 100644
--- a/include/cppad/core/for_one.hpp
+++ b/include/cppad/core/for_one.hpp
@@ -1,7 +1,7 @@
 # ifndef CPPAD_CORE_FOR_ONE_HPP
 # define CPPAD_CORE_FOR_ONE_HPP
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-18 Bradley M. Bell
+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.
@@ -59,7 +59,7 @@ $codei%
 (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$$.
+$cref/domain/fun_property/Domain/$$ space for $icode f$$.
 It specifies
 that point at which to evaluate the partial derivative.
 
@@ -69,7 +69,7 @@ $codei%
     size_t %j%
 %$$
 an is less than $icode n$$,
-$cref/domain/seq_property/Domain/$$ space for $icode f$$.
+$cref/domain/fun_property/Domain/$$ space for $icode f$$.
 It specifies the component of $icode F$$
 for which we are computing the partial derivative.
 
@@ -80,7 +80,7 @@ $codei%
 %$$
 (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$$.
+$cref/range/fun_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$$
diff --git a/include/cppad/core/for_two.hpp b/include/cppad/core/for_two.hpp
index 677266cf2..0815df463 100644
--- a/include/cppad/core/for_two.hpp
+++ b/include/cppad/core/for_two.hpp
@@ -1,7 +1,7 @@
 # ifndef CPPAD_CORE_FOR_TWO_HPP
 # define CPPAD_CORE_FOR_TWO_HPP
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-18 Bradley M. Bell
+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.
@@ -60,7 +60,7 @@ $codei%
 (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$$.
+$cref/domain/fun_property/Domain/$$ space for $icode f$$.
 It specifies
 that point at which to evaluate the partial derivatives listed above.
 
diff --git a/include/cppad/core/forward/forward_dir.omh b/include/cppad/core/forward/forward_dir.omh
index c76c4f1a6..08ce77754 100644
--- a/include/cppad/core/forward/forward_dir.omh
+++ b/include/cppad/core/forward/forward_dir.omh
@@ -1,5 +1,5 @@
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 Bradley M. Bell
+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.
@@ -53,11 +53,11 @@ $head Notation$$
 
 $subhead n$$
 We use $icode n$$ to denote the dimension of the
-$cref/domain/seq_property/Domain/$$ space for $icode f$$.
+$cref/domain/fun_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$$.
+$cref/range/fun_property/Range/$$ space for $icode f$$.
 
 $head f$$
 The $cref ADFun$$ object $icode f$$ has prototype
diff --git a/include/cppad/core/forward/forward_one.omh b/include/cppad/core/forward/forward_one.omh
index 1be1c5502..3f91622cd 100644
--- a/include/cppad/core/forward/forward_one.omh
+++ b/include/cppad/core/forward/forward_one.omh
@@ -1,5 +1,5 @@
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 Bradley M. Bell
+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.
@@ -67,7 +67,7 @@ $codei%
 %$$
 (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$$.
+$cref/domain/fun_property/Domain/$$ space for $icode f$$.
 
 $head Vector$$
 The type $icode Vector$$ must be a $cref SimpleVector$$ class with
diff --git a/include/cppad/core/forward/forward_order.omh b/include/cppad/core/forward/forward_order.omh
index 07e297004..f6228886c 100644
--- a/include/cppad/core/forward/forward_order.omh
+++ b/include/cppad/core/forward/forward_order.omh
@@ -1,5 +1,5 @@
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 Bradley M. Bell
+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.
@@ -60,11 +60,11 @@ $head Notation$$
 
 $subhead n$$
 We use $icode n$$ to denote the dimension of the
-$cref/domain/seq_property/Domain/$$ space for $icode f$$.
+$cref/domain/fun_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$$.
+$cref/range/fun_property/Range/$$ space for $icode f$$.
 
 $head f$$
 The $cref ADFun$$ object $icode f$$ has prototype
@@ -102,7 +102,7 @@ $codei%
 %$$
 (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$$.
+$cref/domain/fun_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
diff --git a/include/cppad/core/forward/forward_two.omh b/include/cppad/core/forward/forward_two.omh
index 782aa864e..3a3f1244a 100644
--- a/include/cppad/core/forward/forward_two.omh
+++ b/include/cppad/core/forward/forward_two.omh
@@ -1,5 +1,5 @@
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 Bradley M. Bell
+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.
@@ -78,7 +78,7 @@ $codei%
 %$$
 (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$$.
+$cref/domain/fun_property/Domain/$$ space for $icode f$$.
 
 $head y2$$
 The result $icode y2$$ has prototype
@@ -87,7 +87,7 @@ $codei%
 %$$
 (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$$.
+$cref/range/fun_property/Range/$$ space for $icode f$$.
 Its value is given element-wise by the formula in the
 $cref/purpose/forward_two/Purpose/$$ above.
 
diff --git a/include/cppad/core/forward/forward_zero.omh b/include/cppad/core/forward/forward_zero.omh
index 8b3dc64ce..ada0d0322 100644
--- a/include/cppad/core/forward/forward_zero.omh
+++ b/include/cppad/core/forward/forward_zero.omh
@@ -1,5 +1,5 @@
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 Bradley M. Bell
+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.
@@ -56,7 +56,7 @@ $codei%
 %$$
 (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$$.
+$cref/domain/fun_property/Domain/$$ space for $icode f$$.
 
 $head s$$
 If the argument $icode s$$ is not present, $code std::cout$$
@@ -76,7 +76,7 @@ $codei%
 (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$$.
+$cref/range/fun_property/Range/$$ space for $icode f$$.
 
 $head Vector$$
 The type $icode Vector$$ must be a $cref SimpleVector$$ class with
diff --git a/include/cppad/core/forward/size_order.omh b/include/cppad/core/forward/size_order.omh
index 29d5480e1..d7b76d35b 100644
--- a/include/cppad/core/forward/size_order.omh
+++ b/include/cppad/core/forward/size_order.omh
@@ -1,5 +1,5 @@
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 Bradley M. Bell
+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.
@@ -22,7 +22,7 @@ $head Syntax$$
 $icode%s% = %f%.size_order()%$$
 
 $subhead See Also$$
-$cref seq_property$$
+$cref fun_property$$
 
 $head Purpose$$
 Determine the number of Taylor coefficient orders, per variable,direction,
@@ -73,7 +73,7 @@ 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.)
+using the $cref/size_var/fun_property/size_var/$$ function.)
 
 $head capacity_order$$
 If the number of Taylor coefficient orders
diff --git a/include/cppad/core/fun_check.hpp b/include/cppad/core/fun_check.hpp
index ebf60d8a5..b4a8eed22 100644
--- a/include/cppad/core/fun_check.hpp
+++ b/include/cppad/core/fun_check.hpp
@@ -1,7 +1,7 @@
 # ifndef CPPAD_CORE_FUN_CHECK_HPP
 # define CPPAD_CORE_FUN_CHECK_HPP
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-18 Bradley M. Bell
+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.
@@ -75,7 +75,7 @@ $codei%
 (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$$.
+$cref/domain/fun_property/Domain/$$ space for $icode f$$.
 
 $head y$$
 The $icode g$$ result $icode y$$ has prototype
@@ -85,7 +85,7 @@ $codei%
 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$$.
+$cref/range/fun_property/Range/$$ space for $icode f$$.
 
 $head x$$
 The $code FunCheck$$ argument $icode x$$ has prototype
@@ -94,7 +94,7 @@ $codei%
 %$$
 and its size
 must be equal to $icode n$$, the dimension of the
-$cref/domain/seq_property/Domain/$$ space for $icode f$$.
+$cref/domain/fun_property/Domain/$$ space for $icode f$$.
 This specifies that point at which to compare the values
 calculated by $icode f$$ and $icode G$$.
 
diff --git a/include/cppad/core/fun_construct.hpp b/include/cppad/core/fun_construct.hpp
index 0ffd988bb..b93a8c87c 100644
--- a/include/cppad/core/fun_construct.hpp
+++ b/include/cppad/core/fun_construct.hpp
@@ -1,7 +1,7 @@
 # ifndef CPPAD_CORE_FUN_CONSTRUCT_HPP
 # define CPPAD_CORE_FUN_CONSTRUCT_HPP
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
+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.
@@ -94,7 +94,7 @@ $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/$$).
+returns the value zero (see $cref/size_var/fun_property/size_var/$$).
 
 $head Sequence Constructor$$
 The sequence constructor
diff --git a/omh/seq_property.omh b/include/cppad/core/fun_property.omh
similarity index 96%
rename from omh/seq_property.omh
rename to include/cppad/core/fun_property.omh
index f696508a3..4cba4d68f 100644
--- a/omh/seq_property.omh
+++ b/include/cppad/core/fun_property.omh
@@ -1,5 +1,5 @@
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-18 Bradley M. Bell
+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.
@@ -10,7 +10,7 @@ CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-18 Bradley M. Bell
         GNU General Public License, Version 2.0 or later.
 -------------------------------------------------------------------------- */
 
-$begin seq_property$$
+$begin fun_property$$
 $spell
     inuse
     Addr
@@ -29,7 +29,7 @@ $spell
     ind
 $$
 
-$section ADFun Sequence Properties$$
+$section ADFun Function Properties$$
 
 $head Syntax$$
 $icode%n% = %f%.Domain()
@@ -62,7 +62,10 @@ $icode%s% = %f%.size_op_seq()
 %$$
 
 $subhead See Also$$
-$cref size_order$$, $cref capacity_order$$, $cref number_skip$$.
+$cref function_name$$,
+$cref size_order$$,
+$cref capacity_order$$,
+$cref number_skip$$.
 
 $head Purpose$$
 The operations above return properties of the
@@ -175,7 +178,7 @@ do not correspond to a variable.
 Other operators, like the sine operator,
 correspond to two variables.
 Thus, this value will be different from
-$cref/size_var/seq_property/size_var/$$.
+$cref/size_var/fun_property/size_var/$$.
 Note that one $code enum$$ value is required for each operator.
 
 $head size_op_arg$$
@@ -292,10 +295,10 @@ of the CppAD API and may change.
 
 $head Example$$
 $children%
-    example/general/seq_property.cpp
+    example/general/fun_property.cpp
 %$$
 The file
-$cref seq_property.cpp$$
+$cref fun_property.cpp$$
 contains an example and test of these operations.
 
 
diff --git a/include/cppad/core/function_name.omh b/include/cppad/core/function_name.omh
new file mode 100644
index 000000000..c4c9175d7
--- /dev/null
+++ b/include/cppad/core/function_name.omh
@@ -0,0 +1,58 @@
+-------------------------------------------------------------------------------
+  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 function_name$$
+$spell
+    const
+    std
+$$
+
+$section Setting and Getting a Function's Name$$
+
+$head Syntax$$
+$icode%f%.function_name_set(%function_name%)
+%$$
+$icode%function_name% = %f%.function_name_get()
+%$$
+
+$head See Also$$
+$cref fun_property$$
+
+$head f$$
+In the set operation, $icode f$$ has prototype
+$codei%
+    ADFun<%Base%> %f%
+%$$
+In the get operation, $icode f$$ has prototype
+$codei%
+    const ADFun<%Base%> %f%
+%$$
+(see $codei%ADFun<%Base%>%$$ $cref/constructor/FunConstruct/$$).
+
+$head function_name$$
+is the name of the function.
+In the set operation, $icode function_name$$ has prototype
+$codei%
+    const std::string& %function_name%
+%$$
+In the get operation, $icode function_name$$ has prototype
+$codei%
+    std::string %function_name%
+%$$
+
+$children%
+    example/general/function_name.cpp
+%$$
+$head Example$$
+The file $cref function_name.cpp$$ contains an example and test
+of these operations.
+
+$end
diff --git a/include/cppad/core/graph/cpp_ad_graph.omh b/include/cppad/core/graph/cpp_ad_graph.omh
index b9f838788..d5181b56a 100644
--- a/include/cppad/core/graph/cpp_ad_graph.omh
+++ b/include/cppad/core/graph/cpp_ad_graph.omh
@@ -1,5 +1,5 @@
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 Bradley M. Bell
+CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
 
   CppAD is distributed under the terms of the
                Eclipse Public License Version 2.0.
@@ -29,6 +29,7 @@ $spell
     enum
     cpp
     Heaviside
+    notpos
 $$
 
 $section C++ Representation of an AD Graph$$
@@ -96,7 +97,7 @@ 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.
+$cref/discrete_graph_op/cpp_ad_graph/operator_arg/discrete_graph_op/$$ below.
 If there are no calls to discrete functions, this vector can be empty.
 
 $head atomic_name_vec$$
@@ -138,12 +139,6 @@ 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).
@@ -157,14 +152,43 @@ 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.
+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
+except for the following operators:
+$code sum_graph_op$$,
+$code discrete_graph_op$$,
+$code atom_graph_op$$,
+$code print_graph_op$$.
+
+$subhead print_graph_op$$
+In the case where $icode%operator_vec%[%i%].op_enum%$$ is
+$code print_graph_op$$:
+$codei%
+    %before%[%i%] = %operator_arg%[ %first_node%[%i%] - 2 ]
+%$$
+is the index in $cref/print_text_vec/cpp_ad_graph/print_text_vec/$$
+of the text that is printed before the value and
+$codei%
+    %after%[%i%] = %operator_arg%[ %first_node%[%i%] - 1 ]
+%$$
+is the index in $cref/print_text_vec/cpp_ad_graph/print_text_vec/$$
+of the text that is printed after the value.
+The $icode operator_arg$$ sub-vector for the $th i$$ operator
+starts at index $icode%first_node%[%i%]-2%$$
+and has $codei%4 = %n_node_arg%[%i%]+2%$$ elements.
+The node with index
+$codei%
+    %notpos%[%i%] = %operator_arg%[ %first_node%[%i%] ]
+%$$
+is checked and if it is positive, nothing is printed by this operator.
+Otherwise, the value corresponding to the following node is printed:
+$codei%
+    %value%[%i%] = %operator_arg%[ %first_node%[%i%] + 1 ]
+%$$
 
-$subhead dis_graph_op$$
+$subhead discrete_graph_op$$
 In the case where $icode%operator_vec%[%i%].op_enum%$$ is
-$code dis_graph_op$$:
+$code discrete_graph_op$$:
 $codei%
     %name_index%[%i%] = %operator_arg%[ %first_node%[%i%] - 1 ]
 %$$
diff --git a/include/cppad/core/graph/cpp_graph.hpp b/include/cppad/core/graph/cpp_graph.hpp
index c259d8889..44c9afc58 100644
--- a/include/cppad/core/graph/cpp_graph.hpp
+++ b/include/cppad/core/graph/cpp_graph.hpp
@@ -1,7 +1,7 @@
 # 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: C++ Algorithmic Differentiation: Copyright (C) 2003-21 Bradley M. Bell
 
 CppAD is distributed under the terms of the
              Eclipse Public License Version 2.0.
@@ -11,6 +11,7 @@ Secondary License when the conditions 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 <iomanip>
 # include <string>
 # include <cppad/utility/vector.hpp>
 # include <cppad/local/graph/cpp_graph_op.hpp>
@@ -85,6 +86,10 @@ $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.
 
+$head Parallel Mode$$
+The first use of the $code cpp_graph$$ constructor
+cannot be in $cref/parallel/ta_in_parallel/$$ execution mode.
+
 $end
 --------------------------------------------------------------------------------
 */
@@ -103,7 +108,16 @@ public:
         return;
     }
     cpp_graph(void)
-    {   initialize(); }
+    {   CPPAD_ASSERT_FIRST_CALL_NOT_PARALLEL
+        static bool first = true;
+        if( first )
+        {   first = false;
+            CPPAD_ASSERT_UNKNOWN( local::graph::op_name2enum.size() == 0 );
+            // initialize cpp_graph global variables in cpp_graph_op.cpp
+            local::graph::set_operator_info();
+        }
+        initialize();
+    }
 /*
 ---------------------------------------------------------------------------------
 $begin cpp_graph_scalar$$
@@ -234,7 +248,7 @@ $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%)
+$icode%graph_obj%.dependent_vec_push_back(%node_index%)
 %$$
 
 $subhead Find$$
@@ -396,6 +410,161 @@ $end
     {   return dependent_vec_.size(); }
     void dependent_vec_push_back(const size_t node_index)
     {   dependent_vec_.push_back(node_index); }
+/*
+$begin cpp_graph_print$$
+$spell
+    obj
+    const
+    std::ostream
+    cpp
+$$
+
+$section Print A C++ AD Graph$$
+
+$head Syntax$$
+$icode%graph_obj%.print(%os%)
+%$$
+
+$head graph_obj$$
+is an const $code cpp_graph$$ object.
+
+$head os$$
+Is the $code std::ostream$$ where the graph is printed.
+
+$head Discussion$$
+This function is included to help with using the $code cpp_graph$$ class.
+The formatting of it's output is not part of the API; i.e.,
+it may change in the future.
+
+$children%
+    example/graph/print_graph.cpp
+%$$
+$head Example$$
+The file $cref print_graph.cpp$$ contains an example and test of this operation.
+
+$end
+*/
+    void print(std::ostream& os) const
+    {   using std::setw;
+        using std::string;
+        //
+        // function name
+        if( function_name_ != "" )
+            os << function_name_ << "\n";
+        //
+        // initialize node index
+        size_t node_index = 1;
+        //
+        // text vector
+        size_t n_text = print_text_vec_.size();
+        for(size_t i = 0; i < n_text; ++i)
+        {   string s_i = "c[" + std::to_string(i) + "]";
+            //
+            os << setw(11) << "";
+            os << setw(10) << s_i;
+            os << "'" << print_text_vec_[i] << "'";
+            os << "\n";
+        }
+        //
+        //  parameter vector
+        for(size_t i = 0; i < n_dynamic_ind_; i++)
+        {   string p_i = "p[" + std::to_string(i) + "]";
+            //
+            os << setw(11)  << node_index;
+            os << setw(10) << p_i;
+            os << "\n";
+            ++node_index;
+        }
+        //
+        //  variable vector
+        for(size_t i = 0; i < n_variable_ind_; i++)
+        {   string x_i = "x[" + std::to_string(i) + "]";
+            //
+            os << setw(11)  << node_index;
+            os << setw(10) << x_i;
+            os << "\n";
+            ++node_index;
+        }
+        //
+        //  constant vector
+        size_t n_constant = constant_vec_.size();
+        for(size_t i = 0; i < n_constant; i++)
+        {   string c_i = "c[" + std::to_string(i) + "]";
+            //
+            os << setw(11) << node_index;
+            os << setw(10) << c_i;
+            os << setw(20) << constant_vec_[i];
+            os << "\n";
+            ++node_index;
+        }
+
+        size_t                    n_op = operator_vec_.size();
+        cpp_graph::const_iterator itr;
+        for(size_t op_index = 0; op_index < n_op; ++op_index)
+        {   if( op_index == 0 )
+                itr = begin();
+            else
+                ++itr;
+            cpp_graph::const_iterator::value_type itr_value = *itr;
+            //
+            const vector<size_t>& str_index( *itr_value.str_index_ptr );
+            const vector<size_t>&       arg( *itr_value.arg_node_ptr );
+            graph_op_enum          op_enum  = itr_value.op_enum;
+            size_t                n_result  = itr_value.n_result;
+            size_t                   n_arg  = arg.size();
+            CPPAD_ASSERT_UNKNOWN( n_arg > 0 );
+            //
+            string op_name = local::graph::op_enum2name[ op_enum ];
+            //
+            if( n_result == 0 )
+                os << setw(11) << "";
+            else if( n_result == 1 )
+                os << setw(11)  << node_index;
+            else
+            {   string first = std::to_string(node_index);
+                string last  = std::to_string(node_index + n_result - 1);
+                os << setw(11) << first + "-" + last;
+            }
+            os << setw(10) << op_name;
+            for(size_t i = 0; i < n_arg; ++i)
+                os << setw(5) << arg[i];
+
+            switch( op_enum )
+            {
+                case graph::discrete_graph_op:
+                CPPAD_ASSERT_UNKNOWN( str_index.size() == 1 );
+                os << discrete_name_vec_get( str_index[0] );
+                break;
+
+                case graph::atom_graph_op:
+                CPPAD_ASSERT_UNKNOWN( str_index.size() == 1 );
+                os << atomic_name_vec_get( str_index[0] );
+                break;
+
+                case graph::print_graph_op:
+                CPPAD_ASSERT_UNKNOWN( str_index.size() == 2 );
+                os << print_text_vec_get( str_index[0] ) << ",";
+                os << print_text_vec_get( str_index[1] );
+                break;
+
+                default:
+                CPPAD_ASSERT_UNKNOWN( str_index.size() == 0 );
+                break;
+            }
+            os << "\n";
+            node_index += n_result;
+        }
+        //
+        //  dependent vector
+        size_t n_dependent = dependent_vec_.size();
+        os << "y nodes = ";
+        for(size_t i = 0; i < n_dependent; i++)
+        {   os << dependent_vec_[i];
+            if( i + 1 < n_dependent )
+                os << ", ";
+        }
+        os << "\n";
+    }
 
 }; // END CPP_GRAPH_CLASS
 
diff --git a/include/cppad/core/graph/from_graph.hpp b/include/cppad/core/graph/from_graph.hpp
index 85ce50a81..ce72c1f4f 100644
--- a/include/cppad/core/graph/from_graph.hpp
+++ b/include/cppad/core/graph/from_graph.hpp
@@ -1,7 +1,7 @@
 # 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: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
 
 CppAD is distributed under the terms of the
              Eclipse Public License Version 2.0.
@@ -33,6 +33,7 @@ $section ADFun Object Corresponding to a CppAD Graph$$
 
 $head Syntax$$
 $codei%
+    cpp_graph %graph_obj%
     ADFun<%Base%> %fun%
     %fun%.from_graph(%graph_obj%)
     %fun%.from_graph(%graph_obj%, %dyn2var%, %var2dyn%)
@@ -155,10 +156,12 @@ void CppAD::ADFun<Base,RecBase>::from_graph(
     }
     //
     // Start of node indices
+# ifndef NDEBUG
     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;
+# endif
     //
     // initialize mappings from node index as empty
     // (there is no node zero)
@@ -197,12 +200,12 @@ void CppAD::ADFun<Base,RecBase>::from_graph(
         }
     }
     //
-    // atomic_three_index
+    // atomic_name2index
     // mapping from index in atomic_name_vec to atomic three index
     size_t n_graph_atomic = graph_obj.atomic_name_vec_size();
-    vector<size_t> atomic_three_index( n_graph_atomic );
+    vector<size_t> atomic_name2index( n_graph_atomic );
     for(size_t index = 0; index < n_graph_atomic; ++index)
-        atomic_three_index[index] = 0; // invalid atomic index
+        atomic_name2index[index] = 0; // invalid atomic index
 
     {   bool        set_null = true;
         size_t      index_in = 0;
@@ -217,28 +220,26 @@ void CppAD::ADFun<Base,RecBase>::from_graph(
         {   CppAD::local::atomic_index<RecBase>(
                 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;
+            size_t graph_index = graph_obj.atomic_name_vec_find(name);
+            if( graph_index != n_graph_atomic )
+            {   if( atomic_name2index[graph_index] != 0 )
+                {   std::string msg = "from_graph: error in call to ";
+                    msg += name + ".\n";
+                    msg += "There is more than one atomic ";
+                    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_name2index[graph_index] = index_in;
             }
         }
     }
@@ -328,16 +329,19 @@ void CppAD::ADFun<Base,RecBase>::from_graph(
     vector<addr_t>                  arg;
     vector<size_t>                  arg_node;
     //
-    // arrays only used by atom_graph_op
+    // arrays only used by atom_graph_op, atom4_graph_op
     vector<Base>                    parameter_x, taylor_y;
     vector<ad_type_enum>            type_y;
     vector< AD<Base> >              ax, ay;
+    vector<bool>                    select_y;
     //
     // define here because not using as loop index
     cpp_graph::const_iterator       graph_itr;
     //
     // loop over operators in the recording
+# ifndef NDEBUG
     size_t start_result = start_operator;
+# endif
     for(size_t op_index = 0; op_index < n_usage; ++op_index)
     {   // op_enum, str_index, n_result, arg_node
         if( op_index == 0 )
@@ -348,6 +352,7 @@ void CppAD::ADFun<Base,RecBase>::from_graph(
         const vector<size_t>& 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        call_id    = itr_value.call_id;
         size_t        n_arg      = itr_value.arg_node_ptr->size();
         arg.resize(n_arg);
         //
@@ -634,17 +639,17 @@ void CppAD::ADFun<Base,RecBase>::from_graph(
         // -------------------------------------------------------------------
         // atomic operator
         // -------------------------------------------------------------------
-        else if( op_enum == atom_graph_op )
+        else if( op_enum == atom_graph_op || op_enum == atom4_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];
+            CPPAD_ASSERT_UNKNOWN( name_index < atomic_name2index.size() );
+            size_t atomic_index = atomic_name2index[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 += "No previously defined atomic function ";
                 msg += "has this name";
                 //
                 // use this source code as point of detection
@@ -657,18 +662,6 @@ void CppAD::ADFun<Base,RecBase>::from_graph(
                 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<RecBase>(
-                set_null, atomic_index, type, name, v_ptr
-            );
-            CPPAD_ASSERT_UNKNOWN( type == 3 );
-            atomic_three<RecBase>* afun =
-                reinterpret_cast< atomic_three<RecBase>* >( v_ptr );
-            //
             // parameter_x
             parameter_x.resize(n_arg);
             for(size_t j = 0; j < n_arg; ++j)
@@ -678,24 +671,84 @@ void CppAD::ADFun<Base,RecBase>::from_graph(
                     parameter_x[j] = nan;
             }
             //
-            // type_y
-            type_y.resize(n_result);
-            afun->for_type(parameter_x, type_x, type_y);
+            // type, name, v_ptr
+            bool         set_null = false;
+            size_t       type;
+            std::string* name = nullptr;
+            void*        v_ptr;
+            CppAD::local::atomic_index<RecBase>(
+                set_null, atomic_index, type, name, v_ptr
+            );
+            CPPAD_ASSERT_KNOWN( 2 < type,
+                "from_graph: attempt to use an atomic function with < 3"
+            );
             //
-            // taylor_y
-            size_t need_y    = size_t(constant_enum);
+            // type_y, taylor_y
+            type_y.resize(n_result);
             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
-            );
+            if( type == 3 )
+            {   // afun
+                atomic_three<RecBase>* afun =
+                    reinterpret_cast< atomic_three<RecBase>* >( v_ptr );
+                //
+                // type_y
+                afun->for_type(parameter_x, type_x, type_y);
+                //
+                // taylor_y
+                size_t need_y    = size_t(constant_enum);
+                taylor_y.resize(n_result);
+                afun->forward(
+                    parameter_x ,
+                    type_x      ,
+                    need_y      ,
+                    order_low   ,
+                    order_up    ,
+                    parameter_x ,
+                    taylor_y
+                );
+            }
+            else
+            {   CPPAD_ASSERT_UNKNOWN( type == 4 );
+                // afun
+                atomic_four<RecBase>* afun =
+                    reinterpret_cast< atomic_four<RecBase>* >( v_ptr );
+                //
+                // type_x
+                for(size_t j = 0; j < n_arg; ++j)
+                {   if( type_x[j] == constant_enum )
+                        if( parameter[ arg[j] ] == Base(0) )
+                            type_x[j] = identical_zero_enum;
+                }
+                //
+                // type_y
+                afun->for_type(call_id, type_x, type_y);
+                for(size_t i = 0; i < n_result; ++i)
+                {   if( type_y[i] == identical_zero_enum )
+                        type_y[i] = constant_enum;
+                }
+                //
+                // type_x
+                for(size_t j = 0; j < n_arg; ++j)
+                    if( type_x[j] == identical_zero_enum )
+                        type_x[j] = constant_enum;
+                //
+                // select_y
+                select_y.resize(n_result);
+                for(size_t i = 0; i < n_result; ++i)
+                    select_y[i] = type_y[i] == constant_enum;
+                //
+                // taylor_y
+                taylor_y.resize(n_result);
+                afun->forward(
+                    call_id     ,
+                    select_y    ,
+                    order_low   ,
+                    order_up    ,
+                    parameter_x ,
+                    taylor_y
+                );
+            }
             //
             // record_dynamic, record_variable
             bool record_dynamic  = false;
@@ -725,10 +778,10 @@ void CppAD::ADFun<Base,RecBase>::from_graph(
                 }
             }
             if( record_dynamic ) rec.put_dyn_atomic(
-                    tape_id, atomic_index, type_x, type_y, ax, ay
+                    tape_id, atomic_index, call_id, type_x, type_y, ax, ay
             );
             if( record_variable ) rec.put_var_atomic(
-                    tape_id, atomic_index, type_x, type_y, ax, ay
+                    tape_id, atomic_index, call_id, type_x, type_y, ax, ay
             );
             //
             // node_type, node2fun
@@ -874,6 +927,12 @@ void CppAD::ADFun<Base,RecBase>::from_graph(
                 CPPAD_ASSERT_UNKNOWN( NumArg(local::LogOp) == 1 );
                 break;
 
+                case neg_graph_op:
+                i_result = rec.PutOp(local::NegOp);
+                rec.PutArg( arg[0] );
+                CPPAD_ASSERT_UNKNOWN( NumArg(local::NegOp) == 1 );
+                break;
+
                 case sign_graph_op:
                 i_result = rec.PutOp(local::SignOp);
                 rec.PutArg( arg[0] );
@@ -991,6 +1050,11 @@ void CppAD::ADFun<Base,RecBase>::from_graph(
                 CPPAD_ASSERT_UNKNOWN( isnan( parameter[i_result] ) );
                 break;
 
+                case neg_graph_op:
+                i_result = rec.put_dyn_par(nan, local::neg_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] ) );
@@ -1117,6 +1181,12 @@ void CppAD::ADFun<Base,RecBase>::from_graph(
                 CPPAD_ASSERT_UNKNOWN( parameter[i_result] == result );
                 break;
 
+                case neg_graph_op:
+                result    = - 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);
@@ -1379,8 +1449,10 @@ void CppAD::ADFun<Base,RecBase>::from_graph(
 
             }
         }
-        // case where node_type and node2fun for the results are set above
-        if( op_enum != atom_graph_op && n_result != 0 )
+        // Exclude cases where node_type and node2fun for the results
+        // have already been set
+        if( n_result != 0 )
+        if( op_enum != atom_graph_op && op_enum != atom4_graph_op )
         {   // set node_type and node2fun for result
             //
             CPPAD_ASSERT_UNKNOWN( i_result != 0 );
@@ -1394,7 +1466,9 @@ void CppAD::ADFun<Base,RecBase>::from_graph(
             node2fun.push_back(i_result);
         }
         //
+# ifndef NDEBUG
         start_result          += n_result;
+# endif
         CPPAD_ASSERT_UNKNOWN( node2fun.size() == start_result );
         CPPAD_ASSERT_UNKNOWN( node_type.size() == start_result );
     }
diff --git a/include/cppad/core/graph/graph_op_enum.hpp b/include/cppad/core/graph/graph_op_enum.hpp
index 84eb86614..17a0cdd2e 100644
--- a/include/cppad/core/graph/graph_op_enum.hpp
+++ b/include/cppad/core/graph/graph_op_enum.hpp
@@ -1,7 +1,7 @@
 # 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: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
 
   CppAD is distributed under the terms of the
                Eclipse Public License Version 2.0.
@@ -39,16 +39,15 @@ $$
 
 $section C++ AD Graph Operator Enum Type$$
 
+$comment
+    The following headings are referenced by comments in cpp_graph_op.cpp:
+    Atomic Fucntion, Comparison, Discrete Function, Print, Summation
+$$
+
 $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.
@@ -114,24 +113,31 @@ 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.
+and a variable number of result nodes.
+These are three extra arguments for $cref atomic_three$$ functions and
+four extra arguments for $cref atomic_four$$ functions.
+The total number of operator arguments is
+the number of extra arguments
+plus the number of arguments for the function being called.
+The extra arguments come before the function arguments.
+
 $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.
+The first operator argument is function name represented by it's index in the
+$cref/atomic_name_vec/cpp_ad_graph/atomic_name_vec/$$.
+$lnext
+If this is an atomic four function call,
+the second operator argument is the $cref/call_id/atomic_four_call/call_id/$$.
 $lnext
-The second argument is the number of result for this function call.
-The order of the results is determined by function being called.
+In the atomic three (atomic four) case, second (third) operator argument
+is the number of results for this function call.
+The order of the function results is determined by the function being called.
 $lnext
-The third argument is the number of arguments
-for this function call.
+In the atomic three (atomic four) case, the third (fourth) operator 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.
+The rest of the operator arguments are the node indices for each of the
+function arguments.
+The order of the function arguments is determined by function being called.
 $lend
 
 $head Print$$
@@ -183,6 +189,7 @@ $childtable%
     example/graph/cexp_op.cpp%
     example/graph/discrete_op.cpp%
     example/graph/atom_op.cpp%
+    example/graph/atom4_op.cpp%
     example/graph/print_op.cpp
 %$$
 
@@ -199,7 +206,8 @@ namespace CppAD { namespace graph {
         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
+        atom_graph_op,     // atomic three function call
+        atom4_graph_op,    // atomic four function call
         azmul_graph_op,    // binary: absolute zero multiplication
         cexp_eq_graph_op,  // conditional expression: ==
         cexp_le_graph_op,  // conditional expression: <=
@@ -218,6 +226,7 @@ namespace CppAD { namespace graph {
         expm1_graph_op,    // unary: exponential minus one
         log1p_graph_op,    // unary: logarithm of one plus argument
         log_graph_op,      // unary: logarithm
+        neg_graph_op,      // unary: minus
         mul_graph_op,      // binary: multiplication
         pow_graph_op,      // binary: first argument raised to second argument
         print_graph_op,    // print during zero order forward
diff --git a/include/cppad/core/graph/json_ad_graph.omh b/include/cppad/core/graph/json_ad_graph.omh
index a727f82b0..61654a1ab 100644
--- a/include/cppad/core/graph/json_ad_graph.omh
+++ b/include/cppad/core/graph/json_ad_graph.omh
@@ -1,5 +1,5 @@
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
+CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
 
   CppAD is distributed under the terms of the
                Eclipse Public License Version 2.0.
@@ -246,7 +246,7 @@ 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% ]
+    [ %n_constant%, [ %first_constant%, %...%, %last_constant% ] ]
 %$$
 Each of the elements of this vector,
 e.g., $icode first_constant$$,
diff --git a/include/cppad/core/graph/json_graph_op.omh b/include/cppad/core/graph/json_graph_op.omh
index 0a80b46b6..f55728ecb 100644
--- a/include/cppad/core/graph/json_graph_op.omh
+++ b/include/cppad/core/graph/json_graph_op.omh
@@ -1,5 +1,5 @@
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 Bradley M. Bell
+CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
 
   CppAD is distributed under the terms of the
                Eclipse Public License Version 2.0.
@@ -40,6 +40,7 @@ $spell
     div
     chkpoint
     CppAD
+    neg
 $$
 
 $section Json AD Graph Operator Definitions$$
@@ -72,35 +73,35 @@ $codei%
 %$$
 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.
+The corresponding result is the node value as a function of the argument value.
 
+$comment BEGIN_SORT_THIS_LINE_PLUS_3$$
 $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
+$icode name$$   $cnext result                           $rnext
+$code abs$$     $cnext absolute value                   $rnext
+$code acos$$    $cnext inverse cosine                   $rnext
+$code acosh$$   $cnext inverse hyperbolic cosine        $rnext
+$code asin$$    $cnext inverse sine                     $rnext
+$code asinh$$   $cnext inverse hyperbolic sine          $rnext
+$code atan$$    $cnext inverse tangent                  $rnext
+$code atanh$$   $cnext inverse hyperbolic sine          $rnext
+$code cos$$     $cnext cosine                           $rnext
+$code cosh$$    $cnext hyperbolic cosine                $rnext
+$code erf$$     $cnext error functions                  $rnext
+$code erfc$$    $cnext complementary error function     $rnext
+$code exp$$     $cnext exponential                      $rnext
+$code expm1$$   $cnext minus one plus the exponential   $rnext
+$code log$$     $cnext logarithm                        $rnext
+$code log1p$$   $cnext log  plus one                    $rnext
+$code neg$$     $cnext negative                         $rnext
+$code sign$$    $cnext sign function                    $rnext
+$code sin$$     $cnext sine                             $rnext
+$code sinh$$    $cnext hyperbolic sine                  $rnext
+$code sqrt$$    $cnext square root                      $rnext
+$code tan$$     $cnext tangent                          $rnext
+$code tanh$$    $cnext hyperbolic tangent
 $tend
+$comment END_SORT_THIS_LINE_MINUS_2$$
 
 $subhead Example$$
 The file $cref json_unary_op.cpp$$ is an example and test
@@ -331,6 +332,10 @@ the example and test $cref json_discrete_op.cpp$$.
 
 
 $head Atomic Functions$$
+These operators create $icode n_result$$ nodes with values determined by
+an evaluation of the an $cref atomic_three$$ or $cref atomic_four$$ function.
+
+$subhead Atomic Three$$
 This operator has the following Json definition:
 $codei%
 {
@@ -344,8 +349,21 @@ $codei%
         [ %first_arg%, %...%, %last_arg% ]
     ]
 %$$
-This operator creates $icode n_result$$ nodes with values equal to
-an evaluation of the $code atomic_three$$ function.
+
+$subhead Atomic Four$$
+This operator has the following Json definition:
+$codei%
+{
+    "op_code":      %op_code%,
+    "name":          "atom4"
+}
+%$$
+A corresponding $icode op_usage$$ has the form
+$codei%
+    [ %op_code%, %name%, %call_id%, %n_result%, %n_arg%,
+        [ %first_arg%, %...%, %last_arg% ]
+    ]
+%$$
 
 $subhead name$$
 The value $icode name$$ is a
@@ -353,6 +371,11 @@ $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 call_id$$
+is a $cref/non-negative integer/json_ad_graph/Token/Non-Negative Integer/$$
+specifying the $cref/call_id/atomic_four_call/call_id/$$ for an
+atomic four function.
+
 $subhead n_result$$
 is the number of results for this function; i.e.,
 its range space dimension.
@@ -415,16 +438,17 @@ $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
+    example/json/comp_op.cpp%
+    example/json/discrete_op.cpp%
+    example/json/atom_op.cpp%
+    example/json/atom4_op.cpp%
+    example/json/print_op.cpp
 %$$
 
 $end
diff --git a/include/cppad/core/graph/to_graph.hpp b/include/cppad/core/graph/to_graph.hpp
index 02654e511..4c9aae12f 100644
--- a/include/cppad/core/graph/to_graph.hpp
+++ b/include/cppad/core/graph/to_graph.hpp
@@ -2,7 +2,7 @@
 # define CPPAD_CORE_GRAPH_TO_GRAPH_HPP
 
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-21 Bradley M. Bell
+CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
 
 CppAD is distributed under the terms of the
              Eclipse Public License Version 2.0.
@@ -34,6 +34,7 @@ $section Create a C++ AD Graph Corresponding to an ADFun Object$$
 
 $head Syntax$$
 $codei%
+    cpp_graph %graph_obj%
     ADFun<%Base%> %fun%
     %fun%.to_graph(%graph_obj%)
 %$$
@@ -73,13 +74,6 @@ void CppAD::ADFun<Base,RecBase>::to_graph(
 {   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
@@ -264,6 +258,10 @@ void CppAD::ADFun<Base,RecBase>::to_graph(
             graph_op = log_graph_op;
             break;
 
+            case local::neg_dyn:
+            graph_op = neg_graph_op;
+            break;
+
             case local::sign_dyn:
             graph_op = sign_graph_op;
             break;
@@ -361,15 +359,19 @@ void CppAD::ADFun<Base,RecBase>::to_graph(
             {
                 // 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
+                // arg[1]: call_id
+                size_t call_id = size_t( dyn_par_arg[i_arg + 1] );
+                //
+                // arg[2]: number of arguments to function
+                n_arg              = size_t( dyn_par_arg[i_arg + 2] );
+                // arg[3]: number of results from function
+                size_t n_result    = size_t( dyn_par_arg[i_arg + 3] );
+                //
+                // get the name and type for this atomic function
                 std::string     name;
+                size_t          type;
                 {   bool        set_null = false;
-                    size_t      type;
                     void*       ptr;
                     CppAD::local::atomic_index<RecBase>(
                         set_null, atom_index, type, &name, ptr
@@ -380,18 +382,29 @@ void CppAD::ADFun<Base,RecBase>::to_graph(
                 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
+                // atom_graph_op:
+                // name_index, n_result, n_arg (before first_node)
+                //
+                // atom4_graph_op:
+                // name_index, call_id, n_result, n_arg (before first_node)
                 graph_obj.operator_arg_push_back(name_index);
+                if( type == 4 )
+                    graph_obj.operator_arg_push_back(call_id);
                 graph_obj.operator_arg_push_back(n_result);
                 graph_obj.operator_arg_push_back(n_arg);
                 //
-                graph_op = atom_graph_op;
+                if( type == 3 )
+                    graph_op = atom_graph_op;
+                else
+                {   CPPAD_ASSERT_UNKNOWN( type == 4 );
+                    graph_op = atom4_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] ];
+                {   // arg[5 + j] is j-th argument to the function
+                    size_t node_j = par2node[ dyn_par_arg[i_arg + 5 + j] ];
                     CPPAD_ASSERT_UNKNOWN( node_j < i_par );
                     graph_obj.operator_arg_push_back( node_j );
                 }
@@ -493,7 +506,8 @@ void CppAD::ADFun<Base,RecBase>::to_graph(
         // operator is not ignored.
         // -------------------------------------------------------------------
         switch( var_op )
-        {
+        {   // 2DO: some of these cases can be joined
+
             // -------------------------------------------------------------
             // unary operators
             case local::AbsOp:
@@ -571,6 +585,11 @@ void CppAD::ADFun<Base,RecBase>::to_graph(
             is_var[0] = true;
             break;
 
+            case local::NegOp:
+            fixed_n_arg = 1;
+            is_var[0] = true;
+            break;
+
             case local::SignOp:
             fixed_n_arg = 1;
             is_var[0] = true;
@@ -710,6 +729,10 @@ void CppAD::ADFun<Base,RecBase>::to_graph(
                 graph_op = log_graph_op;
                 break;
 
+                case local::NegOp:
+                graph_op = neg_graph_op;
+                break;
+
                 case local::SignOp:
                 graph_op = sign_graph_op;
                 break;
@@ -1067,14 +1090,16 @@ void CppAD::ADFun<Base,RecBase>::to_graph(
             else
             {   // This is the AFunOp at the end of the call
                 size_t atom_index   = size_t( arg[0] );
+                //
+                size_t call_id      = size_t( arg[1] );
                 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
+                // get the name and type for this atomic function
                 std::string     name;
+                size_t          type;
                 {   bool        set_null = false;
-                    size_t      type;
                     void*       ptr;
                     CppAD::local::atomic_index<RecBase>(
                         set_null, atom_index, type, &name, ptr
@@ -1086,12 +1111,21 @@ void CppAD::ADFun<Base,RecBase>::to_graph(
                     graph_obj.atomic_name_vec_push_back(name);
                 //
                 // for atom_graph_op:
-                // name_index, n_result, n_arg come before first_node
+                // name_index, n_result, n_arg (before first_node)
+                //
+                // for atom4_graph_op:
+                // name_index, call_id, n_result, n_arg (before first_node)
                 graph_obj.operator_arg_push_back(name_index);
+                if( type == 4 )
+                    graph_obj.operator_arg_push_back(call_id);
                 graph_obj.operator_arg_push_back(n_result);
                 graph_obj.operator_arg_push_back(n_arg);
-                //
-                graph_op = atom_graph_op;
+                if( type == 3 )
+                    graph_op = atom_graph_op;
+                else
+                {   CPPAD_ASSERT_UNKNOWN( type == 4 );
+                    graph_op = atom4_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] );
diff --git a/include/cppad/core/graph/to_json.hpp b/include/cppad/core/graph/to_json.hpp
index 7ae92e8ec..ccb715865 100644
--- a/include/cppad/core/graph/to_json.hpp
+++ b/include/cppad/core/graph/to_json.hpp
@@ -2,7 +2,7 @@
 # define CPPAD_CORE_GRAPH_TO_JSON_HPP
 
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
+CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
 
 CppAD is distributed under the terms of the
              Eclipse Public License Version 2.0.
@@ -70,16 +70,7 @@ $end
 template <class Base, class RecBase>
 std::string CppAD::ADFun<Base,RecBase>::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;
     //
diff --git a/include/cppad/core/hessian.hpp b/include/cppad/core/hessian.hpp
index bee113420..c4cf68236 100644
--- a/include/cppad/core/hessian.hpp
+++ b/include/cppad/core/hessian.hpp
@@ -1,7 +1,7 @@
 # ifndef CPPAD_CORE_HESSIAN_HPP
 # define CPPAD_CORE_HESSIAN_HPP
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-18 Bradley M. Bell
+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.
@@ -59,7 +59,7 @@ $codei%
 (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$$.
+$cref/domain/fun_property/Domain/$$ space for $icode f$$.
 It specifies
 that point at which to evaluate the Hessian.
 
@@ -69,7 +69,7 @@ $codei%
     size_t %l%
 %$$
 and is less than $icode m$$, the dimension of the
-$cref/range/seq_property/Range/$$ space for $icode f$$.
+$cref/range/fun_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,
diff --git a/include/cppad/core/jacobian.hpp b/include/cppad/core/jacobian.hpp
index 3490bb1fc..75736dacf 100644
--- a/include/cppad/core/jacobian.hpp
+++ b/include/cppad/core/jacobian.hpp
@@ -1,7 +1,7 @@
 # ifndef CPPAD_CORE_JACOBIAN_HPP
 # define CPPAD_CORE_JACOBIAN_HPP
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-18 Bradley M. Bell
+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.
@@ -55,7 +55,7 @@ $codei%
 (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$$.
+$cref/domain/fun_property/Domain/$$ space for $icode f$$.
 It specifies
 that point at which to evaluate the Jacobian.
 
@@ -66,9 +66,9 @@ $codei%
 %$$
 (see $cref/Vector/Jacobian/Vector/$$ below)
 and its size is $latex m * n$$; i.e., the product of the
-$cref/domain/seq_property/Domain/$$
+$cref/domain/fun_property/Domain/$$
 and
-$cref/range/seq_property/Range/$$
+$cref/range/fun_property/Range/$$
 dimensions for $icode f$$.
 For $latex i = 0 , \ldots , m - 1 $$
 and $latex j = 0 , \ldots , n - 1$$
diff --git a/include/cppad/core/mul.hpp b/include/cppad/core/mul.hpp
index a85eb71db..14365be31 100644
--- a/include/cppad/core/mul.hpp
+++ b/include/cppad/core/mul.hpp
@@ -1,7 +1,7 @@
 # ifndef CPPAD_CORE_MUL_HPP
 # define CPPAD_CORE_MUL_HPP
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
+CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
 
 CppAD is distributed under the terms of the
              Eclipse Public License Version 2.0.
diff --git a/include/cppad/core/mul_eq.hpp b/include/cppad/core/mul_eq.hpp
index acc4e7742..6b75e97f3 100644
--- a/include/cppad/core/mul_eq.hpp
+++ b/include/cppad/core/mul_eq.hpp
@@ -1,7 +1,7 @@
 # ifndef CPPAD_CORE_MUL_EQ_HPP
 # define CPPAD_CORE_MUL_EQ_HPP
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
+CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
 
 CppAD is distributed under the terms of the
              Eclipse Public License Version 2.0.
diff --git a/include/cppad/core/new_dynamic.hpp b/include/cppad/core/new_dynamic.hpp
index 441d577a9..6b01f07fe 100644
--- a/include/cppad/core/new_dynamic.hpp
+++ b/include/cppad/core/new_dynamic.hpp
@@ -1,7 +1,7 @@
 # ifndef CPPAD_CORE_NEW_DYNAMIC_HPP
 # define CPPAD_CORE_NEW_DYNAMIC_HPP
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-18 Bradley M. Bell
+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.
@@ -59,7 +59,7 @@ 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/$$.
+$cref/size_dyn_ind/fun_property/size_dyn_ind/$$.
 
 $head BaseVector$$
 The type $icode BaseVector$$ must be a $cref SimpleVector$$ class with
diff --git a/include/cppad/core/num_skip.hpp b/include/cppad/core/num_skip.hpp
index 2d0697bbc..4ee87897d 100644
--- a/include/cppad/core/num_skip.hpp
+++ b/include/cppad/core/num_skip.hpp
@@ -1,7 +1,7 @@
 # ifndef CPPAD_CORE_NUM_SKIP_HPP
 # define CPPAD_CORE_NUM_SKIP_HPP
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-18 Bradley M. Bell
+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.
@@ -27,7 +27,7 @@ $head Syntax$$
 $icode%n% = %f%.number_skip()%$$
 
 $subhead See Also$$
-$cref seq_property$$
+$cref fun_property$$
 
 $head Purpose$$
 The $cref/conditional expressions/CondExp/$$ use either the
diff --git a/include/cppad/core/optimize.hpp b/include/cppad/core/optimize.hpp
index 67f4e41a4..8e54ae16e 100644
--- a/include/cppad/core/optimize.hpp
+++ b/include/cppad/core/optimize.hpp
@@ -1,7 +1,7 @@
 # ifndef CPPAD_CORE_OPTIMIZE_HPP
 # define CPPAD_CORE_OPTIMIZE_HPP
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
+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.
@@ -44,7 +44,7 @@ $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$$.
+size functions in $cref fun_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.
diff --git a/include/cppad/core/pow.hpp b/include/cppad/core/pow.hpp
index 5f510c675..a5e541744 100644
--- a/include/cppad/core/pow.hpp
+++ b/include/cppad/core/pow.hpp
@@ -1,7 +1,7 @@
 # ifndef CPPAD_CORE_POW_HPP
 # define CPPAD_CORE_POW_HPP
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
+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.
@@ -37,13 +37,31 @@ 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
+
+$subhead If y is a Variable$$
+If $icode y$$ is a variable,
+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.
+
+$subhead If y is a Parameter$$
+If $icode y$$ is a parameter, a different method is used to
+compute the derivatives; see $cref pow_forward$$.
+In the special case where $icode x$$ is zero,
+zero is returned as the derivative.
+This is correct when $icode y$$ minus the order of the derivative
+is greater than zero.
+If $icode y$$ minus the order of the derivative is zero,
+then $icode y$$ is an integer.
+If $icode y$$ minus the order of the derivative is less than zero,
+the actual derivative is infinite.
+
+$subhead If y is an Integer$$
 If the value of $icode y$$ is an integer,
-the $cref pow_int$$ function is used to compute this value
+the $cref pow_int$$ function can be 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.)
+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
@@ -79,10 +97,11 @@ $cref/operation sequence/glossary/Operation/Sequence/$$.
 $head Example$$
 $children%
     example/general/pow.cpp
+    %example/general/pow_nan.cpp
 %$$
-The file
-$cref pow.cpp$$
-is an examples and tests of this function.
+The files
+$cref pow.cpp$$ and $cref pow_nan.cpp$$
+are examples tests of this function.
 
 $end
 -------------------------------------------------------------------------------
@@ -145,7 +164,7 @@ pow(const AD<Base>& x, const AD<Base>& y)
         }
         else
         {   // result = variable^parameter
-            CPPAD_ASSERT_UNKNOWN( local::NumRes(local::PowvpOp) == 3 );
+            CPPAD_ASSERT_UNKNOWN( local::NumRes(local::PowvpOp) == 1 );
             CPPAD_ASSERT_UNKNOWN( local::NumArg(local::PowvpOp) == 2 );
 
             // put operand addresses in tape
diff --git a/include/cppad/core/rev_one.hpp b/include/cppad/core/rev_one.hpp
index 9c702b3c7..efa5b3923 100644
--- a/include/cppad/core/rev_one.hpp
+++ b/include/cppad/core/rev_one.hpp
@@ -1,7 +1,7 @@
 # ifndef CPPAD_CORE_REV_ONE_HPP
 # define CPPAD_CORE_REV_ONE_HPP
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-18 Bradley M. Bell
+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.
@@ -58,7 +58,7 @@ $codei%
 (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$$.
+$cref/domain/fun_property/Domain/$$ space for $icode f$$.
 It specifies
 that point at which to evaluate the derivative.
 
@@ -68,7 +68,7 @@ $codei%
     size_t %i%
 %$$
 and is less than $latex m$$, the dimension of the
-$cref/range/seq_property/Range/$$ space for $icode f$$.
+$cref/range/fun_property/Range/$$ space for $icode f$$.
 It specifies the
 component of $latex F$$ that we are computing the derivative of.
 
@@ -79,7 +79,7 @@ $codei%
 %$$
 (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$$.
+$cref/domain/fun_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 $$
diff --git a/include/cppad/core/rev_two.hpp b/include/cppad/core/rev_two.hpp
index 43a928b86..02b1f3c17 100644
--- a/include/cppad/core/rev_two.hpp
+++ b/include/cppad/core/rev_two.hpp
@@ -1,7 +1,7 @@
 # ifndef CPPAD_CORE_REV_TWO_HPP
 # define CPPAD_CORE_REV_TWO_HPP
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-18 Bradley M. Bell
+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.
@@ -60,7 +60,7 @@ $codei%
 (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$$.
+$cref/domain/fun_property/Domain/$$ space for $icode f$$.
 It specifies
 that point at which to evaluate the partial derivatives listed above.
 
@@ -73,7 +73,7 @@ $codei%
 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.,
+$cref/range/fun_property/Range/$$ space for $icode f$$; i.e.,
 for $latex \ell = 0 , \ldots , p-1$$, $latex i[ \ell ]  < m$$.
 
 $head j$$
diff --git a/include/cppad/core/sparse_hes.hpp b/include/cppad/core/sparse_hes.hpp
index 15996a7d1..2e99b6929 100644
--- a/include/cppad/core/sparse_hes.hpp
+++ b/include/cppad/core/sparse_hes.hpp
@@ -1,7 +1,7 @@
 # ifndef CPPAD_CORE_SPARSE_HES_HPP
 # define CPPAD_CORE_SPARSE_HES_HPP
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 Bradley M. Bell
+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.
@@ -39,8 +39,8 @@ $icode%n_sweep% = %f%.sparse_hes(
 $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$$.
+Here $icode n$$ is the $cref/domain/fun_property/Domain/$$ size,
+and $icode m$$ is the $cref/range/fun_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)
diff --git a/include/cppad/core/sparse_hessian.hpp b/include/cppad/core/sparse_hessian.hpp
index 94115da24..d577b96f7 100644
--- a/include/cppad/core/sparse_hessian.hpp
+++ b/include/cppad/core/sparse_hessian.hpp
@@ -1,7 +1,7 @@
 # ifndef CPPAD_CORE_SPARSE_HESSIAN_HPP
 # define CPPAD_CORE_SPARSE_HESSIAN_HPP
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 Bradley M. Bell
+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.
@@ -38,8 +38,8 @@ $icode%hes% = %f%.SparseHessian(%x%, %w%)
 %$$
 
 $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 n$$ for the $cref/domain/fun_property/Domain/$$ size,
+and $latex m$$ for the $cref/range/fun_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$$.
@@ -72,7 +72,7 @@ $codei%
 (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$$.
+$cref/domain/fun_property/Domain/$$ space for $icode f$$.
 It specifies
 that point at which to evaluate the Hessian.
 
diff --git a/include/cppad/core/sparse_jac.hpp b/include/cppad/core/sparse_jac.hpp
index 2dd1beb2f..d264fba57 100644
--- a/include/cppad/core/sparse_jac.hpp
+++ b/include/cppad/core/sparse_jac.hpp
@@ -1,7 +1,7 @@
 # ifndef CPPAD_CORE_SPARSE_JAC_HPP
 # define CPPAD_CORE_SPARSE_JAC_HPP
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 Bradley M. Bell
+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.
@@ -44,8 +44,8 @@ $icode%n_color% = %f%.sparse_jac_rev(
 $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$$.
+Here $icode n$$ is the $cref/domain/fun_property/Domain/$$ size,
+and $icode m$$ is the $cref/range/fun_property/Range/$$ size, or $icode f$$.
 The syntax above takes advantage of sparsity when computing the Jacobian
 $latex \[
     J(x) = F^{(1)} (x)
diff --git a/include/cppad/core/sparse_jacobian.hpp b/include/cppad/core/sparse_jacobian.hpp
index dfd849eb5..ff4e1e76f 100644
--- a/include/cppad/core/sparse_jacobian.hpp
+++ b/include/cppad/core/sparse_jacobian.hpp
@@ -1,7 +1,7 @@
 # ifndef CPPAD_CORE_SPARSE_JACOBIAN_HPP
 # define CPPAD_CORE_SPARSE_JACOBIAN_HPP
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 Bradley M. Bell
+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.
@@ -45,8 +45,8 @@ $icode%jac% = %f%.SparseJacobian(%x%)
 %$$
 
 $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 n$$ for the $cref/domain/fun_property/Domain/$$ size,
+and $latex m$$ for the $cref/range/fun_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$$.
@@ -79,7 +79,7 @@ $codei%
 (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$$.
+$cref/domain/fun_property/Domain/$$ space for $icode f$$.
 It specifies
 that point at which to evaluate the Jacobian.
 
diff --git a/include/cppad/core/sub.hpp b/include/cppad/core/sub.hpp
index 0f743eecc..1aaeeac6f 100644
--- a/include/cppad/core/sub.hpp
+++ b/include/cppad/core/sub.hpp
@@ -1,7 +1,7 @@
 # ifndef CPPAD_CORE_SUB_HPP
 # define CPPAD_CORE_SUB_HPP
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
+CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
 
 CppAD is distributed under the terms of the
              Eclipse Public License Version 2.0.
diff --git a/include/cppad/core/sub_eq.hpp b/include/cppad/core/sub_eq.hpp
index 7344321a7..2859b9474 100644
--- a/include/cppad/core/sub_eq.hpp
+++ b/include/cppad/core/sub_eq.hpp
@@ -1,7 +1,7 @@
 # ifndef CPPAD_CORE_SUB_EQ_HPP
 # define CPPAD_CORE_SUB_EQ_HPP
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
+CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
 
 CppAD is distributed under the terms of the
              Eclipse Public License Version 2.0.
diff --git a/include/cppad/core/subgraph_jac_rev.hpp b/include/cppad/core/subgraph_jac_rev.hpp
index a58b22569..2d4728978 100644
--- a/include/cppad/core/subgraph_jac_rev.hpp
+++ b/include/cppad/core/subgraph_jac_rev.hpp
@@ -1,7 +1,7 @@
 # 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: C++ Algorithmic Differentiation: Copyright (C) 2003-21 Bradley M. Bell
 
 CppAD is distributed under the terms of the
              Eclipse Public License Version 2.0.
@@ -44,8 +44,8 @@ $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$$.
+Here $icode n$$ is the $cref/domain/fun_property/Domain/$$ size,
+and $icode m$$ is the $cref/range/fun_property/Range/$$ size, or $icode f$$.
 The syntax above takes advantage of sparsity when computing the Jacobian
 $latex \[
     J(x) = F^{(1)} (x)
diff --git a/include/cppad/core/unary_minus.hpp b/include/cppad/core/unary_minus.hpp
index 5fa689d0c..0eb076597 100644
--- a/include/cppad/core/unary_minus.hpp
+++ b/include/cppad/core/unary_minus.hpp
@@ -1,7 +1,7 @@
 # ifndef CPPAD_CORE_UNARY_MINUS_HPP
 # define CPPAD_CORE_UNARY_MINUS_HPP
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-18 Bradley M. Bell
+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.
@@ -77,18 +77,50 @@ $end
 
 //  BEGIN CppAD namespace
 namespace CppAD {
-
-// Broken g++ compiler inhibits declaring unary minus a member or friend
+//
 template <class Base>
 AD<Base> AD<Base>::operator - (void) const
-{   // 2DO: make a more efficient by adding unary minus to op_code.h (some day)
+{
+    // compute the Base part of this AD object
+    AD<Base> result;
+    result.value_ = - value_;
+    CPPAD_ASSERT_UNKNOWN( Parameter(result) );
+
+    // check if there is a recording in progress
+    local::ADTape<Base>* tape = AD<Base>::tape_ptr();
+    if( tape == nullptr )
+        return result;
+    // tape_id cannot match the default value for tape_id; i.e., 0
+    CPPAD_ASSERT_UNKNOWN( tape->id_ > 0 );
+    //
+    if( tape->id_ != tape_id_ )
+        return result;
     //
-    AD<Base> result(0);
-    result  -= *this;
+    if( ad_type_ == variable_enum )
+    {   // result is a variable
+        CPPAD_ASSERT_UNKNOWN( local::NumRes(local::NegOp) == 1 );
+        CPPAD_ASSERT_UNKNOWN( local::NumRes(local::NegOp) == 1 );
+        //
+        // put operand address in the tape
+        tape->Rec_.PutArg(taddr_);
+        // put operator in the tape
+        result.taddr_ = tape->Rec_.PutOp(local::NegOp);
+        // make result a variable
+        result.tape_id_ = tape_id_;
+        result.ad_type_ = variable_enum;
+    }
+    else
+    {   CPPAD_ASSERT_UNKNOWN( ad_type_ == dynamic_enum );
+        addr_t arg0 = taddr_;
+        result.taddr_ = tape->Rec_.put_dyn_par(
+            result.value_, local::neg_dyn, arg0
+        );
+        result.tape_id_  = tape_id_;
+        result.ad_type_  = dynamic_enum;
+    }
     return result;
 }
-
-
+//
 template <class Base>
 AD<Base> operator - (const VecAD_reference<Base> &right)
 {   return - right.ADBase(); }
diff --git a/include/cppad/core/undef.hpp b/include/cppad/core/undef.hpp
index f7f8f2763..f2c64bf97 100644
--- a/include/cppad/core/undef.hpp
+++ b/include/cppad/core/undef.hpp
@@ -1,7 +1,7 @@
 # ifndef CPPAD_CORE_UNDEF_HPP
 # define CPPAD_CORE_UNDEF_HPP
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 Bradley M. Bell
+CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
 
 CppAD is distributed under the terms of the
              Eclipse Public License Version 2.0.
@@ -63,6 +63,7 @@ by the CppAD examples and tests.
 */
 // Preprecessor definitions that do not presist. None of these are in the
 // user API.
+# undef CPPAD_ASSERT_AD_TYPE
 # undef CPPAD_ASSERT_NARG_NRES
 # undef CPPAD_AZMUL
 # undef CPPAD_BOOSTVECTOR
diff --git a/include/cppad/core/var2par.hpp b/include/cppad/core/var2par.hpp
index 83074f2cf..68382d1d0 100644
--- a/include/cppad/core/var2par.hpp
+++ b/include/cppad/core/var2par.hpp
@@ -1,7 +1,7 @@
 # ifndef CPPAD_CORE_VAR2PAR_HPP
 # define CPPAD_CORE_VAR2PAR_HPP
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-18 Bradley M. Bell
+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.
@@ -22,7 +22,7 @@ $spell
 $$
 
 
-$section Convert an AD Variable to a Parameter$$
+$section Convert an AD Variable or Dynamic Parameter to a Constant$$
 
 $head Syntax$$
 $icode%y% = Var2Par(%x%)%$$
@@ -32,25 +32,23 @@ $cref value$$
 
 $head Purpose$$
 Returns a
-$cref/parameter/glossary/Parameter/$$ $icode y$$
-with the same value as the
-$cref/variable/glossary/Variable/$$ $icode x$$.
+$cref/constant parameter/glossary/Parameter/Constant/$$ $icode y$$
+with the same value as $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.
-
+The argument $icode x$$ may be a
+variable, dynamic parameter, or constant parameter.
 
 $head y$$
 The result $icode y$$ has prototype
 $codei%
     AD<%Base%> &y
 %$$
-The return value $icode y$$ will be a parameter.
-
+and is a constant parameter.
 
 $head Example$$
 $children%
diff --git a/include/cppad/core/vec_ad/vec_ad.hpp b/include/cppad/core/vec_ad/vec_ad.hpp
index 29f1a065a..261f64275 100644
--- a/include/cppad/core/vec_ad/vec_ad.hpp
+++ b/include/cppad/core/vec_ad/vec_ad.hpp
@@ -1,7 +1,7 @@
 # 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: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
 
 CppAD is distributed under the terms of the
              Eclipse Public License Version 2.0.
@@ -114,7 +114,7 @@ $codei%
 %$$
 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$$
+the $cref/AD type/atomic_three_define/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$$.
 
@@ -318,7 +318,7 @@ $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
+is the $cref/ad_type/atomic_three_define/ad_type/$$ corresponding to this
 vector.
 
 $head i$$
diff --git a/include/cppad/example/atomic_four/mat_mul/base_mat_mul.hpp b/include/cppad/example/atomic_four/mat_mul/base_mat_mul.hpp
new file mode 100644
index 000000000..9e99b8410
--- /dev/null
+++ b/include/cppad/example/atomic_four/mat_mul/base_mat_mul.hpp
@@ -0,0 +1,73 @@
+# ifndef CPPAD_EXAMPLE_ATOMIC_FOUR_MAT_MUL_BASE_MAT_MUL_HPP
+# define CPPAD_EXAMPLE_ATOMIC_FOUR_MAT_MUL_BASE_MAT_MUL_HPP
+/* --------------------------------------------------------------------------
+CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
+
+CppAD is distributed under the terms of the
+             Eclipse Public License Version 2.0.
+
+This Source Code may also be made available under the following
+Secondary License when the conditions 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_four_mat_mul_base_mat_mul.hpp$$
+$spell
+$$
+
+$section
+Atomic Multiply Base Matrices: Example Implementation
+$$
+
+$head Source$$
+$srcthisfile%0%// BEGIN C++%// END C++%1%$$
+$end
+*/
+// BEGIN C++
+# include <cppad/example/atomic_four/mat_mul/mat_mul.hpp>
+
+namespace CppAD { // BEGIN_CPPAD_NAMESPACE
+//
+// for_type override
+template <class Base>
+void atomic_mat_mul<Base>::base_mat_mul(
+    size_t                         n_left      ,
+    size_t                         n_middle    ,
+    size_t                         n_right     ,
+    const CppAD::vector<Base>&     x           ,
+    CppAD::vector<Base>&           y           )
+{
+# ifndef NDEBUG
+    // n, m
+    size_t n     = x.size();
+    size_t m     = y.size();
+    //
+    // check sizes
+    assert( n == n_middle * (n_left + n_right ) );
+    assert( m == n_left * n_right );
+# endif
+    //
+    // offset
+    size_t offset = n_left * n_middle;
+    //
+    // y
+    // y[ i * n_right + j] = sum_k
+    //      x[i * n_middle + k] * x[ offset + k * n_right + j]
+    // type_y
+    for(size_t i = 0; i < n_left; ++i)
+    {   for(size_t j = 0; j < n_right; ++j)
+        {   Base sum_ij = Base(0);
+            for(size_t k = 0; k < n_middle; ++k)
+            {   Base left_ik  = x[i * n_middle + k];
+                Base right_kj = x[offset + k * n_right + j];
+                sum_ij       += left_ik * right_kj;
+            }
+            y[i * n_right + j] = sum_ij;
+        }
+    }
+    return;
+}
+} // END_CPPAD_NAMESPACE
+// END C++
+# endif
diff --git a/include/cppad/example/atomic_four/mat_mul/for_type.hpp b/include/cppad/example/atomic_four/mat_mul/for_type.hpp
new file mode 100644
index 000000000..b7c32a6b9
--- /dev/null
+++ b/include/cppad/example/atomic_four/mat_mul/for_type.hpp
@@ -0,0 +1,86 @@
+# ifndef CPPAD_EXAMPLE_ATOMIC_FOUR_MAT_MUL_FOR_TYPE_HPP
+# define CPPAD_EXAMPLE_ATOMIC_FOUR_MAT_MUL_FOR_TYPE_HPP
+/* --------------------------------------------------------------------------
+CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
+
+CppAD is distributed under the terms of the
+             Eclipse Public License Version 2.0.
+
+This Source Code may also be made available under the following
+Secondary License when the conditions 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_four_mat_mul_for_type.hpp$$
+$spell
+    Jacobian
+    jac
+$$
+
+$section
+Atomic Matrix Multiply Forward Type Calculation: Example Implementation$$
+
+$head Purpose$$
+The $code for_type$$ routine overrides the virtual functions
+used by the atomic_four base; see
+$cref/for_type/atomic_four_for_type/$$.
+
+$head Source$$
+$srcthisfile%0%// BEGIN C++%// END C++%1%$$
+$end
+*/
+// BEGIN C++
+# include <cppad/example/atomic_four/mat_mul/mat_mul.hpp>
+
+namespace CppAD { // BEGIN_CPPAD_NAMESPACE
+//
+// for_type override
+template <class Base>
+bool atomic_mat_mul<Base>::for_type(
+    size_t                                     call_id     ,
+    const CppAD::vector<CppAD::ad_type_enum>&  type_x      ,
+    CppAD::vector<CppAD::ad_type_enum>&        type_y      )
+{
+    //
+    // n_left, n_middle, n_right
+    size_t n_left, n_middle, n_right;
+    get(call_id, n_left, n_middle, n_right);
+# ifndef NDEBUG
+    // n, m
+    size_t n     = type_x.size();
+    size_t m     = type_y.size();
+    //
+    // check sizes
+    assert( n == n_left * n_middle + n_middle * n_right );
+    assert( m == n_left * n_right );
+# endif
+    //
+    // offset
+    size_t offset = n_left * n_middle;
+    //
+    // type_y
+    // y[ i * n_right + j] = sum_k
+    //      x[i * n_middle + k] * x[ offset + k * n_right + j]
+    // treat multpilication by zero like absolute zero
+    for(size_t i = 0; i < n_left; ++i)
+    {   for(size_t j = 0; j < n_right; ++j)
+        {   CppAD::ad_type_enum type_ij = CppAD::identical_zero_enum;
+            for(size_t k = 0; k < n_middle; ++k)
+            {   CppAD::ad_type_enum type_ik = type_x[i * n_middle + k];
+                CppAD::ad_type_enum type_kj = type_x[offset + k * n_right + j];
+                if( type_ik != identical_zero_enum )
+                {   if( type_kj != identical_zero_enum )
+                    {   type_ij = std::max(type_ij, type_ik);
+                        type_ij = std::max(type_ij, type_kj);
+                    }
+                }
+            }
+            type_y[ i * n_right + j] = type_ij;
+        }
+    }
+    return true;
+}
+} // END_CPPAD_NAMESPACE
+// END C++
+# endif
diff --git a/include/cppad/example/atomic_four/mat_mul/forward.hpp b/include/cppad/example/atomic_four/mat_mul/forward.hpp
new file mode 100644
index 000000000..05c18d240
--- /dev/null
+++ b/include/cppad/example/atomic_four/mat_mul/forward.hpp
@@ -0,0 +1,161 @@
+# ifndef CPPAD_EXAMPLE_ATOMIC_FOUR_MAT_MUL_FORWARD_HPP
+# define CPPAD_EXAMPLE_ATOMIC_FOUR_MAT_MUL_FORWARD_HPP
+/* --------------------------------------------------------------------------
+CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
+
+CppAD is distributed under the terms of the
+             Eclipse Public License Version 2.0.
+
+This Source Code may also be made available under the following
+Secondary License when the conditions 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_four_mat_mul_forward.hpp$$
+$spell
+    Jacobian
+    jac
+$$
+
+$section
+Atomic Matrix Multiply Forward Mode: Example Implementation
+$$
+
+$head Purpose$$
+The $code forward$$ routine overrides the virtual functions
+used by the atomic_four base; see
+$cref/forward/atomic_four_forward/$$.
+
+$head Source$$
+$srcthisfile%0%// BEGIN C++%// END C++%1%$$
+$end
+*/
+// BEGIN C++
+# include <cppad/example/atomic_four/mat_mul/mat_mul.hpp>
+
+namespace CppAD { // BEGIN_CPPAD_NAMESPACE
+//
+// forward override for Base matrix multiply
+template <class Base>
+bool atomic_mat_mul<Base>::forward(
+    size_t                                     call_id     ,
+    const CppAD::vector<bool>&                 select_y    ,
+    size_t                                     order_low   ,
+    size_t                                     order_up    ,
+    const CppAD::vector<Base>&                 taylor_x    ,
+    CppAD::vector<Base>&                       taylor_y    )
+{
+    // q
+    size_t q     = order_up + 1;
+    //
+    // n_left, n_middle, n_right
+    size_t n_left, n_middle, n_right;
+    get(call_id, n_left, n_middle, n_right);
+# ifndef NDEBUG
+    // n, m
+    size_t n     = taylor_x.size();
+    size_t m     = taylor_y.size();
+    //
+    // check sizes
+    assert( n == n_middle * ( n_left +  n_right ) * q );
+    assert( m == n_left * n_right * q );
+# endif
+    //
+    // offset
+    size_t offset = n_left * n_middle;
+    //
+    // for k = order_low, ..., order_up :
+    //    C^k = sum_ell A^ell * B^{k-ell}
+    CppAD::vector<Base> x( n_middle * ( n_left + n_right) );
+    CppAD::vector<Base> y(n_left * n_right);
+    CppAD::vector<Base> sum(n_left * n_right);
+    for(size_t k = order_low; k < q; ++k)
+    {   // sum = 0
+        for(size_t i = 0; i < n_left * n_right; ++i)
+            sum[i] = Base(0);
+        for(size_t ell = 0; ell <= k; ++ell)
+        {   // x = [ A^ell, B^{k-ell} ]
+            for(size_t i = 0; i < n_left * n_middle; ++i)
+                x[i] = taylor_x[ i * q + ell ];
+            for(size_t i = 0; i < n_middle * n_right; ++i)
+                x[offset + i] = taylor_x[ (offset + i) * q + (k - ell) ];
+            //
+            // y = A^ell * B^{k-ell}
+            base_mat_mul(n_left, n_middle, n_right, x, y);
+            //
+            // sum += y
+            for(size_t i = 0; i < n_left * n_right; ++i)
+                sum[i] += y[i];
+        }
+        // C^k = sum
+        for(size_t i = 0; i < n_left * n_right; ++i)
+            taylor_y[i * q + k] = sum[i];
+    }
+    return true;
+}
+//
+// forward override for AD<Base> matrix multiply
+template <class Base>
+bool atomic_mat_mul<Base>::forward(
+    size_t                                     call_id     ,
+    const CppAD::vector<bool>&                 select_y    ,
+    size_t                                     order_low   ,
+    size_t                                     order_up    ,
+    const CppAD::vector< CppAD::AD<Base> >&    ataylor_x   ,
+    CppAD::vector< CppAD::AD<Base> >&          ataylor_y   )
+{   //
+    // vector, AD
+    using CppAD::vector;
+    using CppAD::AD;
+    // q
+    size_t q     = order_up + 1;
+    //
+    // n_left, n_middle, n_right
+    size_t n_left, n_middle, n_right;
+    get(call_id, n_left, n_middle, n_right);
+# ifndef NDEBUG
+    // n, m
+    size_t n     = ataylor_x.size();
+    size_t m     = ataylor_y.size();
+    //
+    // check sizes
+    assert( n == n_middle * ( n_left +  n_right ) * q );
+    assert( m == n_left * n_right * q );
+# endif
+    //
+    // offset
+    size_t offset = n_left * n_middle;
+    //
+    // for k = order_low, ..., order_up :
+    //    C^k = sum_ell A^ell * B^{k-ell}
+    vector< AD<Base> > ax( n_middle *( n_left + n_right) );
+    vector< AD<Base> > ay(n_left * n_right);
+    vector< AD<Base> > asum(n_left * n_right);
+    for(size_t k = order_low; k < q; ++k)
+    {   // sum = 0
+        for(size_t i = 0; i < n_left * n_right; ++i)
+            asum[i] = AD<Base>(0);
+        for(size_t ell = 0; ell <= k; ++ell)
+        {   // ax = [ A^ell, B^{k-ell} ]
+            for(size_t i = 0; i < n_left * n_middle; ++i)
+                ax[i] = ataylor_x[ i * q + ell ];
+            for(size_t i = 0; i < n_middle * n_right; ++i)
+                ax[offset + i] = ataylor_x[ (offset + i) * q + (k - ell) ];
+            //
+            // ay = A^ell * B^{k-ell}
+            (*this)(call_id, ax, ay);
+            //
+            // asum += ay
+            for(size_t i = 0; i < n_left * n_right; ++i)
+                asum[i] += ay[i];
+        }
+        // C^k = asum
+        for(size_t i = 0; i < n_left * n_right; ++i)
+            ataylor_y[i * q + k] = asum[i];
+    }
+    return true;
+}
+} // END_CPPAD_NAMESPACE
+// END C++
+# endif
diff --git a/include/cppad/example/atomic_four/mat_mul/get.hpp b/include/cppad/example/atomic_four/mat_mul/get.hpp
new file mode 100644
index 000000000..bdcbd4606
--- /dev/null
+++ b/include/cppad/example/atomic_four/mat_mul/get.hpp
@@ -0,0 +1,75 @@
+# ifndef CPPAD_EXAMPLE_ATOMIC_FOUR_MAT_MUL_GET_HPP
+# define CPPAD_EXAMPLE_ATOMIC_FOUR_MAT_MUL_GET_HPP
+/* --------------------------------------------------------------------------
+CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
+
+CppAD is distributed under the terms of the
+             Eclipse Public License Version 2.0.
+
+This Source Code may also be made available under the following
+Secondary License when the conditions 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_four_mat_mul_get.hpp$$
+$spell
+    mul
+$$
+
+$section atomic_mat_mul Get Routine: Example Implementation$$
+
+$head Syntax$$
+$icode%call_id% = %mat_mul%.get(%call_id%, %n_left%, %n_middle%, %n_right%)%$$
+
+$head Prototype$$
+$srcthisfile%0%// BEGIN PROTOTYPE%// END PROTOTYPE%1%$$
+
+$head Purpose$$
+Retrieves the dimension information for a an atomic operation that computes
+the matrix product $icode%R% = %A% * %B%$$.
+
+$head call_id$$
+This argument identifies the dimension information for this matrix product.
+
+$head n_left$$
+This result is the row dimension of the matrices $icode A$$ and $icode R$$.
+
+$head n_middle$$
+This result is the column dimension of the matrix $icode A$$
+and row dimension of the matrix $icode B$$.
+
+$head n_right$$
+This result is the column dimension of the matrices $icode B$$ and $icode R$$.
+
+$head Source$$
+$srcthisfile%0%// BEGIN C++%// END C++%1%$$
+$end
+*/
+// BEGIN C++
+# include <cppad/example/atomic_four/mat_mul/mat_mul.hpp>
+
+namespace CppAD { // BEGIN_CPPAD_NAMESPACE
+// BEGIN PROTOTYPE
+template <class Base>
+void atomic_mat_mul<Base>::get(
+    size_t call_id, size_t& n_left, size_t& n_middle, size_t& n_right
+)
+// END PROTOTYPE
+{
+    // thread
+    size_t thread = thread_alloc::thread_num();
+    assert( work_[thread] != nullptr );
+    assert( thread == (*work_[thread])[call_id].thread );
+    //
+    // n_left, n_middle, n_right
+    call_struct& call = (*work_[thread])[call_id];
+    n_left   = call.n_left;
+    n_middle = call.n_middle;
+    n_right  = call.n_right;
+    //
+    return;
+}
+} // END_CPPAD_NAMESPACE
+// END C++
+# endif
diff --git a/include/cppad/example/atomic_four/mat_mul/hes_sparsity.hpp b/include/cppad/example/atomic_four/mat_mul/hes_sparsity.hpp
new file mode 100644
index 000000000..1f4df72a6
--- /dev/null
+++ b/include/cppad/example/atomic_four/mat_mul/hes_sparsity.hpp
@@ -0,0 +1,94 @@
+# ifndef CPPAD_EXAMPLE_ATOMIC_FOUR_MAT_MUL_HES_SPARSITY_HPP
+# define CPPAD_EXAMPLE_ATOMIC_FOUR_MAT_MUL_HES_SPARSITY_HPP
+/* --------------------------------------------------------------------------
+CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
+
+CppAD is distributed under the terms of the
+             Eclipse Public License Version 2.0.
+
+This Source Code may also be made available under the following
+Secondary License when the conditions 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_four_mat_mul_hes_sparsity.hpp$$
+$spell
+    Jacobian
+    jac
+    hes
+$$
+
+$section
+Atomic Matrix Multiply Jacobian Sparsity Pattern: Example Implementation
+$$
+
+$head Purpose$$
+The $code hes_sparsity$$ routine overrides the virtual functions
+used by the atomic_four base class for Jacobian sparsity calculations; see
+$cref/hes_sparsity/atomic_four_hes_sparsity/$$.
+
+$head Example$$
+The file $cref atomic_four_mat_mul_sparsity.cpp$$
+contains an example and test using this operator.
+
+$head Source$$
+$srcthisfile%0%// BEGIN C++%// END C++%1%$$
+$end
+*/
+// BEGIN C++
+# include <cppad/example/atomic_four/mat_mul/mat_mul.hpp>
+
+namespace CppAD { // BEGIN_CPPAD_NAMESPACE
+//
+// hes_sparsity override
+template <class Base>
+bool atomic_mat_mul<Base>::hes_sparsity(
+    size_t                                         call_id      ,
+    const CppAD::vector<bool>&                     select_x     ,
+    const CppAD::vector<bool>&                     select_y     ,
+    CppAD::sparse_rc< CppAD::vector<size_t> >&     pattern_out  )
+{
+    // n_left, n_middle, n_right
+    size_t n_left, n_middle, n_right;
+    get(call_id, n_left, n_middle, n_right);
+    //
+    // n
+    size_t n     = select_x.size();
+    //
+    // check sizes
+# ifndef NDEBUG
+    size_t m     = select_y.size();
+    assert( n == n_middle * ( n_left +  n_right ) );
+    assert( m == n_left * n_right );
+# endif
+    //
+    // offset
+    size_t offset = n_left * n_middle;
+    //
+    // pattern_out
+    pattern_out.resize(n, n, 0);
+    for(size_t i = 0; i < n_left; ++i)
+    {   for(size_t j = 0; j < n_right; ++j)
+        {   size_t ij = i * n_right + j;               // C_{i,j} = y[ij]
+            if( select_y[ij] ) for(size_t k = 0; k < n_middle; ++k)
+            {   size_t ik = i * n_middle + k;          // A_{i,k} = x[ik]
+                size_t kj = offset + k * n_right + j;  // B_{k,j} = x[kj]
+                if( select_x[ik] & select_x[kj] )
+                {   // an (ik, kj) pair can only occur once in this loop
+                    pattern_out.push_back(ik, kj);
+                    pattern_out.push_back(kj, ik);
+                }
+            }
+        }
+    }
+# ifndef NDEBUG
+    // sorting checks hat there are no duplicate entries
+    pattern_out.row_major();
+# endif
+    //
+    return true;
+}
+} // END_CPPAD_NAMESPACE
+// END C++
+# endif
diff --git a/include/cppad/example/atomic_four/mat_mul/implement.omh b/include/cppad/example/atomic_four/mat_mul/implement.omh
new file mode 100644
index 000000000..e964e5ab7
--- /dev/null
+++ b/include/cppad/example/atomic_four/mat_mul/implement.omh
@@ -0,0 +1,29 @@
+/* --------------------------------------------------------------------------
+CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
+
+CppAD is distributed under the terms of the
+             Eclipse Public License Version 2.0.
+
+This Source Code may also be made available under the following
+Secondary License when the conditions 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_four_mat_mul_implement$$
+
+$section Implementing Atomic Matrix Multiply$$
+
+$childtable%
+    include/cppad/example/atomic_four/mat_mul/mat_mul.hpp
+    %include/cppad/example/atomic_four/mat_mul/set.hpp
+    %include/cppad/example/atomic_four/mat_mul/get.hpp
+    %include/cppad/example/atomic_four/mat_mul/base_mat_mul.hpp
+    %include/cppad/example/atomic_four/mat_mul/for_type.hpp
+    %include/cppad/example/atomic_four/mat_mul/forward.hpp
+    %include/cppad/example/atomic_four/mat_mul/reverse.hpp
+    %include/cppad/example/atomic_four/mat_mul/jac_sparsity.hpp
+    %include/cppad/example/atomic_four/mat_mul/hes_sparsity.hpp
+    %include/cppad/example/atomic_four/mat_mul/rev_depend.hpp
+%$$
+
+$end
diff --git a/include/cppad/example/atomic_four/mat_mul/jac_sparsity.hpp b/include/cppad/example/atomic_four/mat_mul/jac_sparsity.hpp
new file mode 100644
index 000000000..b63d8ca58
--- /dev/null
+++ b/include/cppad/example/atomic_four/mat_mul/jac_sparsity.hpp
@@ -0,0 +1,87 @@
+# ifndef CPPAD_EXAMPLE_ATOMIC_FOUR_MAT_MUL_JAC_SPARSITY_HPP
+# define CPPAD_EXAMPLE_ATOMIC_FOUR_MAT_MUL_JAC_SPARSITY_HPP
+/* --------------------------------------------------------------------------
+CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
+
+CppAD is distributed under the terms of the
+             Eclipse Public License Version 2.0.
+
+This Source Code may also be made available under the following
+Secondary License when the conditions 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_four_mat_mul_jac_sparsity.hpp$$
+$spell
+    Jacobian
+    jac
+$$
+
+$section
+Atomic Matrix Multiply Jacobian Sparsity Pattern: Example Implementation
+$$
+
+$head Purpose$$
+The $code jac_sparsity$$ routine overrides the virtual functions
+used by the atomic_four base class for Jacobian sparsity calculations; see
+$cref/jac_sparsity/atomic_four_jac_sparsity/$$.
+
+$head Example$$
+The file $cref atomic_four_mat_mul_sparsity.cpp$$
+contains an example and test using this operator.
+
+$head Source$$
+$srcthisfile%0%// BEGIN C++%// END C++%1%$$
+$end
+*/
+// BEGIN C++
+# include <cppad/example/atomic_four/mat_mul/mat_mul.hpp>
+
+namespace CppAD { // BEGIN_CPPAD_NAMESPACE
+//
+// jac_sparsity override
+template <class Base>
+bool atomic_mat_mul<Base>::jac_sparsity(
+    size_t                                         call_id      ,
+    bool                                           dependency   ,
+    const CppAD::vector<bool>&                     select_x     ,
+    const CppAD::vector<bool>&                     select_y     ,
+    CppAD::sparse_rc< CppAD::vector<size_t> >&     pattern_out  )
+{
+    // n_left, n_middle, n_right
+    size_t n_left, n_middle, n_right;
+    get(call_id, n_left, n_middle, n_right);
+    //
+    // n, m
+    size_t n     = select_x.size();
+    size_t m     = select_y.size();
+    //
+    // check sizes
+    assert( n == n_middle * ( n_left +  n_right ) );
+    assert( m == n_left * n_right );
+    //
+    // offset
+    size_t offset = n_left * n_middle;
+    //
+    // pattern_out
+    pattern_out.resize(m, n, 0);
+    for(size_t i = 0; i < n_left; ++i)
+    {   for(size_t j = 0; j < n_right; ++j)
+        {   size_t ij = i * n_right + j;               // C_{i,j} = y[ij]
+            if( select_y[ij] ) for(size_t k = 0; k < n_middle; ++k)
+            {   size_t ik = i * n_middle + k;          // A_{i,k} = x[ik]
+                if( select_x[ik] )
+                    pattern_out.push_back(ij, ik);
+                size_t kj = offset + k * n_right + j;  // B_{k,j} = x[kj]
+                if( select_x[kj] )
+                    pattern_out.push_back(ij, kj);
+            }
+        }
+    }
+    //
+    return true;
+}
+} // END_CPPAD_NAMESPACE
+// END C++
+# endif
diff --git a/include/cppad/example/atomic_four/mat_mul/mat_mul.hpp b/include/cppad/example/atomic_four/mat_mul/mat_mul.hpp
new file mode 100644
index 000000000..f8290439c
--- /dev/null
+++ b/include/cppad/example/atomic_four/mat_mul/mat_mul.hpp
@@ -0,0 +1,170 @@
+# ifndef CPPAD_EXAMPLE_ATOMIC_FOUR_MAT_MUL_MAT_MUL_HPP
+# define CPPAD_EXAMPLE_ATOMIC_FOUR_MAT_MUL_MAT_MUL_HPP
+
+/* --------------------------------------------------------------------------
+CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
+
+CppAD is distributed under the terms of the
+             Eclipse Public License Version 2.0.
+
+This Source Code may also be made available under the following
+Secondary License when the conditions 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_four_mat_mul.hpp$$
+$spell
+$$
+
+$section Atomic Matrix Multiply Class: Example Implementation$$
+
+$srcthisfile%0%// BEGIN C++%// END C++%1%$$
+
+$end
+*/
+// BEGIN C++
+# include <cppad/cppad.hpp>
+
+namespace CppAD { // BEGIN_CPPAD_NAMESPACE
+//
+template <class Base>
+class atomic_mat_mul : public CppAD::atomic_four<Base> {
+//
+public:
+    // ctor
+    atomic_mat_mul(const std::string& name) :
+    CppAD::atomic_four<Base>(name)
+    {   for(size_t thread = 0; thread < CPPAD_MAX_NUM_THREADS; ++thread)
+            work_[thread] = nullptr;
+    }
+    // destructor
+    ~atomic_mat_mul(void)
+    {   for(size_t thread = 0; thread < CPPAD_MAX_NUM_THREADS; ++thread)
+        {   if( work_[thread] != nullptr  )
+            {   // allocated in set member function
+                delete work_[thread];
+            }
+        }
+    }
+    // set
+    size_t set(
+        size_t n_left, size_t n_right, size_t n_middle
+    );
+    // get
+    void get(
+        size_t call_id, size_t& n_left, size_t& n_right, size_t& n_middle
+    );
+private:
+    //
+    // matrix dimensions corresponding to a call_id
+    struct call_struct {
+        size_t n_left; size_t n_middle; size_t n_right; size_t thread;
+    };
+    // map from call_id to matrix dimensions
+    typedef CppAD::vector<call_struct> call_vector;
+    //
+    // Use pointers, to avoid false sharing between threads.
+    call_vector* work_[CPPAD_MAX_NUM_THREADS];
+    //
+    // base_mat_mul
+    static void base_mat_mul(
+        size_t                     n_left     ,
+        size_t                     n_middle   ,
+        size_t                     n_right    ,
+        const CppAD::vector<Base>& x          ,
+        CppAD::vector<Base>&       y
+    );
+    //
+    // -----------------------------------------------------------------------
+    // overrides
+    // -----------------------------------------------------------------------
+    //
+    // for_type
+    bool for_type(
+        size_t                                        call_id,
+        const CppAD::vector<CppAD::ad_type_enum>&     type_x,
+        CppAD::vector<CppAD::ad_type_enum>&           type_y
+    ) override;
+    //
+    // Base forward
+    bool forward(
+        size_t                                           call_id,
+        const CppAD::vector<bool>&                       select_y,
+        size_t                                           order_low,
+        size_t                                           order_up,
+        const CppAD::vector<Base>&                       taylor_x,
+        CppAD::vector<Base>&                             taylor_y
+    ) override;
+    //
+    // AD<Base> forward
+    bool forward(
+        size_t                                           call_id,
+        const CppAD::vector<bool>&                       select_y,
+        size_t                                           order_low,
+        size_t                                           order_up,
+        const CppAD::vector< CppAD::AD<Base> >&          ataylor_x,
+        CppAD::vector< CppAD::AD<Base> >&                ataylor_y
+    ) override;
+    //
+    // Base reverse
+    bool reverse(
+        size_t                                           call_id,
+        const CppAD::vector<bool>&                       select_x,
+        size_t                                           order_up,
+        const CppAD::vector<Base>&                       taylor_x,
+        const CppAD::vector<Base>&                       taylor_y,
+        CppAD::vector<Base>&                             partial_x,
+        const CppAD::vector<Base>&                       partial_y
+    ) override;
+    //
+    // AD<Base> reverse
+    bool reverse(
+        size_t                                           call_id,
+        const CppAD::vector<bool>&                       select_x,
+        size_t                                           order_up,
+        const CppAD::vector< CppAD::AD<Base> >&          ataylor_x,
+        const CppAD::vector< CppAD::AD<Base> >&          ataylor_y,
+        CppAD::vector< CppAD::AD<Base> >&                apartial_x,
+        const CppAD::vector< CppAD::AD<Base> >&          apartial_y
+    ) override;
+    //
+    // jac_sparsity
+    bool jac_sparsity(
+        size_t                                         call_id,
+        bool                                           dependency,
+        const CppAD::vector<bool>&                     select_x,
+        const CppAD::vector<bool>&                     select_y,
+        CppAD::sparse_rc< CppAD::vector<size_t> >&     pattern_out
+    ) override;
+    //
+    // hes_sparsity
+    bool hes_sparsity(
+        size_t                                         call_id,
+        const CppAD::vector<bool>&                     select_x,
+        const CppAD::vector<bool>&                     select_y,
+        CppAD::sparse_rc< CppAD::vector<size_t> >&     pattern_out
+    ) override;
+    //
+    // rev_depend
+    bool rev_depend(
+        size_t                                         call_id,
+        CppAD::vector<bool>&                           depend_x,
+        const CppAD::vector<bool>&                     depend_y
+    ) override;
+};
+} // END_CPPAD_NAMESPACE
+
+# undef CPPAD_ATOMIC_FOUR_FORWARD_AND_REVERSE
+# include <cppad/example/atomic_four/mat_mul/set.hpp>
+# include <cppad/example/atomic_four/mat_mul/get.hpp>
+# include <cppad/example/atomic_four/mat_mul/base_mat_mul.hpp>
+# include <cppad/example/atomic_four/mat_mul/for_type.hpp>
+# include <cppad/example/atomic_four/mat_mul/forward.hpp>
+# include <cppad/example/atomic_four/mat_mul/reverse.hpp>
+# include <cppad/example/atomic_four/mat_mul/jac_sparsity.hpp>
+# include <cppad/example/atomic_four/mat_mul/hes_sparsity.hpp>
+# include <cppad/example/atomic_four/mat_mul/rev_depend.hpp>
+// END C++
+
+# endif
diff --git a/include/cppad/example/atomic_four/mat_mul/mat_mul.omh b/include/cppad/example/atomic_four/mat_mul/mat_mul.omh
new file mode 100644
index 000000000..1b8039470
--- /dev/null
+++ b/include/cppad/example/atomic_four/mat_mul/mat_mul.omh
@@ -0,0 +1,171 @@
+/* --------------------------------------------------------------------------
+CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
+
+CppAD is distributed under the terms of the
+             Eclipse Public License Version 2.0.
+
+This Source Code may also be made available under the following
+Secondary License when the conditions 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_four_mat_mul$$
+$spell
+    Taylor
+    nr
+    nc
+    mul
+$$
+
+$section Atomic Matrix Multiply Class: Example Implementation$$
+
+$head Syntax$$
+$codei%atomic_mat_mul %mat_mul%(%name%)
+%$$
+$icode%call_id% = %mat_mul%.set(%n_left%, %n_middle%, %n_right%)
+%$$
+$icode%mat_mul%.get(%call_id%, %n_left%, %n_middle%, %n_right%)
+%$$
+$icode%mat_mul%(%call_id%, %x%, %y%)
+%$$
+
+$head Purpose$$
+Construct an atomic operation that computes the matrix product
+$icode%C% = %A% * %B%$$.
+
+$head n_left$$
+This is the row dimension of the matrices $icode A$$ and $icode C$$.
+This is an argument (return value) for the $code set$$ ($code get$$) routine.
+
+$head n_middle$$
+This is the column dimension of the matrix $icode A$$
+and row dimension of the matrix $icode B$$
+This is an argument (return value) for the $code set$$ ($code get$$) routine.
+
+$head n_right$$
+This is the column dimension of the matrices $icode B$$ and $icode C$$.
+This is an argument (return value) for the $code set$$ ($code get$$) routine.
+
+$head call_id$$
+This is a return value (argument) for the $code set$$ ($code get$$) routine.
+
+$head x$$
+We use $icode x$$ to denote the argument to the atomic function.
+The size of this vector must be
+$icode%
+    n = n_left * n_middle + n_middle * n_right
+%$$
+The matrix $icode A$$ is stored in row major order at the beginning of
+$icode x$$; i.e. its $icode (i,k)$$ element is
+$icode%
+    A(i,k) = x[ i * n_middle + k]
+%$$
+The matrix $icode B$$ is stored in row major order at the end of
+$icode x$$; i.e. its $icode (k,j)$$ element is
+$icode%
+    B(k,j) = x[ n_left * n_middle + k * n_right + j ]
+%$$
+
+$head y$$
+We use $icode y$$ to denote the result of the atomic function.
+The size of this vector must be
+$icode m = n_middle * n_right$$.
+The matrix $icode C$$ is stored in row major order in $icode y$$;
+i.e. its $icode (i,k)$$ element is
+$icode%
+    C(i,j) = y[ i * n_right + j]
+%$$
+
+$head Theory$$
+
+$subhead Forward$$
+For $latex k = 0 , \ldots $$, the $th k$$ order Taylor coefficient
+$latex C^{(k)}$$ is given by
+$latex \[
+    C^{(k)} = \sum_{\ell = 0}^{k} A^{(\ell)} B^{(k-\ell)}
+\] $$
+
+$subhead Matrix Argument Scalar Valued Function$$
+Suppose $latex \bar{F}$$ is the derivative of the
+scalar value function $latex s(F)$$ with respect to the matrix $latex F$$; i.e.,
+$latex \[
+    \bar{F}_{i,j} = \frac{ \partial s } { \partial F_{i,j} }
+\] $$
+Also suppose that $latex t$$ is a scalar valued argument and
+$latex \[
+    F(t) = D(t) E(t)
+\] $$
+It follows that
+$latex \[
+    F'(t) = D'(t) E(t) +  D(t) E'(t)
+\] $$
+
+$latex \[
+    (s \circ F)'(t)
+    =
+    \R{tr} [ \bar{F}^\R{T} F'(t) ]
+\] $$
+$latex \[
+    =
+    \R{tr} [ \bar{F}^\R{T} D'(t) E(t) ] +
+    \R{tr} [ \bar{F}^\R{T} D(t) E'(t) ]
+\] $$
+$latex \[
+    =
+    \R{tr} [ E(t) \bar{F}^\R{T} D'(t) ] +
+    \R{tr} [ \bar{F}^\R{T} D(t) E'(t) ]
+\] $$
+Letting $latex E(t) = 0$$ and $latex D(t) = \Delta^{i,j} (t)$$
+(where $latex \Delta^{i,j} (t)$$ is the matrix that is zero,
+except for $latex i = j$$ where it is $latex t$$) we have
+$latex \[
+    \bar{D}_{i,j}
+    = \frac{ \partial s } { \partial D_{i,j} }
+    = (s \circ F)'(t)
+    = \R{tr} [ E(t) \bar{F}^\R{T} \Delta^{i,j}(1) ]
+\] $$
+$latex \[
+    \bar{D}_{i,j}
+    = \sum_k D_{j,k} \bar{F}^\R{T}_{k,i}
+    = \sum_k \bar{F}_{i,k} E^\R{T}_{k,j}
+\] $$
+$latex \[
+    \bar{D} = \bar{F} E^\R{T}
+\] $$
+Letting $latex D(t) = 0$$ and $latex E(t) = \Delta^{i,j} (t)$$
+we have
+$latex \[
+    \bar{E}_{i,j}
+    = \frac{ \partial s } { \partial E_{i,j} }
+    = (s \circ F)'(t)
+    = \R{tr} [ \bar{F}^\R{T} D(t) \Delta^{i,j} ]
+\] $$
+$latex \[
+    \bar{E}_{i,j}
+    = \sum_k \bar{F}^\R{T}_{j,k} C_{k,i}
+    = \sum_k D^\R{T}_{i,k} \bar{F}_{k,j}
+\] $$
+$latex \[
+    \bar{E} = D^\R{T} \bar{F}
+\] $$
+
+$subhead Reverse$$
+Reverse mode eliminates $latex C^{(k)}$$ as follows:
+for $latex \ell = 0, \ldots , k$$,
+$latex \[
+\bar{A}^{(\ell)}  = \bar{A}^{(\ell)} + \bar{C}^{(k)} [ B^{(k-\ell)} ] ^\R{T}
+\] $$
+$latex \[
+\bar{B}^{(k-\ell)} =  \bar{B}^{(k-\ell)} + [ A^{(\ell)} ]^\R{T} \bar{C}^{(k)}
+\] $$
+
+$childtable%
+    include/cppad/example/atomic_four/mat_mul/implement.omh
+    %example/atomic_four/mat_mul/forward.cpp
+    %example/atomic_four/mat_mul/reverse.cpp
+    %example/atomic_four/mat_mul/sparsity.cpp
+    %example/atomic_four/mat_mul/rev_depend.cpp
+    %example/atomic_four/mat_mul/identical_zero.cpp
+%$$
+
+$end
diff --git a/include/cppad/example/atomic_four/mat_mul/rev_depend.hpp b/include/cppad/example/atomic_four/mat_mul/rev_depend.hpp
new file mode 100644
index 000000000..add31ff0e
--- /dev/null
+++ b/include/cppad/example/atomic_four/mat_mul/rev_depend.hpp
@@ -0,0 +1,83 @@
+# ifndef CPPAD_EXAMPLE_ATOMIC_FOUR_MAT_MUL_REV_DEPEND_HPP
+# define CPPAD_EXAMPLE_ATOMIC_FOUR_MAT_MUL_REV_DEPEND_HPP
+/* --------------------------------------------------------------------------
+CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
+
+CppAD is distributed under the terms of the
+             Eclipse Public License Version 2.0.
+
+This Source Code may also be made available under the following
+Secondary License when the conditions 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_four_mat_mul_rev_depend.hpp$$
+$spell
+    Jacobian
+    jac
+$$
+
+$section
+Atomic Matrix Multiply Reverse Dependency Analysis: Example Implementation
+$$
+
+$head Purpose$$
+The $code rev_depend$$ routine is used by $cref optimize$$
+to reduce the number of variables in the recording of a function.
+
+$head Source$$
+$srcthisfile%0%// BEGIN C++%// END C++%1%$$
+$end
+*/
+// BEGIN C++
+# include <cppad/example/atomic_four/mat_mul/mat_mul.hpp>
+
+namespace CppAD { // BEGIN_CPPAD_NAMESPACE
+//
+// rev_depend override
+template <class Base>
+bool atomic_mat_mul<Base>::rev_depend(
+    size_t                         call_id  ,
+    CppAD::vector<bool>&           depend_x ,
+    const CppAD::vector<bool>&     depend_y )
+{
+    //
+    // n_left, n_middle, n_right
+    size_t n_left, n_middle, n_right;
+    get(call_id, n_left, n_middle, n_right);
+# ifndef NDEBUG
+    // n, m
+    size_t n     = depend_x.size();
+    size_t m     = depend_y.size();
+    //
+    // check sizes
+    assert( n == n_left * n_middle + n_middle * n_right );
+    assert( m == n_left * n_right );
+# endif
+    //
+    // offset
+    size_t offset = n_left * n_middle;
+    //
+    // type_y
+    // y[ i * n_right + j] = sum_k
+    //      x[i * n_middle + k] * x[ offset + k * n_right + j]
+    // type_y
+    for(size_t i = 0; i < n_left; ++i)
+    {   for(size_t j = 0; j < n_right; ++j)
+        {   size_t ij = i * n_right + j;
+            if( depend_y[ij] )
+            {   for(size_t k = 0; k < n_middle; ++k)
+                {   size_t ik = i * n_middle + k;
+                    size_t kj = offset + k * n_right + j;
+                    depend_x[ik] = true;
+                    depend_x[kj] = true;
+                }
+            }
+        }
+    }
+    return true;
+}
+} // END_CPPAD_NAMESPACE
+// END C++
+# endif
diff --git a/include/cppad/example/atomic_four/mat_mul/reverse.hpp b/include/cppad/example/atomic_four/mat_mul/reverse.hpp
new file mode 100644
index 000000000..1bf9fbb41
--- /dev/null
+++ b/include/cppad/example/atomic_four/mat_mul/reverse.hpp
@@ -0,0 +1,253 @@
+# ifndef CPPAD_EXAMPLE_ATOMIC_FOUR_MAT_MUL_REVERSE_HPP
+# define CPPAD_EXAMPLE_ATOMIC_FOUR_MAT_MUL_REVERSE_HPP
+/* --------------------------------------------------------------------------
+CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
+
+CppAD is distributed under the terms of the
+             Eclipse Public License Version 2.0.
+
+This Source Code may also be made available under the following
+Secondary License when the conditions 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_four_mat_mul_reverse.hpp$$
+$spell
+    Jacobian
+    jac
+    mul
+$$
+
+$section
+Atomic Matrix Multiply Reverse Mode: Example Implementation
+$$
+
+$head Purpose$$
+The $code reverse$$ routine overrides the virtual functions
+used by the atomic_four base; see
+$cref/reverse/atomic_four_reverse/$$.
+
+$head Theory$$
+See mat_mul $cref/reverse/atomic_four_mat_mul/Theory/Reverse/$$ theory.
+
+$head Source$$
+$srcthisfile%0%// BEGIN C++%// END C++%1%$$
+$end
+*/
+// BEGIN C++
+# include <cppad/example/atomic_four/mat_mul/mat_mul.hpp>
+
+namespace CppAD { // BEGIN_CPPAD_NAMESPACE
+//
+// reverse override for Base matrix multiply
+template <class Base>
+bool atomic_mat_mul<Base>::reverse(
+    size_t                                     call_id     ,
+    const CppAD::vector<bool>&                 select_y    ,
+    size_t                                     order_up    ,
+    const CppAD::vector<Base>&                 taylor_x    ,
+    const CppAD::vector<Base>&                 taylor_y    ,
+    CppAD::vector<Base>&                       partial_x   ,
+    const CppAD::vector<Base>&                 partial_y   )
+{
+    // q
+    size_t q     = order_up + 1;
+    //
+    // n_left, n_middle, n_right
+    size_t n_left, n_middle, n_right;
+    get(call_id, n_left, n_middle, n_right);
+# ifndef NDEBUG
+    // n, m
+    size_t n     = taylor_x.size();
+    size_t m     = taylor_y.size();
+    //
+    // check sizes
+    assert( n == n_middle * ( n_left +  n_right ) * q );
+    assert( m == n_left * n_right * q );
+    assert( n == partial_x.size() );
+    assert( m == partial_y.size() );
+# endif
+    //
+    // offset
+    size_t x_offset = n_left * n_middle;
+    //
+    // u, v, u_offset
+    // note that resize only re-alocates when capacity is not large enough
+    CppAD::vector<Base> u;
+    CppAD::vector<Base> v;
+    size_t u_offset;
+    //
+    // partial_x
+    for(size_t i = 0; i < partial_x.size(); ++i)
+        partial_x[i] = Base(0);
+    //
+    // k
+    size_t k = q;
+    while(k > 0)
+    {   --k;
+        //
+        // for ell = 0, ..., k :
+        //    bar{A}^ell      += bar{C}^k [ B^{k-ell} ]^T
+        //    bar{B}^{k-ell}  += [ A^ell ]^T \bar{C}^k
+        for(size_t ell = 0; ell < q; ++ell)
+        {   //
+            // u = [ \bar{C}^k, B^{k-ell}^T ]
+            u.resize(0);
+            u.resize( n_left * n_right + n_right * n_middle );
+            u_offset = n_left * n_right;
+            for(size_t i = 0; i < n_left * n_right; ++i)
+                u[i] = partial_y[ i * q + k ];
+            for(size_t i = 0; i < n_middle; ++i)
+            {   for(size_t j = 0; j < n_right; ++j)
+                {   size_t ij = i * n_right + j;
+                    size_t ji = j * n_middle + i;
+                    u[u_offset + ji] =
+                        taylor_x[(x_offset + ij) * q + (k - ell) ];
+                }
+            }
+            //
+            // v = \bar{C} * [ B^{k-ell} ]^T
+            v.resize(0);
+            v.resize( n_left * n_middle );
+            base_mat_mul(n_left, n_right, n_middle, u, v);
+            //
+            // \bar{A}^ell += v
+            for(size_t i = 0; i < n_left * n_middle; ++i)
+                partial_x[i * q + ell] += v[i];
+            //
+            // u = [ A^ell^T , \bar{C}^k ]
+            u.resize(0);
+            u.resize( n_middle * n_left + n_left * n_right );
+            u_offset = n_middle * n_left;
+            for(size_t i = 0; i < n_left; ++i)
+            {   for(size_t j = 0; j < n_middle; ++j)
+                {   size_t ij = i * n_middle + j;
+                    size_t ji = j * n_left + i;
+                    u[ji] = taylor_x[ij * q + ell];
+                }
+            }
+            for(size_t i = 0; i < n_left * n_right; ++i)
+                u[u_offset + i] = partial_y[ i * q + k ];
+            //
+            // v = [ A^ell ]^T * \bar{C}^k
+            v.resize(0);
+            v.resize( n_middle * n_right );
+            base_mat_mul(n_middle, n_left, n_right, u, v);
+            //
+            // \bar{B}^{k-\ell} += v
+            for(size_t i = 0; i < n_middle * n_right; ++i)
+                partial_x[ (x_offset + i) * q + (k - ell) ] += v[i];
+        }
+    }
+    return true;
+}
+//
+// reverse override for AD<Base> matrix multiply
+template <class Base>
+bool atomic_mat_mul<Base>::reverse(
+    size_t                                     call_id     ,
+    const CppAD::vector<bool>&                 select_y    ,
+    size_t                                     order_up    ,
+    const CppAD::vector< AD<Base> >&           ataylor_x   ,
+    const CppAD::vector< AD<Base> >&           ataylor_y   ,
+    CppAD::vector< AD<Base> >&                 apartial_x  ,
+    const CppAD::vector< AD<Base> >&           apartial_y  )
+{
+    // q
+    size_t q     = order_up + 1;
+    //
+    // n_left, n_middle, n_right
+    size_t n_left, n_middle, n_right;
+    get(call_id, n_left, n_middle, n_right);
+# ifndef NDEBUG
+    // n, m
+    size_t n     = ataylor_x.size();
+    size_t m     = ataylor_y.size();
+    //
+    // check sizes
+    assert( n == n_middle * ( n_left +  n_right ) * q );
+    assert( m == n_left * n_right * q );
+    assert( n == apartial_x.size() );
+    assert( m == apartial_y.size() );
+# endif
+    //
+    // offset
+    size_t x_offset = n_left * n_middle;
+    //
+    // u, v, u_offset
+    // note that resize only re-alocates when capacity is not large enough
+    CppAD::vector< AD<Base> > u;
+    CppAD::vector< AD<Base> > v;
+    size_t u_offset;
+    size_t i_call;
+    //
+    // apartial_x
+    for(size_t i = 0; i < apartial_x.size(); ++i)
+        apartial_x[i] =  AD<Base> (0);
+    //
+    // k
+    size_t k = q;
+    while(k > 0)
+    {   --k;
+        //
+        // for ell = 0, ..., k :
+        //    bar{A}^ell      += bar{C}^k [ B^{k-ell} ]^T
+        //    bar{B}^{k-ell}  += [ A^ell ]^T \bar{C}^k
+        for(size_t ell = 0; ell < q; ++ell)
+        {   //
+            // u = [ \bar{C}^k, B^{k-ell}^T ]
+            u.resize(0);
+            u.resize( n_left * n_right + n_right * n_middle );
+            u_offset = n_left * n_right;
+            for(size_t i = 0; i < n_left * n_right; ++i)
+                u[i] = apartial_y[ i * q + k ];
+            for(size_t i = 0; i < n_middle; ++i)
+            {   for(size_t j = 0; j < n_right; ++j)
+                {   size_t ij = i * n_right + j;
+                    size_t ji = j * n_middle + i;
+                    u[u_offset + ji] =
+                        ataylor_x[(x_offset + ij) * q + (k - ell) ];
+                }
+            }
+            //
+            // v = \bar{C} * [ B^{k-ell} ]^T
+            v.resize(0);
+            v.resize( n_left * n_middle );
+            i_call = set(n_left, n_right, n_middle);
+            (*this)(i_call, u, v);
+            //
+            // \bar{A}^ell += v
+            for(size_t i = 0; i < n_left * n_middle; ++i)
+                apartial_x[i * q + ell] += v[i];
+            //
+            // u = [ A^ell^T , \bar{C}^k ]
+            u.resize(0);
+            u.resize( n_middle * n_left + n_left * n_right );
+            u_offset = n_middle * n_left;
+            for(size_t i = 0; i < n_left; ++i)
+            {   for(size_t j = 0; j < n_middle; ++j)
+                {   size_t ij = i * n_middle + j;
+                    size_t ji = j * n_left + i;
+                    u[ji] = ataylor_x[ij * q + ell];
+                }
+            }
+            for(size_t i = 0; i < n_left * n_right; ++i)
+                u[u_offset + i] = apartial_y[ i * q + k ];
+            //
+            // v = [ A^ell ]^T * \bar{C}^k
+            v.resize(0);
+            v.resize( n_middle * n_right );
+            i_call = set(n_middle, n_left, n_right);
+            (*this)(i_call, u, v);
+            //
+            // \bar{B}^{k-\ell} += v
+            for(size_t i = 0; i < n_middle * n_right; ++i)
+                apartial_x[ (x_offset + i) * q + (k - ell) ] += v[i];
+        }
+    }
+    return true;
+}
+} // END_CPPAD_NAMESPACE
+// END C++
+# endif
diff --git a/include/cppad/example/atomic_four/mat_mul/set.hpp b/include/cppad/example/atomic_four/mat_mul/set.hpp
new file mode 100644
index 000000000..437e275f2
--- /dev/null
+++ b/include/cppad/example/atomic_four/mat_mul/set.hpp
@@ -0,0 +1,84 @@
+# ifndef CPPAD_EXAMPLE_ATOMIC_FOUR_MAT_MUL_SET_HPP
+# define CPPAD_EXAMPLE_ATOMIC_FOUR_MAT_MUL_SET_HPP
+/* --------------------------------------------------------------------------
+CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
+
+CppAD is distributed under the terms of the
+             Eclipse Public License Version 2.0.
+
+This Source Code may also be made available under the following
+Secondary License when the conditions 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_four_mat_mul_set.hpp$$
+$spell
+    mul
+$$
+
+$section atomic_mat_mul Set Routine: Example Implementation$$
+
+$head Syntax$$
+$icode%call_id% = %mat_mul%.set(%n_left%, %n_middle%, %n_right%)%$$
+
+$head Prototype$$
+$srcthisfile%0%// BEGIN PROTOTYPE%// END PROTOTYPE%1%$$
+
+$head Purpose$$
+Stores the dimension information for a an atomic operation that computes
+the matrix product $icode%R% = %A% * %B%$$.
+
+$head n_left$$
+This argument is the row dimension of the matrices $icode A$$ and $icode R$$.
+
+$head n_middle$$
+This argument is the column dimension of the matrix $icode A$$
+and row dimension of the matrix $icode B$$.
+
+$head n_right$$
+This argument is the column dimension of the matrices $icode B$$ and $icode R$$.
+
+$head call_id$$
+This return value identifies the dimension information above.
+
+$head Source$$
+$srcthisfile%0%// BEGIN C++%// END C++%1%$$
+$end
+*/
+// BEGIN C++
+# include <cppad/example/atomic_four/mat_mul/mat_mul.hpp>
+
+namespace CppAD { // BEGIN_CPPAD_NAMESPACE
+// BEGIN PROTOTYPE
+template <class Base>
+size_t atomic_mat_mul<Base>::set(
+    size_t n_left, size_t n_middle, size_t n_right
+)
+// END PROTOTYPE
+{
+    // thread
+    size_t thread = thread_alloc::thread_num();
+    //
+    // work_[thread]
+    if( work_[thread] == nullptr )
+        work_[thread] = new call_vector;
+    //
+    // call_id
+    size_t call_id = work_[thread]->size();
+    //
+    // call
+    call_struct call;
+    call.n_left   = n_left;
+    call.n_middle = n_middle;
+    call.n_right  = n_right;
+    call.thread   = thread;
+    //
+    // work_[thread]
+    work_[thread]->push_back( call );
+    //
+    return call_id;
+}
+} // END_CPPAD_NAMESPACE
+// END C++
+# endif
diff --git a/include/cppad/example/atomic_four/vector/add_op.hpp b/include/cppad/example/atomic_four/vector/add_op.hpp
new file mode 100644
index 000000000..518f5300c
--- /dev/null
+++ b/include/cppad/example/atomic_four/vector/add_op.hpp
@@ -0,0 +1,143 @@
+# ifndef CPPAD_EXAMPLE_ATOMIC_FOUR_VECTOR_ADD_OP_HPP
+# define CPPAD_EXAMPLE_ATOMIC_FOUR_VECTOR_ADD_OP_HPP
+/* --------------------------------------------------------------------------
+CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
+
+CppAD is distributed under the terms of the
+             Eclipse Public License Version 2.0.
+
+This Source Code may also be made available under the following
+Secondary License when the conditions 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_four_vector_add_op.hpp$$
+
+$section Atomic Vector Add Operator: Example Implementation$$
+
+$head Forward Mode$$
+see theory for forward mode
+$cref/addition/ForwardTheory/Binary Operators/Addition/$$.
+
+$head Reverse Mode$$
+see theory for reverse mode
+$cref/addition/ReverseTheory/Binary Operators/Addition/$$.
+
+$head Example$$
+The file $cref atomic_four_vector_add.cpp$$ contains an example
+and test for this operator.
+
+$head Source$$
+$srcthisfile%0%// BEGIN C++%// END C++%1%$$
+
+$end
+*/
+// BEGIN C++
+# include <cppad/example/atomic_four/vector/vector.hpp>
+
+namespace CppAD { // BEGIN_CPPAD_NAMESPACE
+// ---------------------------------------------------------------------------
+// comment below is used by atomic_vector.omh
+// BEGIN forward_add
+template <class Base>
+void atomic_vector<Base>::forward_add(
+    size_t                                           m,
+    size_t                                           p,
+    size_t                                           q,
+    const CppAD::vector<Base>&                       tx,
+    CppAD::vector<Base>&                             ty)
+{
+    for(size_t k = p; k < q; ++k)
+    {   for(size_t i = 0; i < m; ++i)
+        {   size_t u_index  =       i * q + k;
+            size_t v_index  = (m + i) * q + k;
+            size_t y_index  =       i * q + k;
+            // y_i^k = u_i^k + v_i^k
+            ty[y_index]     = tx[u_index] + tx[v_index];
+        }
+    }
+}
+template <class Base>
+void atomic_vector<Base>::forward_add(
+    size_t                                           m,
+    size_t                                           p,
+    size_t                                           q,
+    const CppAD::vector< CppAD::AD<Base> >&          atx,
+    CppAD::vector< CppAD::AD<Base> >&                aty)
+{   size_t n = 2 * m;
+    assert( atx.size() == n * q );
+    assert( aty.size() == m * q );
+    //
+    // atu, atv
+    ad_const_iterator atu = atx.begin();
+    ad_const_iterator atv = atu + ad_difference_type(m * q);
+    //
+    // ax
+    ad_vector ax(n);
+    ad_iterator au = ax.begin();
+    ad_iterator av = au + ad_difference_type(m);
+    //
+    // ay
+    ad_vector ay(m);
+    //
+    for(size_t k = p; k < q; ++k)
+    {   // au = u^k
+        copy_mat_to_vec(m, q, k, atu, au);
+        // av = v^k
+        copy_mat_to_vec(m, q, k, atv, av);
+        // ay = au + av
+        (*this)(add_enum, ax, ay); // atomic vector add
+        // y^k = ay
+        copy_vec_to_mat(m, q, k, ay.begin(), aty.begin() );
+    }
+}
+// END forward_add
+// comment above is used by atomic_vector.omh
+// ---------------------------------------------------------------------------
+// reverse_add
+template <class Base>
+void atomic_vector<Base>::reverse_add(
+    size_t                                           m,
+    size_t                                           q,
+    const CppAD::vector<Base>&                       tx,
+    const CppAD::vector<Base>&                       ty,
+    CppAD::vector<Base>&                             px,
+    const CppAD::vector<Base>&                       py)
+{
+    for(size_t k = 0; k < q; ++k)
+    {   for(size_t i = 0; i < m; ++i)
+        {   size_t u_index  =       i * q + k;
+            size_t v_index  = (m + i) * q + k;
+            size_t y_index  =       i * q + k;
+            // y_i^k = u_i^k + v_i^k
+            px[u_index] = py[y_index];
+            px[v_index] = py[y_index];
+        }
+    }
+}
+template <class Base>
+void atomic_vector<Base>::reverse_add(
+    size_t                                           m,
+    size_t                                           q,
+    const CppAD::vector< CppAD::AD<Base> >&          atx,
+    const CppAD::vector< CppAD::AD<Base> >&          aty,
+    CppAD::vector< CppAD::AD<Base> >&                apx,
+    const CppAD::vector< CppAD::AD<Base> >&          apy)
+{
+    //
+    // just copying values does not add any operators to the tape.
+    for(size_t k = 0; k < q; ++k)
+    {   for(size_t i = 0; i < m; ++i)
+        {   size_t u_index  =       i * q + k;
+            size_t v_index  = (m + i) * q + k;
+            size_t y_index  =       i * q + k;
+            // y_i^k = u_i^k + v_i^k
+            apx[u_index] = apy[y_index];
+            apx[v_index] = apy[y_index];
+        }
+    }
+}
+} // END_CPPAD_NAMESPACE
+// END C++
+# endif
diff --git a/include/cppad/example/atomic_four/vector/div_op.hpp b/include/cppad/example/atomic_four/vector/div_op.hpp
new file mode 100644
index 000000000..d850667cc
--- /dev/null
+++ b/include/cppad/example/atomic_four/vector/div_op.hpp
@@ -0,0 +1,322 @@
+# ifndef CPPAD_EXAMPLE_ATOMIC_FOUR_VECTOR_DIV_OP_HPP
+# define CPPAD_EXAMPLE_ATOMIC_FOUR_VECTOR_DIV_OP_HPP
+/* --------------------------------------------------------------------------
+CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
+
+CppAD is distributed under the terms of the
+             Eclipse Public License Version 2.0.
+
+This Source Code may also be made available under the following
+Secondary License when the conditions 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_four_vector_div_op.hpp$$
+
+$section Atomic Vector Divide Operator: Example Implementation$$
+
+$head Forward Mode$$
+see theory for forward mode
+$cref/division/ForwardTheory/Binary Operators/Division/$$.
+
+$head Reverse Mode$$
+see theory for reverse mode
+$cref/division/ReverseTheory/Binary Operators/Division/$$.
+
+$head Example$$
+The file $cref atomic_four_vector_div.cpp$$ contains an example
+and test for this operator.
+
+$head Source$$
+$srcthisfile%0%// BEGIN C++%// END C++%1%$$
+
+$end
+*/
+// BEGIN C++
+# include <cppad/example/atomic_four/vector/vector.hpp>
+
+namespace CppAD { // BEGIN_CPPAD_NAMESPACE
+// ---------------------------------------------------------------------------
+// forward_div
+template <class Base>
+void atomic_vector<Base>::forward_div(
+    size_t                                           m,
+    size_t                                           p,
+    size_t                                           q,
+    const CppAD::vector<Base>&                       tx,
+    CppAD::vector<Base>&                             ty)
+{
+    for(size_t i = 0; i < m; ++i)
+    {   for(size_t k = p; k < q; ++k)
+        {   size_t y_index = i * q + k;
+            size_t u_index = i * q + k;
+            // y^k = u^k
+            ty[y_index]     = tx[u_index];
+            for(size_t d = 1; d <= k; d++)
+            {   size_t y_other = i * q + (k-d);
+                size_t v_index = (i + m) * q + d;
+                // y^k -= y^{k-d} * v^d
+                ty[y_index] -= ty[y_other] * tx[v_index];
+            }
+            size_t v0_index = (i + m) * q + 0;
+            // y^k /= v^0
+            ty[y_index] /= tx[v0_index];
+        }
+    }
+}
+template <class Base>
+void atomic_vector<Base>::forward_div(
+    size_t                                           m,
+    size_t                                           p,
+    size_t                                           q,
+    const CppAD::vector< CppAD::AD<Base> >&          atx,
+    CppAD::vector< CppAD::AD<Base> >&                aty)
+{
+    size_t n = 2 * m;
+    assert( atx.size() == n * q );
+    assert( aty.size() == m * q );
+    //
+    // atu, atv
+    ad_const_iterator atu = atx.begin();
+    ad_const_iterator atv = atu + ad_difference_type(m * q);
+    //
+    // ax_div
+    ad_vector ax_div(n);
+    ad_iterator au_div = ax_div.begin();
+    ad_iterator av_div = ax_div.begin() + ad_difference_type(m);
+    //
+    // ax_mul
+    ad_vector ax_mul(n);
+    ad_iterator au_mul = ax_mul.begin();
+    ad_iterator av_mul = ax_mul.begin() + ad_difference_type(m);
+    //
+    // ax_sub
+    ad_vector ax_sub(n);
+    ad_iterator au_sub = ax_sub.begin();
+    ad_iterator av_sub = ax_sub.begin() + ad_difference_type(m);
+    //
+    // ay
+    ad_vector ay(m);
+    //
+    for(size_t k = p; k < q; ++k)
+    {   // u_sub = u^k
+        copy_mat_to_vec(m, q, k, atu, au_sub);
+        for(size_t d = 1; d <= k; d++)
+        {   // u_mul = y^{k-d}
+            copy_mat_to_vec(m, q, k-d, aty.begin(), au_mul);
+            // v_mul = v^d
+            copy_mat_to_vec(m, q, d, atv, av_mul);
+            // ay = u_mul * v_mul
+            (*this)(mul_enum, ax_mul, ay); // atomic vector multiply
+            // v_sub = ay
+            for(size_t i = 0; i < m; ++i)
+                av_sub[i] = ay[i];
+            // ay = u_sub - v_sub
+            (*this)(sub_enum, ax_sub, ay); // atomic vector subtract
+            // u_sub = ay
+            for(size_t i = 0; i < m; ++i)
+                au_sub[i] = ay[i];
+        }
+        // u_div = u_sub
+        for(size_t i = 0; i < m; ++i)
+            au_div[i] = *(au_sub + ad_difference_type(i));
+        // v_div = v^0
+        copy_mat_to_vec(m, q, 0, atv, av_div);
+        // ay = u_div / v_div
+        (*this)(div_enum, ax_div, ay); // atomic vector divide
+        // y^k = ay
+        copy_vec_to_mat(m, q, k, ay.begin(), aty.begin());
+    }
+}
+// ---------------------------------------------------------------------------
+// reverse_div
+template <class Base>
+void atomic_vector<Base>::reverse_div(
+    size_t                                           m,
+    size_t                                           q,
+    const CppAD::vector<Base>&                       tx,
+    const CppAD::vector<Base>&                       ty,
+    CppAD::vector<Base>&                             px,
+    const CppAD::vector<Base>&                       py)
+{
+# ifndef NDEBUG
+    size_t n = 2 * m;
+    assert( tx.size() == n * q );
+    assert( ty.size() == m * q );
+    assert( px.size() == n * q );
+    assert( py.size() == m * q );
+# endif
+    //
+    // py_copy
+    CppAD::vector<Base> py_copy( py );
+    //
+    // pv
+    for(size_t i = 0; i < m; ++i)
+    {   for(size_t k = 0; k < q; ++k)
+        {   size_t v_index = (i + m) * q + k;
+            px[v_index] = 0.0;
+        }
+    }
+    // px
+    for(size_t i = 0; i < m; ++i)
+    {   size_t v0_index = (i + m) * q + 0;
+        //
+        // k
+        size_t k = q;
+        while(k)
+        {   --k;
+            //
+            // y_index
+            size_t y_index = i * q + k;
+            //
+            // py_scaled
+            double py_scaled = py_copy[y_index] / tx[v0_index];
+            //
+            for(size_t d = 1; d <= k; d++)
+            {   size_t y_other = i * q + (k-d);
+                size_t v_index = (i + m) * q + d;
+                //
+                py_copy[y_other] -= py_scaled * tx[v_index];
+                px[v_index]      -= py_scaled * ty[y_other];
+            }
+            size_t u_index = i * q + k;
+            px[u_index]   = py_scaled;
+            px[v0_index] -= py_scaled * ty[y_index];
+        }
+    }
+}
+template <class Base>
+void atomic_vector<Base>::reverse_div(
+    size_t                                           m,
+    size_t                                           q,
+    const CppAD::vector< CppAD::AD<Base> >&          atx,
+    const CppAD::vector< CppAD::AD<Base> >&          aty,
+    CppAD::vector< CppAD::AD<Base> >&                apx,
+    const CppAD::vector< CppAD::AD<Base> >&          apy)
+{   size_t n = 2 * m;
+    assert( atx.size() == n * q );
+    assert( aty.size() == m * q );
+    assert( apx.size() == n * q );
+    assert( apy.size() == m * q );
+    //
+    // atu, atv, apu, apv
+    ad_const_iterator atu = atx.begin();
+    ad_const_iterator atv = atu + ad_difference_type(m * q);
+    ad_iterator       apu = apx.begin();
+    ad_iterator       apv = apu + ad_difference_type(m * q);
+    //
+    // ax_sub
+    ad_vector ax_sub(n);
+    ad_iterator au_sub = ax_sub.begin();
+    ad_iterator av_sub = ax_sub.begin() + ad_difference_type(m);
+    //
+    // ax_mul
+    ad_vector ax_mul(n);
+    ad_iterator au_mul = ax_mul.begin();
+    ad_iterator av_mul = ax_mul.begin() + ad_difference_type(m);
+    //
+    // ax_div
+    ad_vector ax_div(n);
+    ad_iterator au_div = ax_div.begin();
+    ad_iterator av_div = ax_div.begin() + ad_difference_type(m);
+    //
+    // ay, apy_scaled
+    ad_vector ay(m), apy_scaled(m);
+    //
+    // apy_copy
+    ad_vector apy_copy( apy );
+    //
+    // apv
+    for(size_t i = 0; i < m; ++i)
+    {   for(size_t k = 0; k < q; ++k)
+        {   size_t v_index = (i + m) * q + k;
+            apx[v_index] = 0.0;
+        }
+    }
+    //
+    // av_div = atv^0
+    copy_mat_to_vec(m, q, 0, atv, av_div);
+    //
+    // k
+    size_t k = q;
+    while(k)
+    {   --k;
+        //
+        // au_div = apy^k
+        copy_mat_to_vec(m, q, k, apy_copy.begin(), au_div);
+        //
+        // apy_scaled = au_div / av_dir
+        (*this)(div_enum, ax_div, apy_scaled);
+        //
+        // au_mul = apy_scaled
+        for(size_t i = 0; i < m; ++i)
+            au_mul[i] = apy_scaled[i];
+        //
+        for(size_t d = 1; d <= k; ++d)
+        {   //
+            // av_mul = atv^d
+            copy_mat_to_vec(m, q, d, atv, av_mul);
+            //
+            // ay = au_mul * av_mul
+            (*this)(mul_enum, ax_mul, ay);
+            //
+            // au_sub = apy^{k-d}
+            copy_mat_to_vec(m, q, k-d, apy_copy.begin(), au_sub);
+            //
+            // av_sub = ay
+            for(size_t i = 0; i < m; ++i)
+                av_sub[i] = ay[i];
+            //
+            // ay = au_sub - av_sub
+            (*this)(sub_enum, ax_sub, ay);
+            //
+            // apy^{k-d} = ay
+            copy_vec_to_mat(m, q, k-d, ay.begin(), apy_copy.begin());
+            //
+            // av_mul = aty^{k-d}
+            copy_mat_to_vec(m, q, k-d, aty.begin(), av_mul);
+            //
+            // ay = au_mul * av_mul
+            (*this)(mul_enum, ax_mul, ay);
+            //
+            // au_sub = apv^d
+            copy_mat_to_vec(m, q, d, apv, au_sub);
+            //
+            // av_sub = ay
+            for(size_t i = 0; i < m; ++i)
+                av_sub[i] = ay[i];
+            //
+            // ay = au_sub - av_sub
+            (*this)(sub_enum, ax_sub, ay);
+            //
+            // apv^d = ay
+            copy_vec_to_mat(m, q, d, ay.begin(), apv);
+        }
+        //
+        // apu^k = apy_scaled
+        copy_vec_to_mat(m, q, k, apy_scaled.begin(), apu);
+        //
+        // av_mul = aty^k
+        copy_mat_to_vec(m, q, k, aty.begin(), av_mul);
+        //
+        // ay = au_mul * av_mul
+        (*this)(mul_enum, ax_mul, ay);
+        //
+        // au_sub = apv^0
+        copy_mat_to_vec(m, q, 0, apv, au_sub);
+        //
+        // av_sub = ay
+        for(size_t i = 0; i < m; ++i)
+            av_sub[i] = ay[i];
+        //
+        // ay = au_sub - av_sub
+        (*this)(sub_enum, ax_sub, ay);
+        //
+        // apv^0 = ay
+        copy_vec_to_mat(m, q, 0, ay.begin(), apv);
+    }
+}
+} // END_CPPAD_NAMESPACE
+// END C++
+# endif
diff --git a/include/cppad/example/atomic_four/vector/for_type.hpp b/include/cppad/example/atomic_four/vector/for_type.hpp
new file mode 100644
index 000000000..a44c836de
--- /dev/null
+++ b/include/cppad/example/atomic_four/vector/for_type.hpp
@@ -0,0 +1,110 @@
+# ifndef CPPAD_EXAMPLE_ATOMIC_FOUR_VECTOR_FOR_TYPE_HPP
+# define CPPAD_EXAMPLE_ATOMIC_FOUR_VECTOR_FOR_TYPE_HPP
+/* --------------------------------------------------------------------------
+CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
+
+CppAD is distributed under the terms of the
+             Eclipse Public License Version 2.0.
+
+This Source Code may also be made available under the following
+Secondary License when the conditions 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_four_vector_for_type.hpp$$
+$spell
+    Jacobian
+    jac
+$$
+
+$section Atomic Vector Forward Type Calculation: Example Implementation$$
+
+$head Purpose$$
+The $code for_type$$ routine overrides the virtual functions
+used by the atomic_four base; see
+$cref/for_type/atomic_four_for_type/$$.
+
+$head Source$$
+$srcthisfile%0%// BEGIN C++%// END C++%1%$$
+$end
+*/
+// BEGIN C++
+# include <cppad/example/atomic_four/vector/vector.hpp>
+
+namespace CppAD { // BEGIN_CPPAD_NAMESPACE
+//
+// for_type override
+template <class Base>
+bool atomic_vector<Base>::for_type(
+    size_t                                     call_id     ,
+    const CppAD::vector<CppAD::ad_type_enum>&  type_x      ,
+    CppAD::vector<CppAD::ad_type_enum>&        type_y      )
+{
+    // n, m, op
+    size_t n     = type_x.size();
+    size_t m     = type_y.size();
+    op_enum_t op = op_enum_t( call_id );
+    //
+    // type_y
+    if( n == m )
+    {   // unary operator
+        for(size_t i = 0; i < m; ++i)
+            type_y[i] = type_x[i];
+    }
+    else
+    {   // binary operator
+        for(size_t i = 0; i < m; ++i)
+            type_y[i] = std::max( type_x[i] , type_x[m + i] );
+    }
+    switch(op)
+    {
+        // addition, subtraction
+        // not sure result is identically 0 unless both are identically 0
+        case add_enum:
+        case sub_enum:
+        for(size_t i = 0; i < m; ++i)
+            type_y[i] = std::max( type_x[i] , type_x[m + i] );
+        break;
+
+
+        // multiplication
+        // treat multiplication by zero like absolute zero
+        case mul_enum:
+        for(size_t i = 0; i < m; ++i)
+        {   if( type_x[i] == identical_zero_enum )
+                type_y[i] = identical_zero_enum;
+            else if( type_x[m + i] == identical_zero_enum )
+                type_y[i] = identical_zero_enum;
+            else
+                type_y[i] = std::max( type_x[i] , type_x[m + i] );
+        }
+        break;
+
+        // division
+        // treat divition of zero like absolute zero
+        case div_enum:
+        for(size_t i = 0; i < m; ++i)
+        {   if( type_x[i] == identical_zero_enum )
+                type_y[i] = identical_zero_enum;
+            else
+                type_y[i] = std::max( type_x[i] , type_x[m + i] );
+        }
+        break;
+
+        // unary minus
+        case neg_enum:
+        for(size_t i = 0; i < m; ++i)
+            type_y[i] = type_x[i];
+        break;
+
+        // error
+        case number_op_enum:
+        assert(false);
+        break;
+    }
+    return true;
+}
+} // END_CPPAD_NAMESPACE
+// END C++
+# endif
diff --git a/include/cppad/example/atomic_four/vector/forward_op.hpp b/include/cppad/example/atomic_four/vector/forward_op.hpp
new file mode 100644
index 000000000..b6fecba7d
--- /dev/null
+++ b/include/cppad/example/atomic_four/vector/forward_op.hpp
@@ -0,0 +1,167 @@
+# ifndef CPPAD_EXAMPLE_ATOMIC_FOUR_VECTOR_FORWARD_OP_HPP
+# define CPPAD_EXAMPLE_ATOMIC_FOUR_VECTOR_FORWARD_OP_HPP
+/* --------------------------------------------------------------------------
+CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
+
+CppAD is distributed under the terms of the
+             Eclipse Public License Version 2.0.
+
+This Source Code may also be made available under the following
+Secondary License when the conditions 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_four_vector_forward_op.hpp$$
+
+$section Atomic Vector Forward Mode: Example Implementation$$
+
+$head Purpose$$
+The $code forward$$ routine overrides the virtual functions
+used by the atomic_four base class for forward mode calculations; see
+$cref/forward/atomic_four_forward/$$.
+It determines which operator is specified for this call and transfers
+the call to the operator's implementation.
+There are two versions of the $code forward$$ routine, one for $icode Base$$
+and one for $code AD<Base>$$.
+
+$head Source$$
+$srcthisfile%0%// BEGIN C++%// END C++%1%$$
+$end
+*/
+// BEGIN C++
+# include <cppad/example/atomic_four/vector/vector.hpp>
+
+namespace CppAD { // BEGIN_CPPAD_NAMESPACE
+//
+// forward override
+// this routine called by ADFun<Base> objects
+template <class Base>
+bool atomic_vector<Base>::forward(
+    size_t                                           call_id,
+    const CppAD::vector<bool>&                       select_y,
+    size_t                                           order_low,
+    size_t                                           order_up,
+    const CppAD::vector<Base>&                       tx,
+    CppAD::vector<Base>&                             ty)
+{
+    // p, q
+    size_t p = order_low;
+    size_t q = order_up + 1;
+    CPPAD_ASSERT_UNKNOWN( tx.size() % q == 0 );
+    //
+    // op, m
+    op_enum_t op = op_enum_t( call_id );
+    size_t n     = tx.size() / q;
+    size_t m = n / 2;
+    if( is_unary(op) )
+        m = n;
+    CPPAD_ASSERT_UNKNOWN( ty.size() == m * q );
+    //
+    bool ok = false;
+    switch(op)
+    {
+        // addition
+        case add_enum:
+        forward_add(m, p, q, tx, ty);
+        ok = true;
+        break;
+
+        // subtraction
+        case sub_enum:
+        forward_sub(m, p, q, tx, ty);
+        ok = true;
+        break;
+
+        // multiplication
+        case mul_enum:
+        forward_mul(m, p, q, tx, ty);
+        ok = true;
+        break;
+
+        // division
+        case div_enum:
+        forward_div(m, p, q, tx, ty);
+        ok = true;
+        break;
+
+        // unary minus
+        case neg_enum:
+        forward_neg(m, p, q, tx, ty);
+        ok = true;
+        break;
+
+        // error
+        case number_op_enum:
+        assert(false);
+        break;
+    }
+    return ok;
+}
+// forward override
+// this routine called by ADFun< CppAD::AD<Base> , Base> objects
+template <class Base>
+bool atomic_vector<Base>::forward(
+    size_t                                           call_id,
+    const CppAD::vector<bool>&                       select_y,
+    size_t                                           order_low,
+    size_t                                           order_up,
+    const CppAD::vector< CppAD::AD<Base> >&          atx,
+    CppAD::vector< CppAD::AD<Base> >&                aty         )
+{
+    // p, q
+    size_t p = order_low;
+    size_t q = order_up + 1;
+    CPPAD_ASSERT_UNKNOWN( atx.size() % q == 0 );
+    //
+    // op, m
+    op_enum_t op = op_enum_t( call_id );
+    size_t n     = atx.size() / q;
+    size_t m     = n / 2;
+    if( is_unary(op) )
+        m = n;
+    CPPAD_ASSERT_UNKNOWN( aty.size() == q * m );
+    //
+    bool ok = false;
+    switch(op)
+    {
+        // addition
+        case add_enum:
+        forward_add(m, p, q, atx, aty);
+        ok = true;
+        break;
+
+        // subtraction
+        case sub_enum:
+        forward_sub(m, p, q, atx, aty);
+        ok = true;
+        break;
+
+        // multiplication
+        case mul_enum:
+        forward_mul(m, p, q, atx, aty);
+        ok = true;
+        break;
+
+        // division
+        case div_enum:
+        forward_div(m, p, q, atx, aty);
+        ok = true;
+        break;
+
+        // unary minus
+        case neg_enum:
+        forward_neg(m, p, q, atx, aty);
+        ok = true;
+        break;
+
+        // error
+        case number_op_enum:
+        assert(false);
+        break;
+    }
+    return ok;
+}
+} // END_CPPAD_NAMESPACE
+// END C++
+# endif
diff --git a/include/cppad/example/atomic_four/vector/hes_sparsity.hpp b/include/cppad/example/atomic_four/vector/hes_sparsity.hpp
new file mode 100644
index 000000000..0f85e456f
--- /dev/null
+++ b/include/cppad/example/atomic_four/vector/hes_sparsity.hpp
@@ -0,0 +1,107 @@
+# ifndef CPPAD_EXAMPLE_ATOMIC_FOUR_VECTOR_HES_SPARSITY_HPP
+# define CPPAD_EXAMPLE_ATOMIC_FOUR_VECTOR_HES_SPARSITY_HPP
+/* --------------------------------------------------------------------------
+CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
+
+CppAD is distributed under the terms of the
+             Eclipse Public License Version 2.0.
+
+This Source Code may also be made available under the following
+Secondary License when the conditions 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_four_vector_hes_sparsity.hpp$$
+$spell
+    Jacobian
+    hes
+$$
+
+$section Atomic Vector Hessian Sparsity Pattern: Example Implementation$$
+
+$head Purpose$$
+The $code hes_sparsity$$ routine overrides the virtual functions
+used by the atomic_four base class for Jacobian sparsity calculations; see
+$cref/hes_sparsity/atomic_four_hes_sparsity/$$.
+
+$head Example$$
+The file $cref atomic_four_vector_hes_sparsity.cpp$$
+contains an example and test using this operator.
+
+$head Source$$
+$srcthisfile%0%// BEGIN C++%// END C++%1%$$
+$end
+*/
+// BEGIN C++
+# include <cppad/example/atomic_four/vector/vector.hpp>
+
+namespace CppAD { // BEGIN_CPPAD_NAMESPACE
+//
+// hes_sparsity override
+template <class Base>
+bool atomic_vector<Base>::hes_sparsity(
+    size_t                                         call_id      ,
+    const CppAD::vector<bool>&                     select_x     ,
+    const CppAD::vector<bool>&                     select_y     ,
+    CppAD::sparse_rc< CppAD::vector<size_t> >&     pattern_out  )
+{
+    size_t n = select_x.size();
+    size_t m = select_y.size();
+    assert( n == m || n == 2 * m );
+    //
+    // op
+    op_enum_t op = op_enum_t( call_id );
+    //
+    switch(op)
+    {   // linear operator cases
+        case add_enum:
+        case sub_enum:
+        case neg_enum:
+        //
+        // pattern_out is empty
+        pattern_out.resize(n, n, 0);
+        return true;
+
+        default:
+        break;
+    }
+    //
+    // nnz
+    // number of non-zeros in sparsity pattern
+    size_t nnz = 0;
+    for(size_t i = 0; i < m; ++i) if( select_y[i] )
+    {   size_t j = i;
+        if( select_x[j] && op != mul_enum )
+            ++nnz;
+        if( n != m )
+        {   // binary operator
+            j = m + i;
+            if( select_x[j] )
+                nnz += 2;
+        }
+    }
+    //
+    // pattern_out
+    pattern_out.resize(n, n, nnz);
+    size_t k = 0;
+    for(size_t i = 0; i < m; ++i) if( select_y[i] )
+    {   size_t j = i;
+        if( select_x[j] && op != mul_enum )
+            pattern_out.set(k++, i, j);
+        if( n != m )
+        {   // binary operator
+            j = m + i;
+            if( select_x[j] )
+            {   pattern_out.set(k++, i, j);
+                pattern_out.set(k++, j, i);
+            }
+        }
+    }
+    assert( k == nnz);
+    //
+    return true;
+}
+} // END_CPPAD_NAMESPACE
+// END C++
+# endif
diff --git a/include/cppad/example/atomic_four/vector/implement.omh b/include/cppad/example/atomic_four/vector/implement.omh
new file mode 100644
index 000000000..689ea9116
--- /dev/null
+++ b/include/cppad/example/atomic_four/vector/implement.omh
@@ -0,0 +1,31 @@
+/* --------------------------------------------------------------------------
+CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
+
+CppAD is distributed under the terms of the
+             Eclipse Public License Version 2.0.
+
+This Source Code may also be made available under the following
+Secondary License when the conditions 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_four_vector_implement$$
+
+$section Implementing Atomic Vector Operations$$
+
+$childtable%
+    include/cppad/example/atomic_four/vector/vector.hpp
+    %include/cppad/example/atomic_four/vector/forward_op.hpp
+    %include/cppad/example/atomic_four/vector/reverse_op.hpp
+    %include/cppad/example/atomic_four/vector/jac_sparsity.hpp
+    %include/cppad/example/atomic_four/vector/hes_sparsity.hpp
+    %include/cppad/example/atomic_four/vector/for_type.hpp
+    %include/cppad/example/atomic_four/vector/rev_depend.hpp
+    %include/cppad/example/atomic_four/vector/add_op.hpp
+    %include/cppad/example/atomic_four/vector/sub_op.hpp
+    %include/cppad/example/atomic_four/vector/mul_op.hpp
+    %include/cppad/example/atomic_four/vector/div_op.hpp
+    %include/cppad/example/atomic_four/vector/neg_op.hpp
+%$$
+
+$end
diff --git a/include/cppad/example/atomic_four/vector/jac_sparsity.hpp b/include/cppad/example/atomic_four/vector/jac_sparsity.hpp
new file mode 100644
index 000000000..f6e58aa5d
--- /dev/null
+++ b/include/cppad/example/atomic_four/vector/jac_sparsity.hpp
@@ -0,0 +1,89 @@
+# ifndef CPPAD_EXAMPLE_ATOMIC_FOUR_VECTOR_JAC_SPARSITY_HPP
+# define CPPAD_EXAMPLE_ATOMIC_FOUR_VECTOR_JAC_SPARSITY_HPP
+/* --------------------------------------------------------------------------
+CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
+
+CppAD is distributed under the terms of the
+             Eclipse Public License Version 2.0.
+
+This Source Code may also be made available under the following
+Secondary License when the conditions 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_four_vector_jac_sparsity.hpp$$
+$spell
+    Jacobian
+    jac
+$$
+
+$section Atomic Vector Jacobian Sparsity Pattern: Example Implementation$$
+
+$head Purpose$$
+The $code jac_sparsity$$ routine overrides the virtual functions
+used by the atomic_four base class for Jacobian sparsity calculations; see
+$cref/jac_sparsity/atomic_four_jac_sparsity/$$.
+
+$head Example$$
+The file $cref atomic_four_vector_jac_sparsity.cpp$$
+contains an example and test using this operator.
+
+$head Source$$
+$srcthisfile%0%// BEGIN C++%// END C++%1%$$
+$end
+*/
+// BEGIN C++
+# include <cppad/example/atomic_four/vector/vector.hpp>
+
+namespace CppAD { // BEGIN_CPPAD_NAMESPACE
+//
+// jac_sparsity override
+template <class Base>
+bool atomic_vector<Base>::jac_sparsity(
+    size_t                                         call_id      ,
+    bool                                           dependency   ,
+    const CppAD::vector<bool>&                     select_x     ,
+    const CppAD::vector<bool>&                     select_y     ,
+    CppAD::sparse_rc< CppAD::vector<size_t> >&     pattern_out  )
+{
+    size_t n = select_x.size();
+    size_t m = select_y.size();
+    assert( n == m || n == 2 * m );
+    //
+    // nnz
+    // number of non-zeros in sparsity pattern
+    size_t nnz = 0;
+    for(size_t i = 0; i < m; ++i) if( select_y[i] )
+    {   size_t j = i;
+        if( select_x[j] )
+            ++nnz;
+        if( n != m )
+        {   // binary operator
+            j = m + i;
+            if( select_x[j] )
+                ++nnz;
+        }
+    }
+    //
+    // pattern_out
+    pattern_out.resize(m, n, nnz);
+    size_t k = 0;
+    for(size_t i = 0; i < m; ++i) if( select_y[i] )
+    {   size_t j = i;
+        if( select_x[j] )
+            pattern_out.set(k++, i, j);
+        if( n != m )
+        {   // binary operator
+            j = m + i;
+            if( select_x[j] )
+                pattern_out.set(k++, i, j);
+        }
+    }
+    assert( k == nnz);
+    //
+    return true;
+}
+} // END_CPPAD_NAMESPACE
+// END C++
+# endif
diff --git a/include/cppad/example/atomic_four/vector/mul_op.hpp b/include/cppad/example/atomic_four/vector/mul_op.hpp
new file mode 100644
index 000000000..5c78dba61
--- /dev/null
+++ b/include/cppad/example/atomic_four/vector/mul_op.hpp
@@ -0,0 +1,268 @@
+# ifndef CPPAD_EXAMPLE_ATOMIC_FOUR_VECTOR_MUL_OP_HPP
+# define CPPAD_EXAMPLE_ATOMIC_FOUR_VECTOR_MUL_OP_HPP
+/* --------------------------------------------------------------------------
+CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
+
+CppAD is distributed under the terms of the
+             Eclipse Public License Version 2.0.
+
+This Source Code may also be made available under the following
+Secondary License when the conditions 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_four_vector_mul_op.hpp$$
+
+$section Atomic Vector Multiply Operator: Example Implementation$$
+
+$head Forward Mode$$
+see theory for forward mode
+$cref/multiplication/ForwardTheory/Binary Operators/Multiplication/$$.
+
+$head Reverse Mode$$
+see theory for reverse mode
+$cref/multiplication/ReverseTheory/Binary Operators/Multiplication/$$.
+
+$head Example$$
+The file $cref atomic_four_vector_mul.cpp$$ contains an example
+and test for this operator.
+
+$head Source$$
+$srcthisfile%0%// BEGIN C++%// END C++%1%$$
+
+$end
+*/
+// BEGIN C++
+# include <cppad/example/atomic_four/vector/vector.hpp>
+
+namespace CppAD { // BEGIN_CPPAD_NAMESPACE
+// --------------------------------------------------------------------------
+// forward_mul
+template <class Base>
+void atomic_vector<Base>::forward_mul(
+    size_t                                           m,
+    size_t                                           p,
+    size_t                                           q,
+    const CppAD::vector<Base>&                       tx,
+    CppAD::vector<Base>&                             ty)
+{
+    for(size_t i = 0; i < m; ++i)
+    {   for(size_t k = p; k < q; ++k)
+        {   size_t y_index = i * q + k;
+            // y^k = 0
+            ty[y_index]    = 0.0;
+            for(size_t d = 0; d <= k; d++)
+            {   size_t u_index  =       i * q + (k-d);
+                size_t v_index  = (m + i) * q + d;
+                // y^k += u^{k-d} * v^d
+                ty[y_index]    += tx[u_index] * tx[v_index];
+            }
+        }
+    }
+}
+template <class Base>
+void atomic_vector<Base>::forward_mul(
+    size_t                                           m,
+    size_t                                           p,
+    size_t                                           q,
+    const CppAD::vector< CppAD::AD<Base> >&          atx,
+    CppAD::vector< CppAD::AD<Base> >&                aty)
+{
+    size_t n = 2 * m;
+    assert( atx.size() == n * q );
+    assert( aty.size() == m * q );
+    //
+    // atu, atv
+    ad_const_iterator atu = atx.begin();
+    ad_const_iterator atv = atu + ad_difference_type(m * q);
+    //
+    // ax_mul
+    ad_vector ax_mul(n);
+    ad_iterator au_mul = ax_mul.begin();
+    ad_iterator av_mul = ax_mul.begin() + ad_difference_type(m);
+    //
+    // ax_add
+    ad_vector ax_add(n);
+    ad_iterator au_add = ax_add.begin();
+    ad_iterator av_add = ax_add.begin() + ad_difference_type(m);
+    //
+    // ay
+    ad_vector ay(m);
+    //
+    for(size_t k = p; k < q; ++k)
+    {   // ay = 0
+        for(size_t i = 0; i < m; ++i)
+            ay[i] = 0.0;
+        for(size_t d = 0; d <= k; d++)
+        {   // u_add = ay
+            for(size_t i = 0; i < m; ++i)
+                au_add[i] = ay[i];
+            //
+            // au_mul = u^{k-d}
+            copy_mat_to_vec(m, q, k-d, atu, au_mul);
+            //
+            // av_mul =  v^d
+            copy_mat_to_vec(m, q, d, atv, av_mul);
+            //
+            // ay = au_mul * av_mul
+            (*this)(mul_enum, ax_mul, ay); // atomic vector multiply
+            //
+            // v_add = ay
+            for(size_t i = 0; i < m; ++i)
+                av_add[i] = ay[i];
+            //
+            // ay = u_add + v_add
+            (*this)(add_enum, ax_add, ay); // atomic vector add
+        }
+        // y^k = ay
+        copy_vec_to_mat(m, q, k, ay.begin(), aty.begin());
+    }
+}
+// --------------------------------------------------------------------------
+// reverse_mul
+template <class Base>
+void atomic_vector<Base>::reverse_mul(
+    size_t                                           m,
+    size_t                                           q,
+    const CppAD::vector<Base>&                       tx,
+    const CppAD::vector<Base>&                       ty,
+    CppAD::vector<Base>&                             px,
+    const CppAD::vector<Base>&                       py)
+{   size_t n = 2 * m;
+    assert( tx.size() == n * q );
+    assert( ty.size() == m * q );
+    assert( px.size() == n * q );
+    assert( py.size() == m * q );
+    //
+    // px
+    for(size_t j = 0; j < n; ++j)
+    {   for(size_t k = 0; k < q; ++k)
+            px[j * q + k] = 0.0;
+    }
+    //
+    // px
+    for(size_t i = 0; i < m; ++i)
+    {   // k
+        size_t k = q;
+        while(k)
+        {   --k;
+            //
+            // y_index
+            size_t y_index = i * q + k;
+            //
+            // px
+            for(size_t d = 0; d <= k; ++d)
+            {   size_t u_index  =       i * q + (k-d);
+                size_t v_index  = (m + i) * q + d;
+                //
+                // must use azmul becasue py[y_index] = 0 may mean that this
+                // component of the function was not selected.
+                px[u_index]    += CppAD::azmul( py[y_index] , tx[v_index] );
+                px[v_index]    += CppAD::azmul( py[y_index] , tx[u_index] );
+            }
+        }
+    }
+}
+template <class Base>
+void atomic_vector<Base>::reverse_mul(
+    size_t                                           m,
+    size_t                                           q,
+    const CppAD::vector< CppAD::AD<Base> >&          atx,
+    const CppAD::vector< CppAD::AD<Base> >&          aty,
+    CppAD::vector< CppAD::AD<Base> >&                apx,
+    const CppAD::vector< CppAD::AD<Base> >&          apy)
+{   size_t n = 2 * m;
+    assert( atx.size() == n * q );
+    assert( aty.size() == m * q );
+    assert( apx.size() == n * q );
+    assert( apy.size() == m * q );
+    //
+    // atu, atv, apu, apv
+    ad_const_iterator atu = atx.begin();
+    ad_const_iterator atv = atu + ad_difference_type(m * q);
+    ad_iterator       apu = apx.begin();
+    ad_iterator       apv = apu + ad_difference_type(m * q);
+    //
+    // ax_mul
+    // need azmul_op but it is not yet available
+    ad_vector ax_mul(n);
+    ad_iterator au_mul = ax_mul.begin();
+    ad_iterator av_mul = ax_mul.begin() + ad_difference_type(m);
+    //
+    // ax_add
+    ad_vector ax_add(n);
+    ad_iterator au_add = ax_add.begin();
+    ad_iterator av_add = ax_add.begin() + ad_difference_type(m);
+    //
+    // ay
+    ad_vector ay(m);
+    //
+    // px
+    // assigning to the value zero does not create operators on the tape
+    for(size_t j = 0; j < n; ++j)
+    {   for(size_t k = 0; k < q; ++k)
+            apx[j * q + k] = 0.0;
+    }
+    //
+    // k
+    size_t k = q;
+    while(k)
+    {   --k;
+        //
+        // au_mul = apy^k
+        copy_mat_to_vec(m, q, k, apy.begin(), au_mul);
+        //
+        // d
+        for(size_t d = 0; d <=k; ++d)
+        {   // -------------------------------------------------------------
+            // reverse:
+            //  px[v_index] += CppAD::azmul( py[y_index] , tx[u_index] );
+            // -------------------------------------------------------------
+
+            // av_mul = atu^{k-d}
+            copy_mat_to_vec(m, q, k-d, atu, av_mul);
+            //
+            // ay = au_mul * av_mul
+            (*this)(mul_enum, ax_mul, ay);
+            //
+            // au_add = ay
+            for(size_t i = 0; i < m; ++i)
+                au_add[i] = ay[i];
+            //
+            // av_add = apv^d
+            copy_mat_to_vec(m, q, d, apv, av_add);
+            //
+            // ay = au_add + av_add
+            (*this)(add_enum, ax_add, ay);
+            //
+            // apv^d =  ay
+            copy_vec_to_mat(m, q, d, ay.begin(), apv);
+            // -------------------------------------------------------------
+            // reverse:
+            //  px[u_index] += CppAD::azmul( py[y_index] , tx[v_index] );
+            // -------------------------------------------------------------
+            // av_mul = atv^{k-d}
+            copy_mat_to_vec(m, q, k-d, atv, av_mul);
+            //
+            // ay = au_mul * av_mul
+            (*this)(mul_enum, ax_mul, ay);
+            //
+            // au_add = ay
+            for(size_t i = 0; i < m; ++i)
+                au_add[i] = ay[i];
+            //
+            // av_add = apu^d
+            copy_mat_to_vec(m, q, d, apu, av_add);
+            //
+            // ay = au_add + av_add
+            (*this)(add_enum, ax_add, ay);
+            //
+            // apu^d =  ay
+            copy_vec_to_mat(m, q, d, ay.begin(), apu);
+        }
+    }
+}
+} // END_CPPAD_NAMESPACE
+// END C++
+# endif
diff --git a/include/cppad/example/atomic_four/vector/neg_op.hpp b/include/cppad/example/atomic_four/vector/neg_op.hpp
new file mode 100644
index 000000000..5ee4f4de4
--- /dev/null
+++ b/include/cppad/example/atomic_four/vector/neg_op.hpp
@@ -0,0 +1,133 @@
+# ifndef CPPAD_EXAMPLE_ATOMIC_FOUR_VECTOR_NEG_OP_HPP
+# define CPPAD_EXAMPLE_ATOMIC_FOUR_VECTOR_NEG_OP_HPP
+/* --------------------------------------------------------------------------
+CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
+
+CppAD is distributed under the terms of the
+             Eclipse Public License Version 2.0.
+
+This Source Code may also be made available under the following
+Secondary License when the conditions 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_four_vector_neg_op.hpp$$
+
+$section Atomic Vector Negative Operator: Example Implementation$$
+
+$head Example$$
+The file $cref atomic_four_vector_neg.cpp$$ contains an example
+and test for this operator.
+
+$head Source$$
+$srcthisfile%0%// BEGIN C++%// END C++%1%$$
+
+$end
+*/
+// BEGIN C++
+# include <cppad/example/atomic_four/vector/vector.hpp>
+
+namespace CppAD { // BEGIN_CPPAD_NAMESPACE
+// ---------------------------------------------------------------------------
+template <class Base>
+void atomic_vector<Base>::forward_neg(
+    size_t                                           m,
+    size_t                                           p,
+    size_t                                           q,
+    const CppAD::vector<Base>&                       tx,
+    CppAD::vector<Base>&                             ty)
+{
+    for(size_t k = p; k < q; ++k)
+    {   for(size_t i = 0; i < m; ++i)
+        {   size_t u_index  = i * q + k;
+            size_t y_index  = i * q + k;
+            // y_i^k = - u_i^k
+            ty[y_index] = - tx[u_index];
+        }
+    }
+}
+template <class Base>
+void atomic_vector<Base>::forward_neg(
+    size_t                                           m,
+    size_t                                           p,
+    size_t                                           q,
+    const CppAD::vector< CppAD::AD<Base> >&          atx,
+    CppAD::vector< CppAD::AD<Base> >&                aty)
+{   size_t n = m;
+    assert( atx.size() == n * q );
+    assert( aty.size() == m * q );
+    //
+    // atu
+    ad_const_iterator atu = atx.begin();
+    //
+    // ax
+    ad_vector ax(n);
+    ad_iterator au = ax.begin();
+    //
+    // ay
+    ad_vector ay(m);
+    //
+    for(size_t k = p; k < q; ++k)
+    {   // au = u^k
+        copy_mat_to_vec(m, q, k, atu, au);
+        // ay = - au
+        (*this)(neg_enum, ax, ay); // atomic vector neg
+        // y^k = ay
+        copy_vec_to_mat(m, q, k, ay.begin(), aty.begin() );
+    }
+}
+// ---------------------------------------------------------------------------
+// reverse_neg
+template <class Base>
+void atomic_vector<Base>::reverse_neg(
+    size_t                                           m,
+    size_t                                           q,
+    const CppAD::vector<Base>&                       tx,
+    const CppAD::vector<Base>&                       ty,
+    CppAD::vector<Base>&                             px,
+    const CppAD::vector<Base>&                       py)
+{
+    for(size_t k = 0; k < q; ++k)
+    {   for(size_t i = 0; i < m; ++i)
+        {   size_t u_index  = i * q + k;
+            size_t y_index  = i * q + k;
+            // y_i^k = - u_i^k
+            px[u_index] = - py[y_index];
+        }
+    }
+}
+template <class Base>
+void atomic_vector<Base>::reverse_neg(
+    size_t                                           m,
+    size_t                                           q,
+    const CppAD::vector< CppAD::AD<Base> >&          atx,
+    const CppAD::vector< CppAD::AD<Base> >&          aty,
+    CppAD::vector< CppAD::AD<Base> >&                apx,
+    const CppAD::vector< CppAD::AD<Base> >&          apy)
+{   size_t n = m;
+    assert( atx.size() == n * q );
+    assert( aty.size() == m * q );
+    //
+    // apu
+    ad_iterator apu = apx.begin();
+    //
+    // ax
+    ad_vector ax(n);
+    ad_iterator au = ax.begin();
+    //
+    // ay
+    ad_vector ay(m);
+    //
+    for(size_t k = 0; k < q; ++k)
+    {   // au = py^k
+        copy_mat_to_vec(m, q, k, apy.begin(), au);
+        // ay = - au
+        (*this)(neg_enum, ax, ay); // atomic vector neg
+        // pu^k = ay
+        copy_vec_to_mat(m, q, k, ay.begin(), apu);
+    }
+}
+} // END_CPPAD_NAMESPACE
+// END C++
+# endif
diff --git a/include/cppad/example/atomic_four/vector/rev_depend.hpp b/include/cppad/example/atomic_four/vector/rev_depend.hpp
new file mode 100644
index 000000000..f7e5f377c
--- /dev/null
+++ b/include/cppad/example/atomic_four/vector/rev_depend.hpp
@@ -0,0 +1,69 @@
+# ifndef CPPAD_EXAMPLE_ATOMIC_FOUR_VECTOR_REV_DEPEND_HPP
+# define CPPAD_EXAMPLE_ATOMIC_FOUR_VECTOR_REV_DEPEND_HPP
+/* --------------------------------------------------------------------------
+CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
+
+CppAD is distributed under the terms of the
+             Eclipse Public License Version 2.0.
+
+This Source Code may also be made available under the following
+Secondary License when the conditions 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_four_vector_rev_depend.hpp$$
+$spell
+    Jacobian
+    jac
+$$
+
+$section Atomic Vector Forward Type Calculation: Example Implementation$$
+
+$head Purpose$$
+The $code rev_depend$$ routine overrides the virtual functions
+used by the atomic_four base class for Jacobian sparsity calculations; see
+$cref/rev_depend/atomic_four_rev_depend/$$.
+
+$head Example$$
+The file $cref atomic_four_vector_rev_depend.cpp$$
+contains an example and test that uses this member function.
+
+$head Source$$
+$srcthisfile%0%// BEGIN C++%// END C++%1%$$
+$end
+*/
+// BEGIN C++
+# include <cppad/example/atomic_four/vector/vector.hpp>
+
+namespace CppAD { // BEGIN_CPPAD_NAMESPACE
+//
+// rev_depend override
+template <class Base>
+bool atomic_vector<Base>::rev_depend(
+    size_t                         call_id     ,
+    CppAD::vector<bool>&           depend_x    ,
+    const CppAD::vector<bool>&     depend_y    )
+{
+    // n, m
+    size_t n     = depend_x.size();
+    size_t m     = depend_y.size();
+    //
+    // type_y
+    if( n == m  )
+    {   // unary operator
+        for(size_t i = 0; i < m; ++i)
+            depend_x[i] = depend_y[i];
+    }
+    else
+    {   // binary operator
+        for(size_t i = 0; i < m; ++i)
+        {   depend_x[i]     = depend_y[i];
+            depend_x[m + i] = depend_y[i];
+        }
+    }
+    return true;
+}
+} // END_CPPAD_NAMESPACE
+// END C++
+# endif
diff --git a/include/cppad/example/atomic_four/vector/reverse_op.hpp b/include/cppad/example/atomic_four/vector/reverse_op.hpp
new file mode 100644
index 000000000..164ab4a87
--- /dev/null
+++ b/include/cppad/example/atomic_four/vector/reverse_op.hpp
@@ -0,0 +1,166 @@
+# ifndef CPPAD_EXAMPLE_ATOMIC_FOUR_VECTOR_REVERSE_OP_HPP
+# define CPPAD_EXAMPLE_ATOMIC_FOUR_VECTOR_REVERSE_OP_HPP
+/* --------------------------------------------------------------------------
+CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
+
+CppAD is distributed under the terms of the
+             Eclipse Public License Version 2.0.
+
+This Source Code may also be made available under the following
+Secondary License when the conditions 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_four_vector_reverse_op.hpp$$
+
+$section Atomic Vector Forward Mode: Example Implementation$$
+
+$head Purpose$$
+The $code reverse$$ routine overrides the virtual functions
+used by the atomic_four base class for reverse mode calculations; see
+$cref/reverse/atomic_four_reverse/$$.
+It determines which operator is specified for this call and transfers
+the call to the operator's implementation.
+There are two versions of the $code reverse$$ routine, one for $icode Base$$
+and one for $code AD<Base>$$.
+
+$head Source$$
+$srcthisfile%0%// BEGIN C++%// END C++%1%$$
+$end
+*/
+// BEGIN C++
+# include <cppad/example/atomic_four/vector/vector.hpp>
+
+namespace CppAD { // BEGIN_CPPAD_NAMESPACE
+//
+// reverse override
+// this routine used by ADFun<Base> objects
+template <class Base>
+bool atomic_vector<Base>::reverse(
+    size_t                                           call_id,
+    const CppAD::vector<bool>&                       select_x,
+    size_t                                           order_up,
+    const CppAD::vector<Base>&                       tx,
+    const CppAD::vector<Base>&                       ty,
+    CppAD::vector<Base>&                             px,
+    const CppAD::vector<Base>&                       py)
+{
+    // q
+    size_t q = order_up + 1;
+    //
+    // op, n, m
+    op_enum_t op = op_enum_t( call_id );
+    size_t n     = select_x.size();
+    size_t m  = n / 2;
+    if( is_unary(op) )
+        m = n;
+    assert( tx.size() == q * n );
+    assert( ty.size() == q * m );
+    //
+    bool ok = false;
+    switch(op)
+    {
+        // addition
+        case add_enum:
+        reverse_add(m, q, tx, ty, px, py);
+        ok = true;
+        break;
+
+        // subtraction
+        case sub_enum:
+        reverse_sub(m, q, tx, ty, px, py);
+        ok = true;
+        break;
+
+        // multiplication
+        case mul_enum:
+        reverse_mul(m, q, tx, ty, px, py);
+        ok = true;
+        break;
+
+        // division
+        case div_enum:
+        reverse_div(m, q, tx, ty, px, py);
+        ok = true;
+        break;
+
+        // unary minus
+        case neg_enum:
+        reverse_neg(m, q, tx, ty, px, py);
+        ok = true;
+        break;
+
+        // error
+        case number_op_enum:
+        assert(false);
+        break;
+    }
+    return ok;
+}
+// reverse override
+// this routine used by ADFun< CppAD::AD<Base> , Base> objects
+template <class Base>
+bool atomic_vector<Base>::reverse(
+    size_t                                           call_id,
+    const CppAD::vector<bool>&                       select_x,
+    size_t                                           order_up,
+    const CppAD::vector< CppAD::AD<Base> >&          atx,
+    const CppAD::vector< CppAD::AD<Base> >&          aty,
+    CppAD::vector< CppAD::AD<Base> >&                apx,
+    const CppAD::vector< CppAD::AD<Base> >&          apy)
+{
+    // q
+    size_t q = order_up + 1;
+    //
+    // op, m
+    op_enum_t op = op_enum_t( call_id );
+    size_t n     = select_x.size();
+    size_t m  = n / 2;
+    if( is_unary(op) )
+        m = n;
+    assert( atx.size() == q * n );
+    assert( aty.size() == q * m );
+    bool ok = false;
+    switch(op)
+    {
+        // addition
+        case add_enum:
+        reverse_add(m, q, atx, aty, apx, apy);
+        ok = true;
+        break;
+
+        // subtraction
+        case sub_enum:
+        reverse_sub(m, q, atx, aty, apx, apy);
+        ok = true;
+        break;
+
+        // multiplication
+        case mul_enum:
+        reverse_mul(m, q, atx, aty, apx, apy);
+        ok = true;
+        break;
+
+        // division
+        case div_enum:
+        reverse_div(m, q, atx, aty, apx, apy);
+        ok = true;
+        break;
+
+        // unary minus
+        case neg_enum:
+        reverse_neg(m, q, atx, aty, apx, apy);
+        ok = true;
+        break;
+
+        // error
+        case number_op_enum:
+        assert(false);
+        break;
+    }
+    return ok;
+}
+} // END_CPPAD_NAMESPACE
+// END C++
+# endif
diff --git a/include/cppad/example/atomic_four/vector/sub_op.hpp b/include/cppad/example/atomic_four/vector/sub_op.hpp
new file mode 100644
index 000000000..fb270c086
--- /dev/null
+++ b/include/cppad/example/atomic_four/vector/sub_op.hpp
@@ -0,0 +1,158 @@
+# ifndef CPPAD_EXAMPLE_ATOMIC_FOUR_VECTOR_SUB_OP_HPP
+# define CPPAD_EXAMPLE_ATOMIC_FOUR_VECTOR_SUB_OP_HPP
+/* --------------------------------------------------------------------------
+CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
+
+CppAD is distributed under the terms of the
+             Eclipse Public License Version 2.0.
+
+This Source Code may also be made available under the following
+Secondary License when the conditions 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_four_vector_sub_op.hpp$$
+
+$section Atomic Vector Subtract Operator: Example Implementation$$
+
+$head Forward Mode$$
+see theory for forward mode
+$cref/subtraction/ForwardTheory/Binary Operators/Subtraction/$$.
+
+$head Reverse Mode$$
+see theory for reverse mode
+$cref/subtraction/ReverseTheory/Binary Operators/Subtraction/$$.
+
+$head Example$$
+The file $cref atomic_four_vector_sub.cpp$$ contains an example
+and test for this operator.
+
+$head Source$$
+$srcthisfile%0%// BEGIN C++%// END C++%1%$$
+
+$end
+*/
+// BEGIN C++
+# include <cppad/example/atomic_four/vector/vector.hpp>
+
+namespace CppAD { // BEGIN_CPPAD_NAMESPACE
+// --------------------------------------------------------------------------
+// forward_sub
+template <class Base>
+void atomic_vector<Base>::forward_sub(
+    size_t                                           m,
+    size_t                                           p,
+    size_t                                           q,
+    const CppAD::vector<Base>&                       tx,
+    CppAD::vector<Base>&                             ty)
+{
+    for(size_t k = p; k < q; ++k)
+    {   for(size_t i = 0; i < m; ++i)
+        {   size_t u_index  =       i * q + k;
+            size_t v_index  = (m + i) * q + k;
+            size_t y_index  =       i * q + k;
+            // y_i^k = u_i^k - v_i^k
+            ty[y_index]     = tx[u_index] - tx[v_index];
+        }
+    }
+}
+template <class Base>
+void atomic_vector<Base>::forward_sub(
+    size_t                                           m,
+    size_t                                           p,
+    size_t                                           q,
+    const CppAD::vector< CppAD::AD<Base> >&          atx,
+    CppAD::vector< CppAD::AD<Base> >&                aty)
+{
+    size_t n = 2 * m;
+    assert( atx.size() == n * q );
+    assert( aty.size() == m * q );
+    //
+    // atu, atv
+    ad_const_iterator atu = atx.begin();
+    ad_const_iterator atv = atu + ad_difference_type(m * q);
+    //
+    // ax
+    ad_vector ax(n);
+    ad_iterator au = ax.begin();
+    ad_iterator av = au + ad_difference_type(m);
+    //
+    // ay
+    ad_vector ay(m);
+    //
+    for(size_t k = p; k < q; ++k)
+    {   // au = u^k
+        copy_mat_to_vec(m, q, k, atu, au);
+        // av = v^k
+        copy_mat_to_vec(m, q, k, atv, av);
+        // ay = au - av
+        (*this)(sub_enum, ax, ay); // atomic vector sub
+        // y^k = ay
+        copy_vec_to_mat(m, q, k, ay.begin(), aty.begin());
+    }
+}
+// --------------------------------------------------------------------------
+// reverse_sub
+template <class Base>
+void atomic_vector<Base>::reverse_sub(
+    size_t                                           m,
+    size_t                                           q,
+    const CppAD::vector<Base>&                       tx,
+    const CppAD::vector<Base>&                       ty,
+    CppAD::vector<Base>&                             px,
+    const CppAD::vector<Base>&                       py)
+{
+    for(size_t k = 0; k < q; ++k)
+    {   for(size_t i = 0; i < m; ++i)
+        {   size_t u_index  =       i * q + k;
+            size_t v_index  = (m + i) * q + k;
+            size_t y_index  =       i * q + k;
+            // y_i^k = u_i^k + v_i^k
+            px[u_index] =   py[y_index];
+            px[v_index] = - py[y_index];
+        }
+    }
+}
+template <class Base>
+void atomic_vector<Base>::reverse_sub(
+    size_t                                           m,
+    size_t                                           q,
+    const CppAD::vector< CppAD::AD<Base> >&          atx,
+    const CppAD::vector< CppAD::AD<Base> >&          aty,
+    CppAD::vector< CppAD::AD<Base> >&                apx,
+    const CppAD::vector< CppAD::AD<Base> >&          apy)
+{
+# ifndef NDEBUG
+    size_t n = 2 * m;
+    assert( atx.size() == n * q );
+    assert( aty.size() == m * q );
+    assert( apx.size() == n * q );
+    assert( apy.size() == m * q );
+# endif
+    //
+    // apu, apv
+    ad_iterator apu = apx.begin();
+    ad_iterator apv = apu + ad_difference_type(m * q);
+    //
+    // ax
+    ad_vector ax(m);
+    ad_iterator au = ax.begin();
+    //
+    // ay
+    ad_vector ay(m);
+    //
+    for(size_t k = 0; k < q; ++k)
+    {   // au = apy^k
+        copy_mat_to_vec(m, q, k, apy.begin(), au);
+        // apu^k = au
+        copy_vec_to_mat(m, q, k, au, apu);
+        // ay = - au
+        (*this)(neg_enum, ax, ay); // atomic vector neg
+        // apv^k = ay
+        copy_vec_to_mat(m, q, k, ay.begin(), apv);
+    }
+}
+} // END_CPPAD_NAMESPACE
+// END C++
+# endif
diff --git a/include/cppad/example/atomic_four/vector/vector.hpp b/include/cppad/example/atomic_four/vector/vector.hpp
new file mode 100644
index 000000000..606980b67
--- /dev/null
+++ b/include/cppad/example/atomic_four/vector/vector.hpp
@@ -0,0 +1,235 @@
+# ifndef CPPAD_EXAMPLE_ATOMIC_FOUR_VECTOR_VECTOR_HPP
+# define CPPAD_EXAMPLE_ATOMIC_FOUR_VECTOR_VECTOR_HPP
+
+/* --------------------------------------------------------------------------
+CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
+
+CppAD is distributed under the terms of the
+             Eclipse Public License Version 2.0.
+
+This Source Code may also be made available under the following
+Secondary License when the conditions 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_four_vector.hpp$$
+
+$section Atomic Vector Class: Example Implementation$$
+
+$srcthisfile%0%// BEGIN C++%// END C++%1%$$
+$end
+*/
+// BEGIN C++
+# include <cppad/cppad.hpp>
+
+// declare forward_op and reverse_op for Base and AD<Base> cases
+// where op is an operator name; e.g., forward_add and reverse_add.
+# define CPPAD_ATOMIC_FOUR_FORWARD_AND_REVERSE(op)             \
+    static void forward_ ## op(                                \
+        size_t                                           m,    \
+        size_t                                           p,    \
+        size_t                                           q,    \
+        const CppAD::vector<Base>&                       tx,   \
+        CppAD::vector<Base>&                             ty    \
+    );                                                         \
+    void forward_ ## op(                                       \
+        size_t                                           m,    \
+        size_t                                           p,    \
+        size_t                                           q,    \
+        const CppAD::vector< CppAD::AD<Base> >&          atx,  \
+        CppAD::vector< CppAD::AD<Base> >&                aty   \
+    );                                                         \
+    static void reverse_ ## op(                                \
+        size_t                                           m,    \
+        size_t                                           q,    \
+        const CppAD::vector<Base>&                       tx,   \
+        const CppAD::vector<Base>&                       ty,   \
+        CppAD::vector<Base>&                             px,   \
+        const CppAD::vector<Base>&                       py    \
+    );                                                         \
+    void reverse_ ## op(                                       \
+        size_t                                           m,    \
+        size_t                                           q,    \
+        const CppAD::vector< CppAD::AD<Base> >&          atx,  \
+        const CppAD::vector< CppAD::AD<Base> >&          aty,  \
+        CppAD::vector< CppAD::AD<Base> >&                apx,  \
+        const CppAD::vector< CppAD::AD<Base> >&          apy   \
+    );
+
+namespace CppAD { // BEGIN_CPPAD_NAMESPACE
+//
+template <class Base>
+class atomic_vector : public CppAD::atomic_four<Base> {
+//
+public:
+    // BEGIN_SORT_THIS_LINE_PLUS_4
+    // BEGIN op_enum_t
+    // atomic_vector::op_enum_t
+    typedef enum {
+        add_enum,
+        div_enum,
+        mul_enum,
+        neg_enum,
+        sub_enum,
+        number_op_enum
+    } op_enum_t;
+    // END op_enum_t
+    // END_SORT_THIS_LINE_MINUS_4
+    //
+    // ctor
+    atomic_vector(const std::string& name) :
+    CppAD::atomic_four<Base>(name)
+    { }
+private:
+    typedef CppAD::vector< CppAD::AD<Base> >      ad_vector;
+    typedef typename ad_vector::iterator          ad_iterator;
+    typedef typename ad_vector::const_iterator    ad_const_iterator;
+    typedef typename ad_iterator::difference_type ad_difference_type;
+    //
+    static bool is_unary(op_enum_t op)
+    {   bool result = true;
+        switch(op)
+        {   case add_enum:
+            case sub_enum:
+            case mul_enum:
+            case div_enum:
+            result = false;
+            break;
+
+            default:
+            break;
+        }
+        return result;
+    }
+    // ------------------------------------------------------------------------
+    // copy routines
+    // ------------------------------------------------------------------------
+    static void copy_vec_to_mat(
+        size_t            m,
+        size_t            q,
+        size_t            k ,
+        ad_const_iterator vec,
+        ad_iterator       mat)
+    {   for(size_t i = 0; i < m; ++i)
+        {   size_t index  = i * q + k;
+            *(mat + ad_difference_type(index) ) =
+                *(vec + ad_difference_type(i) );
+        }
+    }
+    // copy_mat_to_vec
+    static void copy_mat_to_vec(
+        size_t            m,
+        size_t            q,
+        size_t            k,
+        ad_const_iterator mat,
+        ad_iterator       vec)
+    {   for(size_t i = 0; i < m; ++i)
+        {   size_t index  = i * q + k;
+            *(vec + ad_difference_type(i) ) =
+                *(mat + ad_difference_type(index) );
+        }
+    }
+    // -----------------------------------------------------------------------
+    // overrides
+    // -----------------------------------------------------------------------
+    //
+    // for_type
+    bool for_type(
+        size_t                                     call_id     ,
+        const CppAD::vector<CppAD::ad_type_enum>&  type_x      ,
+        CppAD::vector<CppAD::ad_type_enum>&        type_y
+    ) override;
+    //
+    // rev_depend
+    bool rev_depend(
+        size_t                         call_id     ,
+        CppAD::vector<bool>&           depend_x    ,
+        const CppAD::vector<bool>&     depend_y
+    ) override;
+    //
+    // jac_sparsity
+    bool jac_sparsity(
+        size_t                                         call_id      ,
+        bool                                           dependency   ,
+        const CppAD::vector<bool>&                     select_x     ,
+        const CppAD::vector<bool>&                     select_y     ,
+        CppAD::sparse_rc< CppAD::vector<size_t> >&     pattern_out
+    ) override;
+    //
+    // hes_sparsity
+    bool hes_sparsity(
+        size_t                                         call_id      ,
+        const CppAD::vector<bool>&                     select_x     ,
+        const CppAD::vector<bool>&                     select_y     ,
+        CppAD::sparse_rc< CppAD::vector<size_t> >&     pattern_out
+    ) override;
+    //
+    // Base forward
+    bool forward(
+        size_t                                           call_id,
+        const CppAD::vector<bool>&                       select_y,
+        size_t                                           order_low,
+        size_t                                           order_up,
+        const CppAD::vector<Base>&                       tx,
+        CppAD::vector<Base>&                             ty
+    ) override;
+    //
+    // AD<Base> forward
+    bool forward(
+        size_t                                           call_id,
+        const CppAD::vector<bool>&                       select_y,
+        size_t                                           order_low,
+        size_t                                           order_up,
+        const CppAD::vector< CppAD::AD<Base> >&          atx,
+        CppAD::vector< CppAD::AD<Base> >&                aty
+    ) override;
+    //
+    // Base reverse
+    bool reverse(
+        size_t                                           call_id,
+        const CppAD::vector<bool>&                       select_x,
+        size_t                                           order_up,
+        const CppAD::vector<Base>&                       tx,
+        const CppAD::vector<Base>&                       ty,
+        CppAD::vector<Base>&                             px,
+        const CppAD::vector<Base>&                       py
+    ) override;
+    //
+    // AD<Base> reverse
+    bool reverse(
+        size_t                                           call_id,
+        const CppAD::vector<bool>&                       select_x,
+        size_t                                           order_up,
+        const CppAD::vector< CppAD::AD<Base> >&          atx,
+        const CppAD::vector< CppAD::AD<Base> >&          aty,
+        CppAD::vector< CppAD::AD<Base> >&                apx,
+        const CppAD::vector< CppAD::AD<Base> >&          apy
+    ) override;
+    // ----------------------------------------------------------------------
+    // Forward and Reverse Implementation Routines
+    // ----------------------------------------------------------------------
+    CPPAD_ATOMIC_FOUR_FORWARD_AND_REVERSE(add)
+    CPPAD_ATOMIC_FOUR_FORWARD_AND_REVERSE(sub)
+    CPPAD_ATOMIC_FOUR_FORWARD_AND_REVERSE(mul)
+    CPPAD_ATOMIC_FOUR_FORWARD_AND_REVERSE(div)
+    CPPAD_ATOMIC_FOUR_FORWARD_AND_REVERSE(neg)
+};
+} // END_CPPAD_NAMESPACE
+
+# undef CPPAD_ATOMIC_FOUR_FORWARD_AND_REVERSE
+
+# include <cppad/example/atomic_four/vector/rev_depend.hpp>
+# include <cppad/example/atomic_four/vector/for_type.hpp>
+# include <cppad/example/atomic_four/vector/jac_sparsity.hpp>
+# include <cppad/example/atomic_four/vector/hes_sparsity.hpp>
+# include <cppad/example/atomic_four/vector/reverse_op.hpp>
+# include <cppad/example/atomic_four/vector/forward_op.hpp>
+# include <cppad/example/atomic_four/vector/neg_op.hpp>
+# include <cppad/example/atomic_four/vector/div_op.hpp>
+# include <cppad/example/atomic_four/vector/mul_op.hpp>
+# include <cppad/example/atomic_four/vector/sub_op.hpp>
+# include <cppad/example/atomic_four/vector/add_op.hpp>
+// END C++
+
+# endif
diff --git a/include/cppad/example/atomic_four/vector/vector.omh b/include/cppad/example/atomic_four/vector/vector.omh
new file mode 100644
index 000000000..eb2c199b5
--- /dev/null
+++ b/include/cppad/example/atomic_four/vector/vector.omh
@@ -0,0 +1,117 @@
+/* --------------------------------------------------------------------------
+CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
+
+CppAD is distributed under the terms of the
+             Eclipse Public License Version 2.0.
+
+This Source Code may also be made available under the following
+Secondary License when the conditions 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_four_vector$$
+$spell
+    op
+    enum
+    mul
+    div
+    vec_op
+$$
+
+$section Atomic Vector Element-wise Operators: Example and Test$$
+
+$head Syntax$$
+$codei%atomic_vector_op %vec_op%(%name%)
+%$$
+$icode%vec_op%(%op%, %x%, %y%)
+%$$
+
+$head op$$
+The value $icode op$$ has the following possible values:
+$srcfile%
+    include/cppad/example/atomic_four/vector/vector.hpp%
+    0%// BEGIN op_enum_t%// END op_enum_t%0
+%$$
+
+$head Purpose$$
+This atomic function class can be used as a general purpose utility.
+It is unclear how much benefit there is do doing so.
+This is because the number of operations internal to an element-wise
+atomic function is not much more than the work required to pass the
+arguments to the atomic function.
+
+$subhead Vector Operations$$
+This atomic function unary operations
+$codei%
+    %y% = %op%(u)
+%$$
+and binary operations
+$codei%
+    %y% = %u% %op% %v%
+%$$
+where $icode op$$, $icode u$$ and $icode v$$ are defined below.
+
+$subhead atomic_four$$
+This example demonstrates all the callbacks for an
+$cref atomic_four$$ function.
+
+$subhead base2ad$$
+It include examples for how one can
+define $codei%AD<%Base%>%$$ atomic operations using atomic operators.
+This avoids expanding the atomic operator to an operator for each element
+when recording derivative calculations.
+For example, notice the difference between $code forward_add$$
+for the $code double$$ and the $code AD<double>$$ cases
+(note that copying an AD variable does not create a new variable):
+$srcfile%
+    include/cppad/example/atomic_four/vector/add_op.hpp%
+    0%// BEGIN forward_add%// END forward_add%0
+%$$
+
+$head x$$
+We use $icode x$$ to denote the argument to the atomic function.
+The length of $icode x$$ is denoted by $icode n$$.
+
+$head m$$
+This is the length of the vectors in the operations.
+In the case of unary (binary) operators
+$code%m% = %n%$$  ( $icode%m% = %n% / 2%$$ ).
+
+$head u$$
+We use $icode u$$ to denote the following sub-vector of $icode x$$:
+$codei%
+    %u% = ( %x%[1] , %...% , %x%[%m%] )
+%$$
+
+$head v$$
+For binary operators,
+we use $icode v$$ to denote the following sub-vector of $icode x$$:
+$codei%
+    %v% = ( %x%[%m% + 1] , %...% , %x%[2 * %m%] )
+%$$
+
+$head y$$
+We use $icode y$$ to denote the atomic function return value.
+The length of $icode y$$ is equal to $icode m$$.
+
+$head AD<double>$$
+During $code AD<double>$$ operations, copying variables
+from one vector to another does not add any operations to the
+resulting tape.
+
+
+$comment BEGIN_SORT_THIS_LINE_PLUS_3$$
+$childtable%
+    include/cppad/example/atomic_four/vector/implement.omh
+    %example/atomic_four/vector/add.cpp
+    %example/atomic_four/vector/div.cpp
+    %example/atomic_four/vector/hes_sparsity.cpp
+    %example/atomic_four/vector/jac_sparsity.cpp
+    %example/atomic_four/vector/mul.cpp
+    %example/atomic_four/vector/neg.cpp
+    %example/atomic_four/vector/rev_depend.cpp
+    %example/atomic_four/vector/sub.cpp
+%$$
+$comment END_SORT_THIS_LINE_MINUS_2$$
+
+$end
diff --git a/include/cppad/example/atomic_three/mat_mul.hpp b/include/cppad/example/atomic_three/mat_mul.hpp
index b0c1af487..d0f875ba5 100644
--- a/include/cppad/example/atomic_three/mat_mul.hpp
+++ b/include/cppad/example/atomic_three/mat_mul.hpp
@@ -1,7 +1,7 @@
 # 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: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
 
 CppAD is distributed under the terms of the
              Eclipse Public License Version 2.0.
@@ -38,12 +38,12 @@ that computes the matrix product for $code AD<double$$ operations.
 
 $subhead parameter_x$$
 This example demonstrates the use of the
-$cref/parameter_x/atomic_three/parameter_x/$$
+$cref/parameter_x/atomic_three_define/parameter_x/$$
 argument to the $cref atomic_three$$ virtual functions.
 
 $subhead type_x$$
 This example also demonstrates the use of the
-$cref/type_x/atomic_three/type_x/$$
+$cref/type_x/atomic_three_define/type_x/$$
 argument to the $cref atomic_three$$ virtual functions.
 
 $head Matrix Dimensions$$
diff --git a/include/cppad/example/code_gen_fun.hpp b/include/cppad/example/code_gen_fun.hpp
index 6f7efdc52..af6a40c2d 100644
--- a/include/cppad/example/code_gen_fun.hpp
+++ b/include/cppad/example/code_gen_fun.hpp
@@ -1,7 +1,7 @@
 # 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: C++ Algorithmic Differentiation: Copyright (C) 2003-21 Bradley M. Bell
 
   CppAD is distributed under the terms of the
                Eclipse Public License Version 2.0.
@@ -14,7 +14,21 @@ CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
 // BEGIN C++
 # include <cppad/cg/cppadcg.hpp>
 
-class code_gen_fun {
+// See https://docs.microsoft.com/en-us/cpp/cpp/
+//      using-dllimport-and-dllexport-in-cpp-classes?view=msvc-160
+// Also see define.hpp where CPPAD_LIB_EXPORTS is also defined and
+// undef.hpp where it gets undefined.
+# 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
+
+class CPPAD_LIB_EXPORT code_gen_fun {
 public:
     // type of evaluation for Jacobians (possibly Hessians in the future)
     enum evaluation_enum { none_enum, dense_enum, sparse_enum };
diff --git a/include/cppad/ipopt/solve_callback.hpp b/include/cppad/ipopt/solve_callback.hpp
index 898f6ff14..e24265d17 100644
--- a/include/cppad/ipopt/solve_callback.hpp
+++ b/include/cppad/ipopt/solve_callback.hpp
@@ -1,7 +1,7 @@
 # ifndef CPPAD_IPOPT_SOLVE_CALLBACK_HPP
 # define CPPAD_IPOPT_SOLVE_CALLBACK_HPP
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
+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.
@@ -254,9 +254,9 @@ public:
         x0_.resize(nx);
         fg0_.resize(nfg);
         for(i = 0; i < nx_; i++)
-            x0_[i] = CppAD::nan(0.0);
+            x0_[i] = std::numeric_limits<double>::quiet_NaN();
         for(i = 0; i < nfg; i++)
-            fg0_[i] = CppAD::nan(0.0);
+            fg0_[i] = std::numeric_limits<double>::quiet_NaN();
 
         if( ! retape_ )
         {   // make adfun_ correspond to x -> [ f(x), g(x) ]
diff --git a/include/cppad/local/ad_tape.hpp b/include/cppad/local/ad_tape.hpp
index d0f19af10..87b4aeb6f 100644
--- a/include/cppad/local/ad_tape.hpp
+++ b/include/cppad/local/ad_tape.hpp
@@ -1,7 +1,7 @@
 # ifndef CPPAD_LOCAL_AD_TAPE_HPP
 # define CPPAD_LOCAL_AD_TAPE_HPP
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
+CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
 
 CppAD is distributed under the terms of the
              Eclipse Public License Version 2.0.
@@ -31,6 +31,7 @@ class ADTape {
     friend class ADFun<Base>;
     friend class atomic_base<Base>;
     friend class atomic_three<Base>;
+    friend class atomic_four<Base>;
     friend class discrete<Base>;
     friend class VecAD<Base>;
     friend class VecAD_reference<Base>;
@@ -65,7 +66,7 @@ class ADTape {
         (const AD<Base> &u);
     // operators -----------------------------------------------------------
     // arithematic binary operators
-# if _MSC_VER
+# if _MSC_VER && !defined(__clang__)
     // see https://stackoverflow.com/questions/63288453
     template <class Type> friend AD<Type> CppAD::operator * <Type>
         (const AD<Type> &left, const AD<Type> &right);
@@ -81,7 +82,7 @@ class ADTape {
         (const AD<Base> &left, const AD<Base> &right);
 
     // comparison operators
-# if _MSC_VER
+# if _MSC_VER && !defined(__clang__)
     template <class Type> friend bool CppAD::operator == <Type>
         (const AD<Type> &left, const AD<Type> &right);
     template <class Type> friend bool CppAD::operator != <Type>
diff --git a/include/cppad/local/atomic_index.hpp b/include/cppad/local/atomic_index.hpp
index ce6e88bae..b2529ffc9 100644
--- a/include/cppad/local/atomic_index.hpp
+++ b/include/cppad/local/atomic_index.hpp
@@ -1,7 +1,7 @@
 # ifndef CPPAD_LOCAL_ATOMIC_INDEX_HPP
 # define CPPAD_LOCAL_ATOMIC_INDEX_HPP
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
+CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
 
 CppAD is distributed under the terms of the
              Eclipse Public License Version 2.0.
@@ -15,6 +15,7 @@ in the Eclipse Public License, Version 2.0 are satisfied:
 $begin atomic_index$$
 $spell
     ptr
+    Cpp
 $$
 
 $section Store and Retrieve Atomic Function Information by Index$$
@@ -33,8 +34,8 @@ $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,
+$head Get Number Case$$
+The get number case is defined by
 $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%>%$$
@@ -43,13 +44,19 @@ 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.
+If $icode set_null$$ is true and $icode index_in$$ is zero,
+this argument is just used to signal the get number case.
+Otherwise, $icode set_null$$
+should only be true during a call to an atomic function destructor.
+In this case, the $icode ptr$$ corresponding to $icode index_in$$
+is set to null
+(so that CppAD knows the corresponding atomic function no longer works).
 
 $head index_in$$
-If this is not the special case:
+If $icode index_in$$ is zero and $icode set_null$$ is true,
+this argument is just used to signal the get number case.
+Otherwise, see below:
+
 
 $subhead zero$$
 The value $icode index_in$$ should only be zero
@@ -64,33 +71,35 @@ 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.
+This argument is not used in the get number case.
+Otherwise if $icode index_in$$ is zero, $icode type$$ is an input.
+Otherwise it is set to the value corresponding to $icode index_in$$.
+The type corresponding to an index is intended to be
+2 for $cref atomic_two$$ functions,
+3 for $cref atomic_three$$ functions, and
+4 for $cref atomic_four$$ 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.
+This argument is not used in the get number case.
+Otherwise if $icode index_in$$ is zero,
+$icode 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.
+This argument is not used in the get number case.
+Otherwise 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
+In the get number case, this is the number of atomic functions.
+Otherwise if $icode index_in$$ is zero,
+$icode index_out$$ is non-zero and is the $icode index_in$$ value
 corresponding to the input values for
 $icode type$$, $codei%*%name%$$, and $icode ptr$$.
 Otherwise, $index_out$$ is zero.
diff --git a/include/cppad/local/cppad_colpack.hpp b/include/cppad/local/cppad_colpack.hpp
index ee96ab5fe..6dd022180 100644
--- a/include/cppad/local/cppad_colpack.hpp
+++ b/include/cppad/local/cppad_colpack.hpp
@@ -59,7 +59,7 @@ it is not the case that both
 This routine tries to minimize, with respect to the choice of colors,
 the number of colors.
 */
-extern void cppad_colpack_general(
+CPPAD_LIB_EXPORT void cppad_colpack_general(
           CppAD::vector<size_t>&         color         ,
     size_t                               m             ,
     size_t                               n             ,
@@ -91,7 +91,7 @@ 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_LIB_EXPORT void cppad_colpack_symmetric(
           CppAD::vector<size_t>&         color         ,
     size_t                               n             ,
     const CppAD::vector<unsigned int*>&  adolc_pattern
diff --git a/include/cppad/local/declare_ad.hpp b/include/cppad/local/declare_ad.hpp
index 1b75f8b66..bc4b79386 100644
--- a/include/cppad/local/declare_ad.hpp
+++ b/include/cppad/local/declare_ad.hpp
@@ -1,7 +1,7 @@
 # ifndef CPPAD_LOCAL_DECLARE_AD_HPP
 # define CPPAD_LOCAL_DECLARE_AD_HPP
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
+CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
 
 CppAD is distributed under the terms of the
              Eclipse Public License Version 2.0.
@@ -51,6 +51,7 @@ namespace CppAD {
     template <class Base, class RecBase=Base> class ADFun;
     template <class Base> class atomic_base;
     template <class Base> class atomic_three;
+    template <class Base> class atomic_four;
     template <class Base> class discrete;
     template <class Base> class VecAD;
     template <class Base> class VecAD_reference;
diff --git a/include/cppad/local/define.hpp b/include/cppad/local/define.hpp
index 8c52b377e..47e91d811 100644
--- a/include/cppad/local/define.hpp
+++ b/include/cppad/local/define.hpp
@@ -1,7 +1,7 @@
 # ifndef CPPAD_LOCAL_DEFINE_HPP
 # define CPPAD_LOCAL_DEFINE_HPP
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 Bradley M. Bell
+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.
@@ -61,6 +61,9 @@ This macro is defined as empty for Microsoft compilers.
 Special macro for exporting windows DLL symbols; see
 https://gitlab.kitware.com/cmake/community/wikis/doc/tutorials/BuildingWinDLL
 */
+/*
+This commented out code is for building windows shared libraries which
+currently does not work for CppAD:
 # ifdef  _MSC_VER
 # ifdef  cppad_lib_EXPORTS
 # define CPPAD_LIB_EXPORT __declspec(dllexport)
@@ -70,7 +73,8 @@ https://gitlab.kitware.com/cmake/community/wikis/doc/tutorials/BuildingWinDLL
 # else   // _MSC_VER
 # define CPPAD_LIB_EXPORT
 # endif
-
+*/
+# define CPPAD_LIB_EXPORT
 
 // ============================================================================
 /*!
diff --git a/include/cppad/local/graph/cpp_graph_itr.hpp b/include/cppad/local/graph/cpp_graph_itr.hpp
index deb5ebdf1..75e260ffa 100644
--- a/include/cppad/local/graph/cpp_graph_itr.hpp
+++ b/include/cppad/local/graph/cpp_graph_itr.hpp
@@ -1,7 +1,7 @@
 # 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: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
 
 CppAD is distributed under the terms of the
              Eclipse Public License Version 2.0.
@@ -35,16 +35,17 @@ private:
     size_t                         op_index_;
     size_t                         first_arg_;
     //
-    // set by get_value
-    size_t                         first_node_;
+    // set by set_value
     graph_op_enum                  op_enum_;
-    vector<size_t>                 str_index_;
+    size_t                         first_node_;
     size_t                         n_result_;
+    size_t                         call_id_;
+    vector<size_t>                 str_index_;
     vector<size_t>                 arg_node_;
 /* %$$
 $end
 ------------------------------------------------------------------------------
-$begin cpp_graph_itr_get_value$$
+$begin cpp_graph_itr_set_value$$
 $spell
     obj
     op
@@ -56,10 +57,10 @@ $spell
     str
 $$
 
-$section C++ AD Graph Iterator get_value()$$
+$section C++ AD Graph Iterator set_value()$$
 
 $head Syntax$$
-$icode%itr%.get_value()%$$
+$icode%itr%.set_value()%$$
 
 $head op_index_$$
 This input is the operator index for the value we are retrieving.
@@ -81,8 +82,8 @@ 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$$,
+$subhead atom_graph_op, atom4_graph_op$$
+If $icode op_enum_$$ is $code atom_graph_op$$ or $code atom4_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/$$
@@ -107,6 +108,13 @@ $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 call_id_$$
+If $icode op_enum_$$ is $code atom4_graph_op$$,
+$code call_id_$$ is set to the $cref/call_id/atomic_four_call/call_id/$$
+for this function call.
+If $icode op_enum_$$ is $code atom_graph_op$$,
+$code call_id$$ is set to zero.
+
 $head arg_node_$$
 The input value of this argument does not matter.
 Upon return, its size is the number of arguments,
@@ -115,7 +123,7 @@ The value of the elements are the node indices.
 
 $head Prototype$$
 $srccode%hpp% */
-    void get_value(void)
+    void set_value(void)
 /* %$$
 $end
 */
@@ -124,13 +132,14 @@ $end
     size_t n_arg      = invalid_index;
     first_node_       = invalid_index;
     n_result_         = invalid_index;
+    call_id_          = invalid_index;
     str_index_.resize(0);
     arg_node_.resize(0);
     //
     // op_enum
     op_enum_          = (*operator_vec_)[op_index_];
     //
-    // n_result_, n_arg, str_index_
+    // n_result_, n_arg, call_id_, str_index_
     switch( op_enum_ )
     {
         // unary operators
@@ -149,6 +158,7 @@ $end
         case expm1_graph_op:
         case log1p_graph_op:
         case log_graph_op:
+        case neg_graph_op:
         case sign_graph_op:
         case sin_graph_op:
         case sinh_graph_op:
@@ -180,11 +190,20 @@ $end
         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] );
+        call_id_    = 0;
+        n_result_   = (*operator_arg_)[first_node_ - 2];
+        n_arg       = (*operator_arg_)[first_node_ - 1];
+        break;
+
+        // atom4_graph_op
+        case atom4_graph_op:
+        first_node_ = first_arg_ + 4;
+        str_index_.push_back( (*operator_arg_)[first_node_ - 4] );
+        call_id_    = (*operator_arg_)[first_node_ - 3];
         n_result_   = (*operator_arg_)[first_node_ - 2];
         n_arg       = (*operator_arg_)[first_node_ - 1];
         break;
@@ -250,8 +269,9 @@ $srccode%hpp% */
 public:
     typedef struct {
         graph_op_enum          op_enum;
-        const vector<size_t>*  str_index_ptr;
         size_t                 n_result;
+        size_t                 call_id;
+        const vector<size_t>*  str_index_ptr;
         const vector<size_t>*  arg_node_ptr;
     } value_type;
     typedef std::input_iterator_tag    iterator_category;
@@ -325,7 +345,7 @@ $end
         first_arg_ = 0;
         //
         // get the value, and first_node_, for this operator
-        get_value();
+        set_value();
     }
 /* %$$
 ------------------------------------------------------------------------------
@@ -355,8 +375,9 @@ $srccode%hpp% */
         );
         value_type ret;
         ret.op_enum       = op_enum_;
-        ret.str_index_ptr = &str_index_;
         ret.n_result      = n_result_;
+        ret.call_id       = call_id_;
+        ret.str_index_ptr = &str_index_;
         ret.arg_node_ptr  = &arg_node_;
         return ret;
     }
@@ -364,7 +385,7 @@ $srccode%hpp% */
     cpp_graph_itr& operator++(void)
     {   ++op_index_;
         first_arg_ = first_node_ + arg_node_.size();
-        get_value();
+        set_value();
         return *this;
     }
     // itr++
@@ -372,7 +393,7 @@ $srccode%hpp% */
     {   cpp_graph_itr ret(*this);
         ++op_index_;
         first_arg_ = first_node_ + arg_node_.size();
-        get_value();
+        set_value();
         return ret;
     }
 /* %$$
diff --git a/include/cppad/local/graph/cpp_graph_op.hpp b/include/cppad/local/graph/cpp_graph_op.hpp
index 0f278ed1b..c35c27bc4 100644
--- a/include/cppad/local/graph/cpp_graph_op.hpp
+++ b/include/cppad/local/graph/cpp_graph_op.hpp
@@ -1,7 +1,7 @@
 # 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: C++ Algorithmic Differentiation: Copyright (C) 2003-21 Bradley M. Bell
 
   CppAD is distributed under the terms of the
                Eclipse Public License Version 2.0.
@@ -60,7 +60,7 @@ $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;
+    extern CPPAD_LIB_EXPORT std::map< std::string, graph_op_enum > op_name2enum;
 /* %$$
 
 $head op_enum2fixed_n_arg$$
@@ -68,14 +68,14 @@ 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[];
+    extern CPPAD_LIB_EXPORT 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[];
+    extern CPPAD_LIB_EXPORT const char* op_enum2name[];
 /* %$$
 
 $head set_operator_info$$
@@ -84,7 +84,7 @@ $code op_enum2fixed_n_arg$$,
 $code op_enum2name$$, and
 $code op_name2enum$$.
 $srccode%hpp% */
-    extern void set_operator_info(void);
+    extern CPPAD_LIB_EXPORT void set_operator_info(void);
 /* %$$
 $end
 */
diff --git a/include/cppad/local/graph/json_lexer.hpp b/include/cppad/local/graph/json_lexer.hpp
index 11873ce54..17c1726ef 100644
--- a/include/cppad/local/graph/json_lexer.hpp
+++ b/include/cppad/local/graph/json_lexer.hpp
@@ -1,7 +1,7 @@
 # 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: C++ Algorithmic Differentiation: Copyright (C) 2003-21 Bradley M. Bell
 
   CppAD is distributed under the terms of the
                Eclipse Public License Version 2.0.
@@ -212,16 +212,6 @@ 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:
diff --git a/include/cppad/local/graph/json_parser.hpp b/include/cppad/local/graph/json_parser.hpp
index 17bcc7c7e..a28d2c045 100644
--- a/include/cppad/local/graph/json_parser.hpp
+++ b/include/cppad/local/graph/json_parser.hpp
@@ -42,7 +42,7 @@ 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(
+    CPPAD_LIB_EXPORT void json_parser(
         const std::string&  json      ,
         cpp_graph&          graph_obj
     );
diff --git a/include/cppad/local/graph/json_writer.hpp b/include/cppad/local/graph/json_writer.hpp
index 36a4cb39f..299c56cc0 100644
--- a/include/cppad/local/graph/json_writer.hpp
+++ b/include/cppad/local/graph/json_writer.hpp
@@ -41,7 +41,7 @@ This is a $code cpp_graph$$ object.
 $head Prototype$$
 $srccode%hpp% */
 namespace CppAD { namespace local { namespace graph {
-    void json_writer(
+    CPPAD_LIB_EXPORT void json_writer(
         std::string&       json        ,
         const cpp_graph&   graph_obj
     );
diff --git a/include/cppad/local/op.hpp b/include/cppad/local/op.hpp
index fbed5728b..b0c63e8a9 100644
--- a/include/cppad/local/op.hpp
+++ b/include/cppad/local/op.hpp
@@ -1,7 +1,7 @@
 # ifndef CPPAD_LOCAL_OP_HPP
 # define CPPAD_LOCAL_OP_HPP
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
+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.
@@ -17,43 +17,44 @@ in the Eclipse Public License, Version 2.0 are satisfied:
 
 // operations
 # include <cppad/core/std_math_11.hpp>
-# include <cppad/local/abs_op.hpp>
-# include <cppad/local/add_op.hpp>
-# include <cppad/local/acos_op.hpp>
-# include <cppad/local/acosh_op.hpp>
-# include <cppad/local/asin_op.hpp>
-# include <cppad/local/asinh_op.hpp>
-# include <cppad/local/atan_op.hpp>
-# include <cppad/local/atanh_op.hpp>
-# include <cppad/local/comp_op.hpp>
-# include <cppad/local/cond_op.hpp>
-# include <cppad/local/cos_op.hpp>
-# include <cppad/local/cosh_op.hpp>
-# include <cppad/local/cskip_op.hpp>
-# include <cppad/local/csum_op.hpp>
-# include <cppad/local/discrete_op.hpp>
-# include <cppad/local/div_op.hpp>
-# include <cppad/local/erf_op.hpp>
-# include <cppad/local/exp_op.hpp>
-# include <cppad/local/expm1_op.hpp>
-# include <cppad/local/load_op.hpp>
-# include <cppad/local/log_op.hpp>
-# include <cppad/local/log1p_op.hpp>
-# include <cppad/local/mul_op.hpp>
-# include <cppad/local/parameter_op.hpp>
-# include <cppad/local/pow_op.hpp>
-# include <cppad/local/print_op.hpp>
-# include <cppad/local/sign_op.hpp>
-# include <cppad/local/sin_op.hpp>
-# include <cppad/local/sinh_op.hpp>
-# include <cppad/local/sqrt_op.hpp>
-# include <cppad/local/sub_op.hpp>
+# include <cppad/local/op/abs_op.hpp>
+# include <cppad/local/op/add_op.hpp>
+# include <cppad/local/op/acos_op.hpp>
+# include <cppad/local/op/acosh_op.hpp>
+# include <cppad/local/op/asin_op.hpp>
+# include <cppad/local/op/asinh_op.hpp>
+# include <cppad/local/op/atan_op.hpp>
+# include <cppad/local/op/atanh_op.hpp>
+# include <cppad/local/op/comp_op.hpp>
+# include <cppad/local/op/cond_op.hpp>
+# include <cppad/local/op/cos_op.hpp>
+# include <cppad/local/op/cosh_op.hpp>
+# include <cppad/local/op/cskip_op.hpp>
+# include <cppad/local/op/csum_op.hpp>
+# include <cppad/local/op/discrete_op.hpp>
+# include <cppad/local/op/div_op.hpp>
+# include <cppad/local/op/erf_op.hpp>
+# include <cppad/local/op/exp_op.hpp>
+# include <cppad/local/op/expm1_op.hpp>
+# include <cppad/local/op/load_op.hpp>
+# include <cppad/local/op/log_op.hpp>
+# include <cppad/local/op/log1p_op.hpp>
+# include <cppad/local/op/mul_op.hpp>
+# include <cppad/local/op/neg_op.hpp>
+# include <cppad/local/op/parameter_op.hpp>
+# include <cppad/local/op/pow_op.hpp>
+# include <cppad/local/op/print_op.hpp>
+# include <cppad/local/op/sign_op.hpp>
+# include <cppad/local/op/sin_op.hpp>
+# include <cppad/local/op/sinh_op.hpp>
+# include <cppad/local/op/sqrt_op.hpp>
+# include <cppad/local/op/sub_op.hpp>
 # include <cppad/local/sparse/binary_op.hpp>
 # include <cppad/local/sparse/unary_op.hpp>
-# include <cppad/local/store_op.hpp>
-# include <cppad/local/tan_op.hpp>
-# include <cppad/local/tanh_op.hpp>
-# include <cppad/local/zmul_op.hpp>
+# include <cppad/local/op/store_op.hpp>
+# include <cppad/local/op/tan_op.hpp>
+# include <cppad/local/op/tanh_op.hpp>
+# include <cppad/local/op/zmul_op.hpp>
 
 
 # endif
diff --git a/include/cppad/local/abs_op.hpp b/include/cppad/local/op/abs_op.hpp
similarity index 75%
rename from include/cppad/local/abs_op.hpp
rename to include/cppad/local/op/abs_op.hpp
index f0e7fe411..390395d41 100644
--- a/include/cppad/local/abs_op.hpp
+++ b/include/cppad/local/op/abs_op.hpp
@@ -1,7 +1,7 @@
-# ifndef CPPAD_LOCAL_ABS_OP_HPP
-# define CPPAD_LOCAL_ABS_OP_HPP
+# ifndef CPPAD_LOCAL_OP_ABS_OP_HPP
+# define CPPAD_LOCAL_OP_ABS_OP_HPP
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-17 Bradley M. Bell
+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.
@@ -14,21 +14,8 @@ in the Eclipse Public License, Version 2.0 are satisfied:
 
 
 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
-*/
+// See dev documentation: forward_unary_op
 template <class Base>
 void forward_abs_op(
     size_t p           ,
@@ -52,16 +39,7 @@ void forward_abs_op(
         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
-*/
+// See dev documentation: forward_unary_op
 template <class Base>
 void forward_abs_op_dir(
     size_t q           ,
@@ -87,16 +65,7 @@ void forward_abs_op_dir(
         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
-*/
+// See dev documentation: forward_unary_op
 template <class Base>
 void forward_abs_op_0(
     size_t i_z         ,
@@ -116,17 +85,8 @@ void forward_abs_op_0(
 
     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
-*/
 
+// See dev documentation: reverse_unary_op
 template <class Base>
 void reverse_abs_op(
     size_t      d            ,
diff --git a/include/cppad/local/acos_op.hpp b/include/cppad/local/op/acos_op.hpp
similarity index 78%
rename from include/cppad/local/acos_op.hpp
rename to include/cppad/local/op/acos_op.hpp
index 512c3b94c..5344e4cc3 100644
--- a/include/cppad/local/acos_op.hpp
+++ b/include/cppad/local/op/acos_op.hpp
@@ -1,7 +1,7 @@
-# ifndef CPPAD_LOCAL_ACOS_OP_HPP
-# define CPPAD_LOCAL_ACOS_OP_HPP
+# ifndef CPPAD_LOCAL_OP_ACOS_OP_HPP
+# define CPPAD_LOCAL_OP_ACOS_OP_HPP
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-17 Bradley M. Bell
+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.
@@ -14,28 +14,9 @@ in the Eclipse Public License, Version 2.0 are satisfied:
 
 
 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
-*/
+// See dev documentation: forward_unary_op
 template <class Base>
 void forward_acos_op(
     size_t p           ,
@@ -84,22 +65,7 @@ void forward_acos_op(
         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
-*/
+// See dev documentation: forward_unary_op
 template <class Base>
 void forward_acos_op_dir(
     size_t q           ,
@@ -138,21 +104,7 @@ void forward_acos_op_dir(
     }
 }
 
-/*!
-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
-*/
+// See dev documentation: forward_unary_op
 template <class Base>
 void forward_acos_op_0(
     size_t i_z         ,
@@ -173,22 +125,8 @@ void forward_acos_op_0(
     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
-*/
 
+// See dev documentation: reverse_unary_op
 template <class Base>
 void reverse_acos_op(
     size_t      d            ,
diff --git a/include/cppad/local/acosh_op.hpp b/include/cppad/local/op/acosh_op.hpp
similarity index 77%
rename from include/cppad/local/acosh_op.hpp
rename to include/cppad/local/op/acosh_op.hpp
index 4aabec0af..92bfddd44 100644
--- a/include/cppad/local/acosh_op.hpp
+++ b/include/cppad/local/op/acosh_op.hpp
@@ -1,8 +1,8 @@
-# ifndef CPPAD_LOCAL_ACOSH_OP_HPP
-# define CPPAD_LOCAL_ACOSH_OP_HPP
+# ifndef CPPAD_LOCAL_OP_ACOSH_OP_HPP
+# define CPPAD_LOCAL_OP_ACOSH_OP_HPP
 
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
+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.
@@ -15,28 +15,9 @@ in the Eclipse Public License, Version 2.0 are satisfied:
 
 
 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
-*/
+// See dev documentation: forward_unary_op
 template <class Base>
 void forward_acosh_op(
     size_t p           ,
@@ -85,22 +66,7 @@ void forward_acosh_op(
         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
-*/
+// See dev documentation: forward_unary_op
 template <class Base>
 void forward_acosh_op_dir(
     size_t q           ,
@@ -139,21 +105,7 @@ void forward_acosh_op_dir(
     }
 }
 
-/*!
-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
-*/
+// See dev documentation: forward_unary_op
 template <class Base>
 void forward_acosh_op_0(
     size_t i_z         ,
@@ -174,22 +126,8 @@ void forward_acosh_op_0(
     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
-*/
 
+// See dev documentation: reverse_unary_op
 template <class Base>
 void reverse_acosh_op(
     size_t      d            ,
diff --git a/include/cppad/local/add_op.hpp b/include/cppad/local/op/add_op.hpp
similarity index 70%
rename from include/cppad/local/add_op.hpp
rename to include/cppad/local/op/add_op.hpp
index 6b193346a..60e5e574c 100644
--- a/include/cppad/local/add_op.hpp
+++ b/include/cppad/local/op/add_op.hpp
@@ -1,7 +1,7 @@
-# ifndef CPPAD_LOCAL_ADD_OP_HPP
-# define CPPAD_LOCAL_ADD_OP_HPP
+# ifndef CPPAD_LOCAL_OP_ADD_OP_HPP
+# define CPPAD_LOCAL_OP_ADD_OP_HPP
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-18 Bradley M. Bell
+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.
@@ -13,26 +13,11 @@ in the Eclipse Public License, Version 2.0 are satisfied:
 ---------------------------------------------------------------------------- */
 
 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
-*/
 
+// See dev documentation: forward_unary_op
+// See dev documentation: forward_binary_op
 template <class Base>
 void forward_addvv_op(
     size_t        p           ,
@@ -57,20 +42,9 @@ void forward_addvv_op(
     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
-*/
 
+// See dev documentation: forward_unary_op
+// See dev documentation: forward_binary_op
 template <class Base>
 void forward_addvv_op_dir(
     size_t        q           ,
@@ -98,20 +72,9 @@ void forward_addvv_op_dir(
         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
-*/
 
+// See dev documentation: forward_unary_op
+// See dev documentation: forward_binary_op
 template <class Base>
 void forward_addvv_op_0(
     size_t        i_z         ,
@@ -132,20 +95,9 @@ void forward_addvv_op_0(
     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
-*/
 
+// See dev documentation: reverse_unary_op
+// See dev documentation: reverse_binary_op
 template <class Base>
 void reverse_addvv_op(
     size_t        d           ,
@@ -178,18 +130,8 @@ void reverse_addvv_op(
 }
 
 // --------------------------- 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
-*/
+// See dev documentation: forward_unary_op
+// See dev documentation: forward_binary_op
 template <class Base>
 void forward_addpv_op(
     size_t        p           ,
@@ -219,18 +161,8 @@ void forward_addpv_op(
     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
-*/
+// See dev documentation: forward_unary_op
+// See dev documentation: forward_binary_op
 template <class Base>
 void forward_addpv_op_dir(
     size_t        q           ,
@@ -256,19 +188,9 @@ void forward_addpv_op_dir(
     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
-*/
 
+// See dev documentation: forward_unary_op
+// See dev documentation: forward_binary_op
 template <class Base>
 void forward_addpv_op_0(
     size_t        i_z         ,
@@ -291,19 +213,9 @@ void forward_addpv_op_0(
     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
-*/
 
+// See dev documentation: reverse_unary_op
+// See dev documentation: reverse_binary_op
 template <class Base>
 void reverse_addpv_op(
     size_t        d           ,
diff --git a/include/cppad/local/asin_op.hpp b/include/cppad/local/op/asin_op.hpp
similarity index 78%
rename from include/cppad/local/asin_op.hpp
rename to include/cppad/local/op/asin_op.hpp
index 5909aead1..9c0112ffa 100644
--- a/include/cppad/local/asin_op.hpp
+++ b/include/cppad/local/op/asin_op.hpp
@@ -1,7 +1,7 @@
-# ifndef CPPAD_LOCAL_ASIN_OP_HPP
-# define CPPAD_LOCAL_ASIN_OP_HPP
+# ifndef CPPAD_LOCAL_OP_ASIN_OP_HPP
+# define CPPAD_LOCAL_OP_ASIN_OP_HPP
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-17 Bradley M. Bell
+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.
@@ -14,28 +14,9 @@ in the Eclipse Public License, Version 2.0 are satisfied:
 
 
 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
-*/
+// See dev documentation: forward_unary_op
 template <class Base>
 void forward_asin_op(
     size_t p           ,
@@ -84,22 +65,7 @@ void forward_asin_op(
         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
-*/
+// See dev documentation: forward_unary_op
 template <class Base>
 void forward_asin_op_dir(
     size_t q           ,
@@ -138,21 +104,7 @@ void forward_asin_op_dir(
     }
 }
 
-/*!
-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
-*/
+// See dev documentation: forward_unary_op
 template <class Base>
 void forward_asin_op_0(
     size_t i_z         ,
@@ -173,22 +125,8 @@ void forward_asin_op_0(
     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
-*/
 
+// See dev documentation: reverse_unary_op
 template <class Base>
 void reverse_asin_op(
     size_t      d            ,
diff --git a/include/cppad/local/asinh_op.hpp b/include/cppad/local/op/asinh_op.hpp
similarity index 77%
rename from include/cppad/local/asinh_op.hpp
rename to include/cppad/local/op/asinh_op.hpp
index 84b16b57e..1e0242924 100644
--- a/include/cppad/local/asinh_op.hpp
+++ b/include/cppad/local/op/asinh_op.hpp
@@ -1,8 +1,8 @@
-# ifndef CPPAD_LOCAL_ASINH_OP_HPP
-# define CPPAD_LOCAL_ASINH_OP_HPP
+# ifndef CPPAD_LOCAL_OP_ASINH_OP_HPP
+# define CPPAD_LOCAL_OP_ASINH_OP_HPP
 
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
+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.
@@ -15,28 +15,9 @@ in the Eclipse Public License, Version 2.0 are satisfied:
 
 
 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
-*/
+// See dev documentation: forward_unary_op
 template <class Base>
 void forward_asinh_op(
     size_t p           ,
@@ -85,22 +66,7 @@ void forward_asinh_op(
         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
-*/
+// See dev documentation: forward_unary_op
 template <class Base>
 void forward_asinh_op_dir(
     size_t q           ,
@@ -139,21 +105,7 @@ void forward_asinh_op_dir(
     }
 }
 
-/*!
-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
-*/
+// See dev documentation: forward_unary_op
 template <class Base>
 void forward_asinh_op_0(
     size_t i_z         ,
@@ -174,22 +126,8 @@ void forward_asinh_op_0(
     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
-*/
 
+// See dev documentation: reverse_unary_op
 template <class Base>
 void reverse_asinh_op(
     size_t      d            ,
diff --git a/include/cppad/local/atan_op.hpp b/include/cppad/local/op/atan_op.hpp
similarity index 76%
rename from include/cppad/local/atan_op.hpp
rename to include/cppad/local/op/atan_op.hpp
index 1dbd2c2fd..a5bf5db9b 100644
--- a/include/cppad/local/atan_op.hpp
+++ b/include/cppad/local/op/atan_op.hpp
@@ -1,7 +1,7 @@
-# ifndef CPPAD_LOCAL_ATAN_OP_HPP
-# define CPPAD_LOCAL_ATAN_OP_HPP
+# ifndef CPPAD_LOCAL_OP_ATAN_OP_HPP
+# define CPPAD_LOCAL_OP_ATAN_OP_HPP
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-17 Bradley M. Bell
+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.
@@ -14,28 +14,9 @@ in the Eclipse Public License, Version 2.0 are satisfied:
 
 
 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
-*/
+
+
+// See dev documentation: forward_unary_op
 template <class Base>
 void forward_atan_op(
     size_t p           ,
@@ -76,22 +57,7 @@ void forward_atan_op(
     }
 }
 
-/*!
-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
-*/
+// See dev documentation: forward_unary_op
 template <class Base>
 void forward_atan_op_dir(
     size_t q           ,
@@ -125,21 +91,7 @@ void forward_atan_op_dir(
     }
 }
 
-/*!
-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
-*/
+// See dev documentation: forward_unary_op
 template <class Base>
 void forward_atan_op_0(
     size_t i_z         ,
@@ -160,22 +112,8 @@ void forward_atan_op_0(
     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
-*/
 
+// See dev documentation: reverse_unary_op
 template <class Base>
 void reverse_atan_op(
     size_t      d            ,
diff --git a/include/cppad/local/atanh_op.hpp b/include/cppad/local/op/atanh_op.hpp
similarity index 76%
rename from include/cppad/local/atanh_op.hpp
rename to include/cppad/local/op/atanh_op.hpp
index a1adc6af6..ff44c52a2 100644
--- a/include/cppad/local/atanh_op.hpp
+++ b/include/cppad/local/op/atanh_op.hpp
@@ -1,8 +1,8 @@
-# ifndef CPPAD_LOCAL_ATANH_OP_HPP
-# define CPPAD_LOCAL_ATANH_OP_HPP
+# ifndef CPPAD_LOCAL_OP_ATANH_OP_HPP
+# define CPPAD_LOCAL_OP_ATANH_OP_HPP
 
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
+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.
@@ -15,28 +15,9 @@ in the Eclipse Public License, Version 2.0 are satisfied:
 
 
 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
-*/
+
+
+// See dev documentation: forward_unary_op
 template <class Base>
 void forward_atanh_op(
     size_t p           ,
@@ -77,22 +58,7 @@ void forward_atanh_op(
     }
 }
 
-/*!
-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
-*/
+// See dev documentation: forward_unary_op
 template <class Base>
 void forward_atanh_op_dir(
     size_t q           ,
@@ -126,21 +92,7 @@ void forward_atanh_op_dir(
     }
 }
 
-/*!
-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
-*/
+// See dev documentation: forward_unary_op
 template <class Base>
 void forward_atanh_op_0(
     size_t i_z         ,
@@ -161,22 +113,8 @@ void forward_atanh_op_0(
     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
-*/
 
+// See dev documentation: reverse_unary_op
 template <class Base>
 void reverse_atanh_op(
     size_t      d            ,
diff --git a/include/cppad/local/op/binary_op.omh b/include/cppad/local/op/binary_op.omh
new file mode 100644
index 000000000..097f30ecd
--- /dev/null
+++ b/include/cppad/local/op/binary_op.omh
@@ -0,0 +1,449 @@
+/* -------------------------------------------------------------------------
+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 forward_binary_op$$
+$spell
+    const addr_t arg
+    subvp
+    Taylor
+    op
+$$
+
+$section Variable Forward Binary Operators$$
+
+$head Syntax$$
+$codei%forward_%name%_op(
+    %p%, %q%, %i_z%, %arg%, %parameter% %cap_order%, %taylor%
+)%$$
+
+$head Assumption$$
+The operator corresponding to $icode name$$ has
+two arguments and one result.
+
+$head Notation$$
+
+$head name$$
+The last two characters in the $icode name$$ for a binary operator are
+$code p$$ (for parameter) or $code v$$ (for variable).
+For example the name $code subvp$$ corresponding to subtraction
+with a variable on the left (first) and a parameter on the right (second).
+
+$subhead x$$
+We use $icode x$$ to denote the first argument of this binary operation.
+This argument is a variable or a parameter depending on the operator.
+
+$subhead y$$
+We use $icode y$$ to denote the second argument of this binary operation.
+This argument is a variable or a parameter depending on the operator.
+
+$subhead z$$
+We use $icode z$$ to denote the result of this binary operation.
+The result is always a variable.
+
+$head Base$$
+is the 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 p$$
+This argument has type $code size_t$$ and
+is lowest order of the Taylor coefficient that we are computing.
+
+$head q$$
+The argument $icode q >= p$$ has type $code size_t$$ and
+is highest order of the Taylor coefficient that we are computing.
+
+$head i_z$$
+This argument has type $code size_t$$ and
+is the variable index corresponding to the result for this operation;
+i.e. the row index in $icode taylor$$ corresponding to $icode z$$.
+
+$head arg$$
+This argument has type $code const addr_t*$$.
+
+$subhead i_x$$
+We use $icode%i_x% = %arg%[0]%$$ for the
+index corresponding to the first operand for this operator.
+If $icode x$$ is a parameter,
+$icode%parameter%[%i_x%]%$$ is the corresponding value.
+If $icode x$$ is a variable,
+$icode i_x$$ is the row index in $icode taylor$$ corresponding to $code x$$.
+
+$subhead i_y$$
+We use $icode%i_y% = %arg%[0]%$$ for the
+index corresponding to the first operand for this operator.
+If $icode y$$ is a parameter,
+$icode%parameter%[%i_y%]%$$ is the corresponding value.
+If $icode y$$ is a variable,
+$icode i_y$$ is the row index in $icode taylor$$ corresponding to $code y$$.
+
+$head parameter$$
+This argument has type $codei%const %Base%*%$$
+and maps parameter indices to parameter values.
+
+$head cap_order$$
+This argument has type $code size_t$$ and
+is the maximum number of orders that will fit in $icode taylor$$.
+
+$head taylor$$
+This argument has type $icode%Base%*%$$.
+The Taylor coefficient corresponding to
+variable $icode i$$ and order $icode k$$ is
+$codei%
+    %taylor%[ %i% * %cap_order% + %k% ]
+%$$.
+
+$subhead Input$$
+$list number$$
+If $icode x$$ is a variable,
+the Taylor coefficients for variable $icode i_x$$ up to order $icode q$$.
+$lnext
+If $icode y$$ is a variable,
+the Taylor coefficients for variable $icode i_y$$ up to order $icode q$$.
+$lnext
+The Taylor coefficients for variable $icode i_z$$ up to order $icode%p%-1%$$.
+$lend
+
+$subhead Output$$
+The Taylor coefficients for variable $icode i_z$$ up to order $icode q$$.
+
+$end
+------------------------------------------------------------------------------
+$begin forward_binary_op_dir$$
+$spell
+    const addr_t arg
+    op
+    tpv
+    Taylor
+$$
+
+$section Multiple Direction Forward Binary Operators$$
+
+$head Syntax$$
+$codei%forward_%name%_op(
+    %q%, %r%, %i_z%, %arg%, %parameter%, %cap_order%, %taylor%
+)%$$
+
+$head Assumption$$
+The operator corresponding to $icode name$$ has
+two arguments and one result.
+
+$head Notation$$
+
+$subhead x$$
+We use $icode x$$ to denote the first argument of this binary operation.
+This argument is a variable or a parameter depending on the operator.
+
+$subhead y$$
+We use $icode y$$ to denote the second argument of this binary operation.
+This argument is a variable or a parameter depending on the operator.
+
+$subhead z$$
+We use $icode z$$ to denote the result of this binary operation.
+The result is always a variable.
+
+$head Base$$
+is the 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 q$$
+This argument has type $code size_t$$ and
+is the order of the Taylor coefficients that we are computing.
+Furthermore $icode%q% > 0%$$ and $icode%q% < %cap_order%$$.
+
+$head r$$
+This argument has type $code size_t$$ and
+is number of directions for Taylor coefficients that we are computing.
+
+$head i_z$$
+This argument has type $code size_t$$ and
+is the variable index corresponding to the result for this operation;
+i.e. the row index in $icode taylor$$ corresponding to $icode z$$.
+
+$head arg$$
+This argument has type $codei%const addr_t* %arg%$$.
+
+$subhead i_x$$
+We use $icode%i_x% = %arg%[0]%$$ for the
+index corresponding to the first operand for this operator.
+If $icode x$$ is a parameter,
+$icode%parameter%[%i_x%]%$$ is the corresponding value.
+If $icode x$$ is a variable,
+$icode i_x$$ is the row index in $icode taylor$$ corresponding to $code x$$.
+
+$subhead i_y$$
+We use $icode%i_y% = %arg%[0]%$$ for the
+index corresponding to the first operand for this operator.
+If $icode y$$ is a parameter,
+$icode%parameter%[%i_y%]%$$ is the corresponding value.
+If $icode y$$ is a variable,
+$icode i_y$$ is the row index in $icode taylor$$ corresponding to $code y$$.
+
+$head parameter$$
+This argument has type $codei%const %Base%*%$$
+and maps parameter indices to parameter values.
+
+$head cap_order$$
+This argument has type $code size_t$$ and
+is the maximum number of orders that will fit in $icode taylor$$.
+The zero order Taylor coefficient for a variable
+is the same for all directions.  We use the notation
+$codei%
+    %tpv% = (%cap_order% - 1) * r + 1
+%$$
+which is the number of Taylor coefficients per variable.
+
+$head taylor$$
+This argument has type $icode%Base%*%$$.
+The zero order Taylor coefficient for variable $icode i$$ is
+$codei%
+    %taylor%[ %i% * %tpv% + 0 ]
+%$$.
+For $icode k > 0$$,
+and $icode%ell% = 0 , %..% , %r-1%$$,
+The Taylor coefficient for variable $icode i$$,
+order $icode k$$, and direction $icode ell$$ is
+$codei%
+    %taylor%[ %i% * %tpv% + (%k% - 1) * %r% + %ell% + 1 ]
+%$$.
+
+$head Input$$
+$list number$$
+If $icode x$$ is a variable,
+the Taylor coefficients for variable $icode i_x$$ up to order $icode q$$
+and all $icode r$$ directions.
+$lnext
+If $icode y$$ is a variable,
+the Taylor coefficients for variable $icode i_x$$ up to order $icode q$$
+and all $icode r$$ directions.
+$lnext
+The Taylor coefficients for variable $icode i_z$$ up to order $icode q-1$$
+and all $icode r$$ directions.
+$lend
+
+$head Output$$
+The Taylor coefficients for variable $icode i_z$$ up to order $icode q$$
+and all $icode r$$ directions.
+
+$end
+-------------------------------------------------------------------------------
+/*
+$begin forward_binary_op_0$$
+$spell
+    const addr_t arg
+    op
+    Taylor
+$$
+
+$section Zero Order Forward Binary Operators$$
+
+$head Syntax$$
+$codei%forward_%name%_op_0(
+    %i_z%, %arg%, %parameter%, %cap_order%, %taylor%
+)%$$
+
+$head Assumption$$
+The operator corresponding to $icode name$$ has
+two arguments and one result.
+
+$head Notation$$
+
+$subhead x$$
+We use $icode x$$ to denote the first argument of this binary operation.
+This argument is a variable or a parameter depending on the operator.
+
+$subhead y$$
+We use $icode y$$ to denote the second argument of this binary operation.
+This argument is a variable or a parameter depending on the operator.
+
+$subhead z$$
+We use $icode z$$ to denote the result of this binary operation.
+The result is always a variable.
+
+$head Base$$
+is the 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 i_z$$
+This argument has type $code size_t$$ and
+is the variable index corresponding to the result for this operation;
+i.e. the row index in $icode taylor$$ corresponding to $icode z$$.
+
+$head arg$$
+This argument has type $code const addr_t*$$.
+
+$subhead i_x$$
+We use $icode%i_x% = %arg%[0]%$$ for the
+index corresponding to the first operand for this operator.
+If $icode x$$ is a parameter,
+$icode%parameter%[%i_x%]%$$ is the corresponding value.
+If $icode x$$ is a variable,
+$icode i_x$$ is the row index in $icode taylor$$ corresponding to $code x$$.
+
+$subhead i_y$$
+We use $icode%i_y% = %arg%[0]%$$ for the
+index corresponding to the first operand for this operator.
+If $icode y$$ is a parameter,
+$icode%parameter%[%i_y%]%$$ is the corresponding value.
+If $icode y$$ is a variable,
+$icode i_y$$ is the row index in $icode taylor$$ corresponding to $code y$$.
+
+$head parameter$$
+This argument has type $codei%const %Base%*%$$
+and maps parameter indices to parameter values.
+
+$head cap_order$$
+This argument has type $code size_t$$ and
+is the maximum number of orders that will fit in $icode taylor$$.
+
+$head taylor$$
+This argument has type $icode%Base%*%$$.
+The Taylor coefficient corresponding to
+variable $icode i$$ and order $icode k$$ is
+$codei%
+    %taylor%[ %i% * %cap_order% + %k% ]
+%$$.
+
+$subhead Input$$
+If $icode x$$ is a variable,
+the zero order Taylor coefficients for variable $icode i_x$$.
+If $icode y$$ is a variable,
+the zero order Taylor coefficients for variable $icode i_y$$.
+
+$subhead Output$$
+The zero order Taylor coefficients for variable $icode i_z$$.
+
+$end
+------------------------------------------------------------------------------
+/*
+$begin reverse_binary_op$$
+$spell
+    const addr_ arg
+    op
+    Taylor
+    nc
+    const
+$$
+
+$section Reverse Binary Operators$$
+
+$head Syntax$$
+$codei%reverse_%name%_op(
+%d%, %i_z%, %arg%, %parameter%, %cap_order%, %taylor%, %nc_partial%, %partial%
+)%$$
+
+$head Assumption$$
+The operator corresponding to $icode name$$ has one argument and one result.
+
+$head Notation$$
+
+$subhead x$$
+We use $icode x$$ to denote the first argument of this binary operation.
+This argument is a variable or a parameter depending on the operator.
+
+$subhead y$$
+We use $icode y$$ to denote the second argument of this binary operation.
+This argument is a variable or a parameter depending on the operator.
+
+$subhead z$$
+We use $icode z$$ to denote the result of this binary operation.
+The result is always a variable.
+
+$subhead G$$
+We use $latex G(z, y, x, w, \ldots )$$ to denote a scalar valued function
+of the variables up to variable index $icode i_z$$.
+
+$subhead H$$
+We use $latex H(y, x, w, \ldots )$$ to denote the scalar valued function
+of the variables up to variable index $icode%i_z%-1%$$ defined by
+$latex \[
+    H(y, x, w, \ldots ) = G [ z(x, y), y, x, w, \ldots ) ]
+\]$$
+
+$head Base$$
+is the 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 d$$
+This argument has type $code size_t$$ and
+is this highest order Taylor coefficient that we are computing
+partial derivatives with respect to.
+Furthermore $icode%d% < %cap_order%$$ and $icode%d% < %nc_partial%$$.
+
+$head i_z$$
+This argument has type $code size_t$$ and
+is the variable index corresponding to the result for this operation;
+i.e. the row index in $icode taylor$$ corresponding to $icode z$$.
+
+$head arg$$
+This argument has type $code const addr_t*$$.
+
+$subhead i_x$$
+We use $icode%i_x% = %arg%[0]%$$ for the
+index corresponding to the first operand for this operator.
+If $icode x$$ is a parameter,
+$icode%parameter%[%i_x%]%$$ is the corresponding value.
+If $icode x$$ is a variable,
+$icode i_x$$ is the row index in $icode taylor$$ corresponding to $code x$$.
+
+$subhead i_y$$
+We use $icode%i_y% = %arg%[0]%$$ for the
+index corresponding to the first operand for this operator.
+If $icode y$$ is a parameter,
+$icode%parameter%[%i_y%]%$$ is the corresponding value.
+If $icode y$$ is a variable,
+$icode i_y$$ is the row index in $icode taylor$$ corresponding to $code y$$.
+
+$head parameter$$
+This argument has type $codei%const %Base%*%$$
+and maps parameter indices to parameter values.
+
+$head cap_order$$
+This argument has type $code size_t$$ and
+is the maximum number of orders that will fit in $icode taylor$$.
+
+$head taylor$$
+This argument has type $codei%const %Base%*%$$.
+The Taylor coefficient corresponding to
+variable $icode i$$ and order $icode k$$ is
+$codei%
+    %taylor%[ %i% * %cap_order% + %k% ]
+%$$.
+
+$head nc_partial$$
+This argument has type $code size_t$$ and
+is the number of columns in the partial array.
+
+$head partial$$
+This argument has type $icode%Base%*%$$.
+The partial derivative w.r.t. variable $icode i$$ and
+Taylor coefficient of order $icode k$$ is
+$code%
+    %partial% [ %i% * %nc_partial% + k ]
+%$$
+for $icode%k% = 0 , %...%, %d%$$.
+
+$subhead Input$$
+For variable $icode%i% = 0 ,%...%, %i_z%$$,
+$icode partial$$ contains the
+partial derivatives of $latex G(z, y, x, w, \ldots)$$.
+
+$subhead Output$$
+The array $icode partial$$ contains the
+partial derivatives of $latex H(x, w, \ldots)$$.
+The partial derivative for variable $icode i_z$$ is unspecified.
+
+$end
+------------------------------------------------------------------------------
diff --git a/include/cppad/local/comp_op.hpp b/include/cppad/local/op/comp_op.hpp
similarity index 98%
rename from include/cppad/local/comp_op.hpp
rename to include/cppad/local/op/comp_op.hpp
index e9098da18..1448d62e6 100644
--- a/include/cppad/local/comp_op.hpp
+++ b/include/cppad/local/op/comp_op.hpp
@@ -1,7 +1,7 @@
-# ifndef CPPAD_LOCAL_COMP_OP_HPP
-# define CPPAD_LOCAL_COMP_OP_HPP
+# ifndef CPPAD_LOCAL_OP_COMP_OP_HPP
+# define CPPAD_LOCAL_OP_COMP_OP_HPP
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-18 Bradley M. Bell
+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.
diff --git a/include/cppad/local/cond_op.hpp b/include/cppad/local/op/cond_op.hpp
similarity index 99%
rename from include/cppad/local/cond_op.hpp
rename to include/cppad/local/op/cond_op.hpp
index 7cc1dd27a..054551cbb 100644
--- a/include/cppad/local/cond_op.hpp
+++ b/include/cppad/local/op/cond_op.hpp
@@ -1,7 +1,7 @@
-# ifndef CPPAD_LOCAL_COND_OP_HPP
-# define CPPAD_LOCAL_COND_OP_HPP
+# ifndef CPPAD_LOCAL_OP_COND_OP_HPP
+# define CPPAD_LOCAL_OP_COND_OP_HPP
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 Bradley M. Bell
+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.
diff --git a/include/cppad/local/cos_op.hpp b/include/cppad/local/op/cos_op.hpp
similarity index 77%
rename from include/cppad/local/cos_op.hpp
rename to include/cppad/local/op/cos_op.hpp
index f7d44e1b2..e16de3326 100644
--- a/include/cppad/local/cos_op.hpp
+++ b/include/cppad/local/op/cos_op.hpp
@@ -1,7 +1,7 @@
-# ifndef CPPAD_LOCAL_COS_OP_HPP
-# define CPPAD_LOCAL_COS_OP_HPP
+# ifndef CPPAD_LOCAL_OP_COS_OP_HPP
+# define CPPAD_LOCAL_OP_COS_OP_HPP
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-17 Bradley M. Bell
+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.
@@ -14,27 +14,8 @@ in the Eclipse Public License, Version 2.0 are satisfied:
 
 
 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
-*/
+
+// See dev documentation: forward_unary_op
 template <class Base>
 void forward_cos_op(
     size_t p           ,
@@ -77,22 +58,7 @@ void forward_cos_op(
         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
-*/
+// See dev documentation: forward_unary_op
 template <class Base>
 void forward_cos_op_dir(
     size_t q           ,
@@ -131,21 +97,7 @@ void forward_cos_op_dir(
     }
 }
 
-/*!
-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
-*/
+// See dev documentation: forward_unary_op
 template <class Base>
 void forward_cos_op_0(
     size_t i_z         ,
@@ -166,22 +118,8 @@ void forward_cos_op_0(
     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
-*/
 
+// See dev documentation: reverse_unary_op
 template <class Base>
 void reverse_cos_op(
     size_t      d            ,
diff --git a/include/cppad/local/cosh_op.hpp b/include/cppad/local/op/cosh_op.hpp
similarity index 76%
rename from include/cppad/local/cosh_op.hpp
rename to include/cppad/local/op/cosh_op.hpp
index 875200c05..04b55ea98 100644
--- a/include/cppad/local/cosh_op.hpp
+++ b/include/cppad/local/op/cosh_op.hpp
@@ -1,7 +1,7 @@
-# ifndef CPPAD_LOCAL_COSH_OP_HPP
-# define CPPAD_LOCAL_COSH_OP_HPP
+# ifndef CPPAD_LOCAL_OP_COSH_OP_HPP
+# define CPPAD_LOCAL_OP_COSH_OP_HPP
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-17 Bradley M. Bell
+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.
@@ -14,28 +14,9 @@ in the Eclipse Public License, Version 2.0 are satisfied:
 
 
 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
-*/
+
+
+// See dev documentation: forward_unary_op
 template <class Base>
 void forward_cosh_op(
     size_t p           ,
@@ -77,22 +58,7 @@ void forward_cosh_op(
         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
-*/
+// See dev documentation: forward_unary_op
 template <class Base>
 void forward_cosh_op_dir(
     size_t q           ,
@@ -131,21 +97,7 @@ void forward_cosh_op_dir(
     }
 }
 
-/*!
-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
-*/
+// See dev documentation: forward_unary_op
 template <class Base>
 void forward_cosh_op_0(
     size_t i_z         ,
@@ -166,22 +118,8 @@ void forward_cosh_op_0(
     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
-*/
 
+// See dev documentation: reverse_unary_op
 template <class Base>
 void reverse_cosh_op(
     size_t      d            ,
diff --git a/include/cppad/local/cskip_op.hpp b/include/cppad/local/op/cskip_op.hpp
similarity index 97%
rename from include/cppad/local/cskip_op.hpp
rename to include/cppad/local/op/cskip_op.hpp
index f9250608e..5295fdad3 100644
--- a/include/cppad/local/cskip_op.hpp
+++ b/include/cppad/local/op/cskip_op.hpp
@@ -1,7 +1,7 @@
-# ifndef CPPAD_LOCAL_CSKIP_OP_HPP
-# define CPPAD_LOCAL_CSKIP_OP_HPP
+# ifndef CPPAD_LOCAL_OP_CSKIP_OP_HPP
+# define CPPAD_LOCAL_OP_CSKIP_OP_HPP
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
+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.
diff --git a/include/cppad/local/csum_op.hpp b/include/cppad/local/op/csum_op.hpp
similarity index 99%
rename from include/cppad/local/csum_op.hpp
rename to include/cppad/local/op/csum_op.hpp
index 84eecde75..d5b597d5e 100644
--- a/include/cppad/local/csum_op.hpp
+++ b/include/cppad/local/op/csum_op.hpp
@@ -1,7 +1,7 @@
-# ifndef CPPAD_LOCAL_CSUM_OP_HPP
-# define CPPAD_LOCAL_CSUM_OP_HPP
+# ifndef CPPAD_LOCAL_OP_CSUM_OP_HPP
+# define CPPAD_LOCAL_OP_CSUM_OP_HPP
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 Bradley M. Bell
+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.
diff --git a/include/cppad/local/discrete_op.hpp b/include/cppad/local/op/discrete_op.hpp
similarity index 96%
rename from include/cppad/local/discrete_op.hpp
rename to include/cppad/local/op/discrete_op.hpp
index e3fa08099..5e7f339eb 100644
--- a/include/cppad/local/discrete_op.hpp
+++ b/include/cppad/local/op/discrete_op.hpp
@@ -1,7 +1,7 @@
-# ifndef CPPAD_LOCAL_DISCRETE_OP_HPP
-# define CPPAD_LOCAL_DISCRETE_OP_HPP
+# ifndef CPPAD_LOCAL_OP_DISCRETE_OP_HPP
+# define CPPAD_LOCAL_OP_DISCRETE_OP_HPP
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-18 Bradley M. Bell
+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.
diff --git a/include/cppad/local/div_op.hpp b/include/cppad/local/op/div_op.hpp
similarity index 74%
rename from include/cppad/local/div_op.hpp
rename to include/cppad/local/op/div_op.hpp
index 9fcb196aa..dc0554afb 100644
--- a/include/cppad/local/div_op.hpp
+++ b/include/cppad/local/op/div_op.hpp
@@ -1,7 +1,7 @@
-# ifndef CPPAD_LOCAL_DIV_OP_HPP
-# define CPPAD_LOCAL_DIV_OP_HPP
+# ifndef CPPAD_LOCAL_OP_DIV_OP_HPP
+# define CPPAD_LOCAL_OP_DIV_OP_HPP
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-18 Bradley M. Bell
+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.
@@ -13,26 +13,10 @@ in the Eclipse Public License, Version 2.0 are satisfied:
 ---------------------------------------------------------------------------- */
 
 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
-*/
 
+// See dev documentation: forward_binary_op
 template <class Base>
 void forward_divvv_op(
     size_t        p           ,
@@ -65,20 +49,8 @@ void forward_divvv_op(
         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
-*/
 
+// See dev documentation: forward_binary_op
 template <class Base>
 void forward_divvv_op_dir(
     size_t        q           ,
@@ -114,20 +86,8 @@ void forward_divvv_op_dir(
 }
 
 
-/*!
-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
-*/
 
+// See dev documentation: forward_binary_op
 template <class Base>
 void forward_divvv_op_0(
     size_t        i_z         ,
@@ -148,20 +108,8 @@ void forward_divvv_op_0(
     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
-*/
 
+// See dev documentation: reverse_binary_op
 template <class Base>
 void reverse_divvv_op(
     size_t        d           ,
@@ -210,19 +158,8 @@ void reverse_divvv_op(
 }
 
 // --------------------------- 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
-*/
 
+// See dev documentation: forward_binary_op
 template <class Base>
 void forward_divpv_op(
     size_t        p           ,
@@ -260,19 +197,8 @@ void forward_divpv_op(
         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
-*/
 
+// See dev documentation: forward_binary_op
 template <class Base>
 void forward_divpv_op_dir(
     size_t        q           ,
@@ -305,19 +231,8 @@ void forward_divpv_op_dir(
     }
 }
 
-/*!
-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
-*/
 
+// See dev documentation: forward_binary_op
 template <class Base>
 void forward_divpv_op_0(
     size_t        i_z         ,
@@ -340,19 +255,8 @@ void forward_divpv_op_0(
     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
-*/
 
+// See dev documentation: reverse_binary_op
 template <class Base>
 void reverse_divpv_op(
     size_t        d           ,
@@ -400,19 +304,8 @@ void reverse_divpv_op(
 
 
 // --------------------------- 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
-*/
 
+// See dev documentation: forward_binary_op
 template <class Base>
 void forward_divvp_op(
     size_t        p           ,
@@ -441,19 +334,8 @@ void forward_divvp_op(
     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
-*/
 
+// See dev documentation: forward_binary_op
 template <class Base>
 void forward_divvp_op_dir(
     size_t        q           ,
@@ -486,19 +368,8 @@ void forward_divvp_op_dir(
 }
 
 
-/*!
-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
-*/
 
+// See dev documentation: forward_binary_op
 template <class Base>
 void forward_divvp_op_0(
     size_t        i_z         ,
@@ -521,19 +392,8 @@ void forward_divvp_op_0(
     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
-*/
 
+// See dev documentation: reverse_binary_op
 template <class Base>
 void reverse_divvp_op(
     size_t        d           ,
diff --git a/include/cppad/local/erf_op.hpp b/include/cppad/local/op/erf_op.hpp
similarity index 98%
rename from include/cppad/local/erf_op.hpp
rename to include/cppad/local/op/erf_op.hpp
index 937c81977..6f3c2b026 100644
--- a/include/cppad/local/erf_op.hpp
+++ b/include/cppad/local/op/erf_op.hpp
@@ -1,8 +1,8 @@
-# ifndef CPPAD_LOCAL_ERF_OP_HPP
-# define CPPAD_LOCAL_ERF_OP_HPP
+# ifndef CPPAD_LOCAL_OP_ERF_OP_HPP
+# define CPPAD_LOCAL_OP_ERF_OP_HPP
 
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
+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.
@@ -13,9 +13,9 @@ in the Eclipse Public License, Version 2.0 are satisfied:
       GNU General Public License, Version 2.0 or later.
 ---------------------------------------------------------------------------- */
 
-# include <cppad/local/mul_op.hpp>
-# include <cppad/local/sub_op.hpp>
-# include <cppad/local/exp_op.hpp>
+# include <cppad/local/op/mul_op.hpp>
+# include <cppad/local/op/sub_op.hpp>
+# include <cppad/local/op/exp_op.hpp>
 
 
 namespace CppAD { namespace local { // BEGIN_CPPAD_LOCAL_NAMESPACE
diff --git a/include/cppad/local/exp_op.hpp b/include/cppad/local/op/exp_op.hpp
similarity index 80%
rename from include/cppad/local/exp_op.hpp
rename to include/cppad/local/op/exp_op.hpp
index a5fca7ae8..d46d88481 100644
--- a/include/cppad/local/exp_op.hpp
+++ b/include/cppad/local/op/exp_op.hpp
@@ -1,7 +1,7 @@
-# ifndef CPPAD_LOCAL_EXP_OP_HPP
-# define CPPAD_LOCAL_EXP_OP_HPP
+# ifndef CPPAD_LOCAL_OP_EXP_OP_HPP
+# define CPPAD_LOCAL_OP_EXP_OP_HPP
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-17 Bradley M. Bell
+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.
@@ -14,22 +14,9 @@ in the Eclipse Public License, Version 2.0 are satisfied:
 
 
 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
-*/
+// See dev documentation: forward_unary_op
 template <class Base>
 void forward_exp_op(
     size_t p           ,
@@ -64,16 +51,7 @@ void forward_exp_op(
 }
 
 
-/*!
-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
-*/
+// See dev documentation: forward_unary_op
 template <class Base>
 void forward_exp_op_dir(
     size_t q           ,
@@ -103,16 +81,7 @@ void forward_exp_op_dir(
     }
 }
 
-/*!
-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
-*/
+// See dev documentation: forward_unary_op
 template <class Base>
 void forward_exp_op_0(
     size_t i_z         ,
@@ -131,17 +100,8 @@ void forward_exp_op_0(
 
     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
-*/
 
+// See dev documentation: reverse_unary_op
 template <class Base>
 void reverse_exp_op(
     size_t      d            ,
diff --git a/include/cppad/local/expm1_op.hpp b/include/cppad/local/op/expm1_op.hpp
similarity index 80%
rename from include/cppad/local/expm1_op.hpp
rename to include/cppad/local/op/expm1_op.hpp
index ea80fc96d..671019666 100644
--- a/include/cppad/local/expm1_op.hpp
+++ b/include/cppad/local/op/expm1_op.hpp
@@ -1,8 +1,8 @@
-# ifndef CPPAD_LOCAL_EXPM1_OP_HPP
-# define CPPAD_LOCAL_EXPM1_OP_HPP
+# ifndef CPPAD_LOCAL_OP_EXPM1_OP_HPP
+# define CPPAD_LOCAL_OP_EXPM1_OP_HPP
 
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
+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.
@@ -15,22 +15,8 @@ in the Eclipse Public License, Version 2.0 are satisfied:
 
 
 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 <class Base>
 void forward_expm1_op(
     size_t p           ,
@@ -66,16 +52,6 @@ void forward_expm1_op(
 }
 
 
-/*!
-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 <class Base>
 void forward_expm1_op_dir(
     size_t q           ,
@@ -106,16 +82,6 @@ void forward_expm1_op_dir(
     }
 }
 
-/*!
-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 <class Base>
 void forward_expm1_op_0(
     size_t i_z         ,
@@ -134,16 +100,6 @@ void forward_expm1_op_0(
 
     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 <class Base>
 void reverse_expm1_op(
diff --git a/include/cppad/local/load_op.hpp b/include/cppad/local/op/load_op.hpp
similarity index 99%
rename from include/cppad/local/load_op.hpp
rename to include/cppad/local/op/load_op.hpp
index b70dd4110..152ef2b7b 100644
--- a/include/cppad/local/load_op.hpp
+++ b/include/cppad/local/op/load_op.hpp
@@ -1,7 +1,7 @@
-# ifndef CPPAD_LOCAL_LOAD_OP_HPP
-# define CPPAD_LOCAL_LOAD_OP_HPP
+# ifndef CPPAD_LOCAL_OP_LOAD_OP_HPP
+# define CPPAD_LOCAL_OP_LOAD_OP_HPP
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
+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.
diff --git a/include/cppad/local/log1p_op.hpp b/include/cppad/local/op/log1p_op.hpp
similarity index 80%
rename from include/cppad/local/log1p_op.hpp
rename to include/cppad/local/op/log1p_op.hpp
index fba31a258..5a2faddd2 100644
--- a/include/cppad/local/log1p_op.hpp
+++ b/include/cppad/local/op/log1p_op.hpp
@@ -1,8 +1,8 @@
-# ifndef CPPAD_LOCAL_LOG1P_OP_HPP
-# define CPPAD_LOCAL_LOG1P_OP_HPP
+# ifndef CPPAD_LOCAL_OP_LOG1P_OP_HPP
+# define CPPAD_LOCAL_OP_LOG1P_OP_HPP
 
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
+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.
@@ -14,21 +14,7 @@ in the Eclipse Public License, Version 2.0 are satisfied:
 ---------------------------------------------------------------------------- */
 
 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 <class Base>
 void forward_log1p_op(
     size_t p           ,
@@ -71,16 +57,6 @@ void forward_log1p_op(
     }
 }
 
-/*!
-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 <class Base>
 void forward_log1p_op_dir(
     size_t q           ,
@@ -111,16 +87,6 @@ void forward_log1p_op_dir(
     }
 }
 
-/*!
-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 <class Base>
 void forward_log1p_op_0(
     size_t i_z         ,
@@ -141,16 +107,6 @@ void forward_log1p_op_0(
     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 <class Base>
 void reverse_log1p_op(
diff --git a/include/cppad/local/log_op.hpp b/include/cppad/local/op/log_op.hpp
similarity index 80%
rename from include/cppad/local/log_op.hpp
rename to include/cppad/local/op/log_op.hpp
index 937062c50..ea97d1bf9 100644
--- a/include/cppad/local/log_op.hpp
+++ b/include/cppad/local/op/log_op.hpp
@@ -1,7 +1,7 @@
-# ifndef CPPAD_LOCAL_LOG_OP_HPP
-# define CPPAD_LOCAL_LOG_OP_HPP
+# ifndef CPPAD_LOCAL_OP_LOG_OP_HPP
+# define CPPAD_LOCAL_OP_LOG_OP_HPP
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-17 Bradley M. Bell
+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.
@@ -13,21 +13,8 @@ in the Eclipse Public License, Version 2.0 are satisfied:
 ---------------------------------------------------------------------------- */
 
 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
-*/
+// See dev documentation: forward_unary_op
 template <class Base>
 void forward_log_op(
     size_t p           ,
@@ -70,16 +57,7 @@ void forward_log_op(
     }
 }
 
-/*!
-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
-*/
+// See dev documentation: forward_unary_op
 template <class Base>
 void forward_log_op_dir(
     size_t q           ,
@@ -110,16 +88,7 @@ void forward_log_op_dir(
     }
 }
 
-/*!
-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
-*/
+// See dev documentation: forward_unary_op
 template <class Base>
 void forward_log_op_0(
     size_t i_z         ,
@@ -140,17 +109,8 @@ void forward_log_op_0(
     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
-*/
 
+// See dev documentation: reverse_unary_op
 template <class Base>
 void reverse_log_op(
     size_t      d            ,
diff --git a/include/cppad/local/mul_op.hpp b/include/cppad/local/op/mul_op.hpp
similarity index 71%
rename from include/cppad/local/mul_op.hpp
rename to include/cppad/local/op/mul_op.hpp
index d7fe15124..7c02557e5 100644
--- a/include/cppad/local/mul_op.hpp
+++ b/include/cppad/local/op/mul_op.hpp
@@ -1,7 +1,7 @@
-# ifndef CPPAD_LOCAL_MUL_OP_HPP
-# define CPPAD_LOCAL_MUL_OP_HPP
+# ifndef CPPAD_LOCAL_OP_MUL_OP_HPP
+# define CPPAD_LOCAL_OP_MUL_OP_HPP
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-18 Bradley M. Bell
+CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
 
 CppAD is distributed under the terms of the
              Eclipse Public License Version 2.0.
@@ -13,26 +13,10 @@ in the Eclipse Public License, Version 2.0 are satisfied:
 ---------------------------------------------------------------------------- */
 
 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
-*/
 
+// See dev documentation: forward_binary_op
 template <class Base>
 void forward_mulvv_op(
     size_t        p           ,
@@ -61,20 +45,8 @@ void forward_mulvv_op(
             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
-*/
 
+// See dev documentation: forward_binary_op
 template <class Base>
 void forward_mulvv_op_dir(
     size_t        q           ,
@@ -106,20 +78,8 @@ void forward_mulvv_op_dir(
     }
 }
 
-/*!
-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
-*/
 
+// See dev documentation: forward_binary_op
 template <class Base>
 void forward_mulvv_op_0(
     size_t        i_z         ,
@@ -140,20 +100,8 @@ void forward_mulvv_op_0(
     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
-*/
 
+// See dev documentation: reverse_binary_op
 template <class Base>
 void reverse_mulvv_op(
     size_t        d           ,
@@ -188,25 +136,16 @@ void reverse_mulvv_op(
     {   --j;
         for(k = 0; k <= j; k++)
         {
+            // must use azmul becasue pz[j] = 0 may mean that this
+            // component of the function was not selected.
             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
-*/
 
+// See dev documentation: forward_binary_op
 template <class Base>
 void forward_mulpv_op(
     size_t        p           ,
@@ -233,19 +172,8 @@ void forward_mulpv_op(
     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
-*/
 
+// See dev documentation: forward_binary_op
 template <class Base>
 void forward_mulpv_op_dir(
     size_t        q           ,
@@ -274,19 +202,8 @@ void forward_mulpv_op_dir(
     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
-*/
 
+// See dev documentation: forward_binary_op
 template <class Base>
 void forward_mulpv_op_0(
     size_t        i_z         ,
@@ -309,19 +226,8 @@ void forward_mulpv_op_0(
     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
-*/
 
+// See dev documentation: reverse_binary_op
 template <class Base>
 void reverse_mulpv_op(
     size_t        d           ,
@@ -350,6 +256,8 @@ void reverse_mulpv_op(
     size_t j = d + 1;
     while(j)
     {   --j;
+        // must use azmul becasue pz[j] = 0 may mean that this
+        // component of the function was not selected.
         py[j] += azmul(pz[j], x);
     }
 }
diff --git a/include/cppad/local/op/neg_op.hpp b/include/cppad/local/op/neg_op.hpp
new file mode 100644
index 000000000..2efc8f83d
--- /dev/null
+++ b/include/cppad/local/op/neg_op.hpp
@@ -0,0 +1,118 @@
+# ifndef CPPAD_LOCAL_OP_NEG_OP_HPP
+# define CPPAD_LOCAL_OP_NEG_OP_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.
+---------------------------------------------------------------------------- */
+
+namespace CppAD { namespace local { // BEGIN_CPPAD_LOCAL_NAMESPACE
+template <class Base>
+
+// See forward_unary1_op in developer documentation
+void forward_neg_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_NARG_NRES( NegOp, 1, 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 k = p; k <= q; k++)
+        z[k] = - x[k];
+}
+
+// See forward_unary1_op_dir in  developer documentation
+// See dev documentation: forward_unary_op
+template <class Base>
+void forward_neg_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_NARG_NRES( NegOp, 1, 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] = - x[m+ell];
+}
+
+// See forward_unary1_op_0 in developer documentation
+// See dev documentation: forward_unary_op
+template <class Base>
+void forward_neg_op_0(
+    size_t i_z         ,
+    size_t i_x         ,
+    size_t cap_order   ,
+    Base*  taylor      )
+{
+
+    // check assumptions
+    CPPAD_ASSERT_NARG_NRES( NegOp, 1, 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] = - x[0];
+}
+
+// See reverse_unary1_op in developer documentation
+// See dev documentation: reverse_unary_op
+template <class Base>
+void reverse_neg_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_NARG_NRES( NegOp, 1, 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
+    Base* pz       = partial + i_z * nc_partial;
+
+    Base neg_one   = Base(-1.0);
+    for(size_t k = 0; k <= d; ++k)
+        px[k]  += azmul(pz[k], neg_one);
+
+}
+
+} } // END_CPPAD_LOCAL_NAMESPACE
+# endif
diff --git a/include/cppad/local/op/parameter_op.hpp b/include/cppad/local/op/parameter_op.hpp
new file mode 100644
index 000000000..dfbfdeceb
--- /dev/null
+++ b/include/cppad/local/op/parameter_op.hpp
@@ -0,0 +1,41 @@
+# ifndef CPPAD_LOCAL_OP_PARAMETER_OP_HPP
+# define CPPAD_LOCAL_OP_PARAMETER_OP_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.
+---------------------------------------------------------------------------- */
+
+
+namespace CppAD { namespace local { // BEGIN_CPPAD_LOCAL_NAMESPACE
+
+
+// See dev documentation: forward_unary_op
+template <class Base>
+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/include/cppad/local/pow_op.hpp b/include/cppad/local/op/pow_op.hpp
similarity index 81%
rename from include/cppad/local/pow_op.hpp
rename to include/cppad/local/op/pow_op.hpp
index 6994756f8..8e283ab6c 100644
--- a/include/cppad/local/pow_op.hpp
+++ b/include/cppad/local/op/pow_op.hpp
@@ -1,7 +1,7 @@
-# ifndef CPPAD_LOCAL_POW_OP_HPP
-# define CPPAD_LOCAL_POW_OP_HPP
+# ifndef CPPAD_LOCAL_OP_POW_OP_HPP
+# define CPPAD_LOCAL_OP_POW_OP_HPP
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
+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.
@@ -484,38 +484,40 @@ void forward_powvp_op(
     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( NumRes(PowvpOp) == 1 );
     CPPAD_ASSERT_UNKNOWN( q < cap_order );
     CPPAD_ASSERT_UNKNOWN( p <= q );
     CPPAD_ASSERT_UNKNOWN(
         size_t( std::numeric_limits<addr_t>::max() ) >= i_z
     );
 
-    // z_0 = log(x)
-    forward_log_op(p, q, i_z, size_t(arg[0]), cap_order, taylor);
+    // Taylor coefficients corresponding to arguments and result
+    Base* x = taylor + size_t(arg[0]) * cap_order;
+    Base* z = taylor + i_z    * cap_order;
 
-    // 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);
+    // Paraemter value
+    Base y = parameter[ arg[1] ];
 
-    // z_2 = exp(z_1)
-    // zero order case exactly same as Base type operation
+    // Special solution when x[0] is zero
+    Base b0 = Base( 0.0 );
+
+    // special case zero order
     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);
+    {   z[0] = pow(x[0], y);
         p++;
     }
-    if( p <= q )
-        forward_exp_op(p, q, i_z+2, i_z+1, cap_order, taylor);
+    for(size_t j = p; j <= q; ++j)
+    {   Base sum = Base(0);
+        for(size_t k = 1; k < j; ++k)
+        {   Base bk = Base( double(k) );
+            sum += bk * (y * x[k] * z[j-k] - z[k] * x[j-k]);
+        }
+        Base bj = Base( double(j) );
+        Base zj = ( y * z[0] * x[j] + sum / bj ) / x[0];
+        z[j] = CondExpEq(x[0], b0, b0, zj);
+    }
 }
 /*!
 Multiple directions forward mode Taylor coefficients for op = PowvpOp.
@@ -540,29 +542,45 @@ void forward_powvp_op_dir(
     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( NumRes(PowvpOp) == 1 );
     CPPAD_ASSERT_UNKNOWN( 0 < q );
     CPPAD_ASSERT_UNKNOWN( q < cap_order );
     CPPAD_ASSERT_UNKNOWN(
         size_t( std::numeric_limits<addr_t>::max() ) >= i_z
     );
 
-    // z_0 = log(x)
-    forward_log_op_dir(q, r, i_z, size_t(arg[0]), cap_order, taylor);
+    // 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;
 
-    // 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);
+    // Parameter value
+    Base y = parameter[ arg[1] ];
 
-    // z_2 = exp(z_1)
-    forward_exp_op_dir(q, r, i_z+2, i_z+1, cap_order, taylor);
+    // special solution when x[0] is zero
+    Base b0 = Base( 0.0 );
+
+    // index in Taylor coefficients where multiple directions start
+    size_t m = (q-1)*r + 1;
+    //
+    // loop over directions
+    for(size_t ell = 0; ell < r; ell++)
+    {   Base sum = Base(0);
+        for(size_t k = 1; k < q; ++k)
+        {   Base xk   = x[(k-1)*r   + ell + 1];
+            Base zk   = z[(k-1)*r   + ell + 1];
+            Base xqk  = x[(q-k-1)*r + ell + 1];
+            Base zqk  = z[(q-k-1)*r + ell + 1];
+            Base bk   = Base( double(k) );
+            sum += bk * (y * xk * zqk - zk * xqk);
+        }
+        Base xq  = x[(q-1)*r + ell + 1];
+        Base bq   = Base( double(q) );
+        Base zell = ( y * z[0] * xq + sum / bq ) / x[0];
+        z[m+ell]  = CondExpEq(x[0], b0, b0, zell);
+    }
 }
 
 /*!
@@ -586,31 +604,18 @@ void forward_powvp_op_0(
     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 );
+    CPPAD_ASSERT_UNKNOWN( NumRes(PowvpOp) == 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_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]);
+    Base* x = taylor + size_t(arg[0]) * cap_order;
+    Base* z = taylor + i_z * cap_order;
 
-    // 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);
+    z[0] = pow(x[0], y);
 }
 
 /*!
@@ -635,37 +640,74 @@ void reverse_powvp_op(
     size_t        cap_order   ,
     const Base*   taylor      ,
     size_t        nc_partial  ,
-    Base*         partial     )
+    Base*         partial     ,
+    CppAD::vector<Base>& work )
 {
-    // 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( NumRes(PowvpOp) == 1 );
     CPPAD_ASSERT_UNKNOWN( d < cap_order );
     CPPAD_ASSERT_UNKNOWN( d < nc_partial );
     CPPAD_ASSERT_UNKNOWN(
         size_t( std::numeric_limits<addr_t>::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
-    );
+    // Taylor coefficients
+    const Base* x = taylor + size_t( arg[0] ) * cap_order;
+    const Base* z = taylor + i_z * cap_order;
+
+    // parameter value
+    const 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;
+
+    // Special solution when x[0] is zero
+    Base b0 = Base( 0.0 );
+
+    // Place to hold px for this operator until conditional assigment at end
+    work.resize(nc_partial);
+    for(size_t j = 0; j <= d; ++j)
+        work[j] = px[j];
+
+    // reverse z^j for j = d, ..., 1
+    size_t j = d;
+    while(j)
+    {   // j
+        Base bj = Base( double(j) );
+        //
+        // x^j term
+        work[j] += azmul(pz[j], y * z[0] / x[0]);
+        //
+        // x^k terms
+        for(size_t k = 1; k < j; ++k)
+        {   Base bk   = Base( double(k) );
+            Base term = (bk * y - Base(j-k) ) * z[j-k] / (bj * x[0]);
+            work[k] += azmul(pz[j], term);
+        }
+        //
+        // z^k terms
+        for(size_t k = 1; k < j; ++k)
+        {   Base bk   = Base( double(k) );
+            Base term = (Base(j-k) * y - bk) * x[j-k] / (bj * x[0]);
+            pz[k] += azmul(pz[j], term);
+        }
+        //
+        // x^0 term
+        work[0] -= azmul(pz[j], z[j] / x[0]);
+        //
+        // z^0 term
+        pz[0] += azmul(pz[j], y * x[j] / x[0] );
+        //
+        // next j
+        --j;
+    }
+    // reverse z^0
+    work[0] += azmul(pz[0], y * z[0] / x[0]);
+    //
+    for(j = 0; j <=d; ++j)
+        px[j] = CondExpEq(x[0], b0, b0, work[j]);
 }
 
 } } // END_CPPAD_LOCAL_NAMESPACE
diff --git a/include/cppad/local/print_op.hpp b/include/cppad/local/op/print_op.hpp
similarity index 96%
rename from include/cppad/local/print_op.hpp
rename to include/cppad/local/op/print_op.hpp
index f338ecbdc..34214c130 100644
--- a/include/cppad/local/print_op.hpp
+++ b/include/cppad/local/op/print_op.hpp
@@ -1,7 +1,7 @@
-# ifndef CPPAD_LOCAL_PRINT_OP_HPP
-# define CPPAD_LOCAL_PRINT_OP_HPP
+# ifndef CPPAD_LOCAL_OP_PRINT_OP_HPP
+# define CPPAD_LOCAL_OP_PRINT_OP_HPP
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
+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.
diff --git a/include/cppad/local/prototype_op.hpp b/include/cppad/local/op/prototype_op.hpp
similarity index 99%
rename from include/cppad/local/prototype_op.hpp
rename to include/cppad/local/op/prototype_op.hpp
index dc93132ee..e2dc30224 100644
--- a/include/cppad/local/prototype_op.hpp
+++ b/include/cppad/local/op/prototype_op.hpp
@@ -1,7 +1,7 @@
-# ifndef CPPAD_LOCAL_PROTOTYPE_OP_HPP
-# define CPPAD_LOCAL_PROTOTYPE_OP_HPP
+# ifndef CPPAD_LOCAL_OP_PROTOTYPE_OP_HPP
+# define CPPAD_LOCAL_OP_PROTOTYPE_OP_HPP
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 Bradley M. Bell
+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.
diff --git a/include/cppad/local/sign_op.hpp b/include/cppad/local/op/sign_op.hpp
similarity index 73%
rename from include/cppad/local/sign_op.hpp
rename to include/cppad/local/op/sign_op.hpp
index 2906b51da..2079f22e9 100644
--- a/include/cppad/local/sign_op.hpp
+++ b/include/cppad/local/op/sign_op.hpp
@@ -1,7 +1,7 @@
-# ifndef CPPAD_LOCAL_SIGN_OP_HPP
-# define CPPAD_LOCAL_SIGN_OP_HPP
+# ifndef CPPAD_LOCAL_OP_SIGN_OP_HPP
+# define CPPAD_LOCAL_OP_SIGN_OP_HPP
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-17 Bradley M. Bell
+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.
@@ -14,21 +14,8 @@ in the Eclipse Public License, Version 2.0 are satisfied:
 
 
 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
-*/
+// See dev documentation: forward_unary_op
 template <class Base>
 void forward_sign_op(
     size_t p           ,
@@ -55,16 +42,7 @@ void forward_sign_op(
     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
-*/
+// See dev documentation: forward_unary_op
 template <class Base>
 void forward_sign_op_dir(
     size_t q           ,
@@ -89,16 +67,7 @@ void forward_sign_op_dir(
         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
-*/
+// See dev documentation: forward_unary_op
 template <class Base>
 void forward_sign_op_0(
     size_t i_z         ,
@@ -118,17 +87,8 @@ void forward_sign_op_0(
 
     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
-*/
 
+// See dev documentation: reverse_unary_op
 template <class Base>
 void reverse_sign_op(
     size_t      d            ,
diff --git a/include/cppad/local/sin_op.hpp b/include/cppad/local/op/sin_op.hpp
similarity index 77%
rename from include/cppad/local/sin_op.hpp
rename to include/cppad/local/op/sin_op.hpp
index de3471c8f..6aee5c912 100644
--- a/include/cppad/local/sin_op.hpp
+++ b/include/cppad/local/op/sin_op.hpp
@@ -1,7 +1,7 @@
-# ifndef CPPAD_LOCAL_SIN_OP_HPP
-# define CPPAD_LOCAL_SIN_OP_HPP
+# ifndef CPPAD_LOCAL_OP_SIN_OP_HPP
+# define CPPAD_LOCAL_OP_SIN_OP_HPP
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-17 Bradley M. Bell
+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.
@@ -14,28 +14,9 @@ in the Eclipse Public License, Version 2.0 are satisfied:
 
 
 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
-*/
+
+
+// See dev documentation: forward_unary_op
 template <class Base>
 void forward_sin_op(
     size_t p           ,
@@ -77,22 +58,7 @@ void forward_sin_op(
         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
-*/
+// See dev documentation: forward_unary_op
 template <class Base>
 void forward_sin_op_dir(
     size_t q           ,
@@ -132,21 +98,7 @@ void forward_sin_op_dir(
 }
 
 
-/*!
-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
-*/
+// See dev documentation: forward_unary_op
 template <class Base>
 void forward_sin_op_0(
     size_t i_z         ,
@@ -168,22 +120,8 @@ void forward_sin_op_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
-*/
 
+// See dev documentation: reverse_unary_op
 template <class Base>
 void reverse_sin_op(
     size_t      d            ,
diff --git a/include/cppad/local/sinh_op.hpp b/include/cppad/local/op/sinh_op.hpp
similarity index 76%
rename from include/cppad/local/sinh_op.hpp
rename to include/cppad/local/op/sinh_op.hpp
index 9fd05568c..fba91c468 100644
--- a/include/cppad/local/sinh_op.hpp
+++ b/include/cppad/local/op/sinh_op.hpp
@@ -1,7 +1,7 @@
-# ifndef CPPAD_LOCAL_SINH_OP_HPP
-# define CPPAD_LOCAL_SINH_OP_HPP
+# ifndef CPPAD_LOCAL_OP_SINH_OP_HPP
+# define CPPAD_LOCAL_OP_SINH_OP_HPP
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-17 Bradley M. Bell
+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.
@@ -14,28 +14,9 @@ in the Eclipse Public License, Version 2.0 are satisfied:
 
 
 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
-*/
+
+
+// See dev documentation: forward_unary_op
 template <class Base>
 void forward_sinh_op(
     size_t p           ,
@@ -78,22 +59,7 @@ void forward_sinh_op(
         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
-*/
+// See dev documentation: forward_unary_op
 template <class Base>
 void forward_sinh_op_dir(
     size_t q           ,
@@ -132,21 +98,7 @@ void forward_sinh_op_dir(
     }
 }
 
-/*!
-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
-*/
+// See dev documentation: forward_unary_op
 template <class Base>
 void forward_sinh_op_0(
     size_t i_z         ,
@@ -167,22 +119,8 @@ void forward_sinh_op_0(
     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
-*/
 
+// See dev documentation: reverse_unary_op
 template <class Base>
 void reverse_sinh_op(
     size_t      d            ,
diff --git a/include/cppad/local/sqrt_op.hpp b/include/cppad/local/op/sqrt_op.hpp
similarity index 79%
rename from include/cppad/local/sqrt_op.hpp
rename to include/cppad/local/op/sqrt_op.hpp
index a99ea5e9f..ed3ec93a0 100644
--- a/include/cppad/local/sqrt_op.hpp
+++ b/include/cppad/local/op/sqrt_op.hpp
@@ -1,7 +1,7 @@
-# ifndef CPPAD_LOCAL_SQRT_OP_HPP
-# define CPPAD_LOCAL_SQRT_OP_HPP
+# ifndef CPPAD_LOCAL_OP_SQRT_OP_HPP
+# define CPPAD_LOCAL_OP_SQRT_OP_HPP
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-17 Bradley M. Bell
+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.
@@ -14,22 +14,9 @@ in the Eclipse Public License, Version 2.0 are satisfied:
 
 
 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
-*/
+// See dev documentation: forward_unary_op
 template <class Base>
 void forward_sqrt_op(
     size_t p           ,
@@ -65,16 +52,7 @@ void forward_sqrt_op(
     }
 }
 
-/*!
-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
-*/
+// See dev documentation: forward_unary_op
 template <class Base>
 void forward_sqrt_op_dir(
     size_t q           ,
@@ -106,16 +84,7 @@ void forward_sqrt_op_dir(
     }
 }
 
-/*!
-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
-*/
+// See dev documentation: forward_unary_op
 template <class Base>
 void forward_sqrt_op_0(
     size_t i_z         ,
@@ -134,17 +103,8 @@ void forward_sqrt_op_0(
 
     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
-*/
 
+// See dev documentation: reverse_unary_op
 template <class Base>
 void reverse_sqrt_op(
     size_t      d            ,
diff --git a/include/cppad/local/store_op.hpp b/include/cppad/local/op/store_op.hpp
similarity index 99%
rename from include/cppad/local/store_op.hpp
rename to include/cppad/local/op/store_op.hpp
index f7989bbb0..493b42167 100644
--- a/include/cppad/local/store_op.hpp
+++ b/include/cppad/local/op/store_op.hpp
@@ -1,7 +1,7 @@
-# ifndef CPPAD_LOCAL_STORE_OP_HPP
-# define CPPAD_LOCAL_STORE_OP_HPP
+# ifndef CPPAD_LOCAL_OP_STORE_OP_HPP
+# define CPPAD_LOCAL_OP_STORE_OP_HPP
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
+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.
diff --git a/include/cppad/local/sub_op.hpp b/include/cppad/local/op/sub_op.hpp
similarity index 70%
rename from include/cppad/local/sub_op.hpp
rename to include/cppad/local/op/sub_op.hpp
index 23c373ef2..3a218a923 100644
--- a/include/cppad/local/sub_op.hpp
+++ b/include/cppad/local/op/sub_op.hpp
@@ -1,7 +1,7 @@
-# ifndef CPPAD_LOCAL_SUB_OP_HPP
-# define CPPAD_LOCAL_SUB_OP_HPP
+# ifndef CPPAD_LOCAL_OP_SUB_OP_HPP
+# define CPPAD_LOCAL_OP_SUB_OP_HPP
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-18 Bradley M. Bell
+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.
@@ -13,26 +13,10 @@ in the Eclipse Public License, Version 2.0 are satisfied:
 ---------------------------------------------------------------------------- */
 
 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
-*/
 
+// See dev documentation: forward_binary_op
 template <class Base>
 void forward_subvv_op(
     size_t        p           ,
@@ -57,20 +41,8 @@ void forward_subvv_op(
     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
-*/
 
+// See dev documentation: forward_binary_op
 template <class Base>
 void forward_subvv_op_dir(
     size_t        q           ,
@@ -98,20 +70,8 @@ void forward_subvv_op_dir(
         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
-*/
 
+// See dev documentation: forward_binary_op
 template <class Base>
 void forward_subvv_op_0(
     size_t        i_z         ,
@@ -132,20 +92,8 @@ void forward_subvv_op_0(
     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
-*/
 
+// See dev documentation: reverse_binary_op
 template <class Base>
 void reverse_subvv_op(
     size_t        d           ,
@@ -178,19 +126,8 @@ void reverse_subvv_op(
 }
 
 // --------------------------- 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
-*/
 
+// See dev documentation: forward_binary_op
 template <class Base>
 void forward_subpv_op(
     size_t        p           ,
@@ -220,19 +157,8 @@ void forward_subpv_op(
     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
-*/
 
+// See dev documentation: forward_binary_op
 template <class Base>
 void forward_subpv_op_dir(
     size_t        q           ,
@@ -259,19 +185,8 @@ void forward_subpv_op_dir(
     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
-*/
 
+// See dev documentation: forward_binary_op
 template <class Base>
 void forward_subpv_op_0(
     size_t        i_z         ,
@@ -294,19 +209,8 @@ void forward_subpv_op_0(
     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
-*/
 
+// See dev documentation: reverse_binary_op
 template <class Base>
 void reverse_subpv_op(
     size_t        d           ,
@@ -337,19 +241,8 @@ void reverse_subpv_op(
 }
 
 // --------------------------- 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
-*/
 
+// See dev documentation: forward_binary_op
 template <class Base>
 void forward_subvp_op(
     size_t        p           ,
@@ -379,19 +272,8 @@ void forward_subvp_op(
     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
-*/
 
+// See dev documentation: forward_binary_op
 template <class Base>
 void forward_subvp_op_dir(
     size_t        q           ,
@@ -419,19 +301,8 @@ void forward_subvp_op_dir(
         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
-*/
 
+// See dev documentation: forward_binary_op
 template <class Base>
 void forward_subvp_op_0(
     size_t        i_z         ,
@@ -454,19 +325,8 @@ void forward_subvp_op_0(
     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
-*/
 
+// See dev documentation: reverse_binary_op
 template <class Base>
 void reverse_subvp_op(
     size_t        d           ,
diff --git a/include/cppad/local/tan_op.hpp b/include/cppad/local/op/tan_op.hpp
similarity index 74%
rename from include/cppad/local/tan_op.hpp
rename to include/cppad/local/op/tan_op.hpp
index fba7dc836..b2d4810f9 100644
--- a/include/cppad/local/tan_op.hpp
+++ b/include/cppad/local/op/tan_op.hpp
@@ -1,7 +1,7 @@
-# ifndef CPPAD_LOCAL_TAN_OP_HPP
-# define CPPAD_LOCAL_TAN_OP_HPP
+# ifndef CPPAD_LOCAL_OP_TAN_OP_HPP
+# define CPPAD_LOCAL_OP_TAN_OP_HPP
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-17 Bradley M. Bell
+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.
@@ -14,28 +14,9 @@ in the Eclipse Public License, Version 2.0 are satisfied:
 
 
 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
-*/
+
+
+// See dev documentation: forward_unary_op
 template <class Base>
 void forward_tan_op(
     size_t p           ,
@@ -75,22 +56,7 @@ void forward_tan_op(
     }
 }
 
-/*!
-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
-*/
+// See dev documentation: forward_unary_op
 template <class Base>
 void forward_tan_op_dir(
     size_t q           ,
@@ -127,21 +93,7 @@ void forward_tan_op_dir(
 }
 
 
-/*!
-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
-*/
+// See dev documentation: forward_unary_op
 template <class Base>
 void forward_tan_op_0(
     size_t i_z         ,
@@ -163,22 +115,8 @@ void forward_tan_op_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
-*/
 
+// See dev documentation: reverse_unary_op
 template <class Base>
 void reverse_tan_op(
     size_t      d            ,
diff --git a/include/cppad/local/tanh_op.hpp b/include/cppad/local/op/tanh_op.hpp
similarity index 74%
rename from include/cppad/local/tanh_op.hpp
rename to include/cppad/local/op/tanh_op.hpp
index a2ade1faa..59e40a87d 100644
--- a/include/cppad/local/tanh_op.hpp
+++ b/include/cppad/local/op/tanh_op.hpp
@@ -1,7 +1,7 @@
-# ifndef CPPAD_LOCAL_TANH_OP_HPP
-# define CPPAD_LOCAL_TANH_OP_HPP
+# ifndef CPPAD_LOCAL_OP_TANH_OP_HPP
+# define CPPAD_LOCAL_OP_TANH_OP_HPP
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-17 Bradley M. Bell
+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.
@@ -14,28 +14,9 @@ in the Eclipse Public License, Version 2.0 are satisfied:
 
 
 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
-*/
+
+
+// See dev documentation: forward_unary_op
 template <class Base>
 void forward_tanh_op(
     size_t p           ,
@@ -75,22 +56,7 @@ void forward_tanh_op(
     }
 }
 
-/*!
-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
-*/
+// See dev documentation: forward_unary_op
 template <class Base>
 void forward_tanh_op_dir(
     size_t q           ,
@@ -126,21 +92,7 @@ void forward_tanh_op_dir(
     }
 }
 
-/*!
-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
-*/
+// See dev documentation: forward_unary_op
 template <class Base>
 void forward_tanh_op_0(
     size_t i_z         ,
@@ -162,22 +114,8 @@ void forward_tanh_op_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
-*/
 
+// See dev documentation: reverse_unary_op
 template <class Base>
 void reverse_tanh_op(
     size_t      d            ,
diff --git a/include/cppad/local/op/unary_op.omh b/include/cppad/local/op/unary_op.omh
new file mode 100644
index 000000000..a33cb8840
--- /dev/null
+++ b/include/cppad/local/op/unary_op.omh
@@ -0,0 +1,354 @@
+/* --------------------------------------------------------------------------
+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 forward_unary_op$$
+$spell
+    NumRes
+    Taylor
+    op
+$$
+
+$section Variable Forward Unary Operators$$
+
+$head Syntax$$
+$codei%forward_%name%_op(%p%, %q%, %i_z%, %i_x%, %cap_order%, %taylor%)%$$
+
+$head Assumption$$
+The operator corresponding to $icode name$$ has one argument and one result.
+
+$head Notation$$
+
+$subhead x$$
+We use $icode x$$ to denote the argument of this unary operation.
+
+$subhead z$$
+We use $icode z$$ to denote the primary result of this unary operation.
+If this operator has two results, $codei%NumRes(%op%) == 2%$$,
+we call the other the auxillary result.
+
+$head Base$$
+is the 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 p$$
+This argument has type $code size_t$$ and
+is lowest order of the Taylor coefficient that we are computing.
+
+$head q$$
+The argument $icode q >= p$$ has type $code size_t$$ and
+is highest order of the Taylor coefficient that we are computing.
+
+$head i_z$$
+This argument has type $code size_t$$ and
+is the variable index corresponding to the primary result for this operation;
+i.e. the row index in taylor corresponding to $icode z$$.
+If this operator has an auxillary result, its variable index is
+$icode%i_z% - 1%$$.
+
+$head i_x$$
+This argument has type $code size_t$$ and
+is variable index corresponding to the argument for this operator;
+i.e. the row index in taylor corresponding to $code x$$.
+
+$head cap_order$$
+This argument has type $code size_t$$ and
+is the maximum number of orders that will fit in $icode taylor$$.
+
+$head taylor$$
+This argument has type $icode%Base%*%$$.
+The Taylor coefficient corresponding to
+variable $icode i$$ and order $icode k$$ is
+$codei%
+    %taylor%[ %i% * %cap_order% + %k% ]
+%$$.
+
+$subhead Input$$
+$list number$$
+The Taylor coefficients for variable $icode i_x$$ up to order $icode q$$.
+$lnext
+The Taylor coefficients for variable $icode i_z$$ up to order $icode%p%-1%$$.
+$lnext
+If this operator has an auxillary result,
+the Taylor coefficients for variable $icode%i_z%-1%$$
+up to order $icode%p%-1%$$.
+$lend
+
+$subhead Output$$
+The Taylor coefficients for variable $icode i_z$$ up to order $icode q$$.
+
+$end
+------------------------------------------------------------------------------
+$begin forward_unary_op_dir$$
+$spell
+    NumRes
+    op
+    tpv
+    Taylor
+$$
+
+$section Multiple Direction Forward Unary Operators$$
+
+$head Syntax$$
+$codei%forward_%name%_op(%q%, %r%, %i_z%, %i_x%, %cap_order%, %taylor%)%$$
+
+$head Assumption$$
+The operator corresponding to $icode name$$ has one argument and one result.
+
+$head Notation$$
+
+$subhead x$$
+We use $icode x$$ to denote the argument of this unary operation.
+
+$subhead z$$
+We use $icode z$$ to denote the primary result of this unary operation.
+If this operator has two results, $codei%NumRes(%op%) == 2%$$,
+we call the other the auxillary result.
+
+$head Base$$
+is the 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 q$$
+This argument has type $code size_t$$ and
+is the order of the Taylor coefficients that we are computing.
+Furthermore $icode%q% > 0%$$ and $icode%q% < %cap_order%$$.
+
+$head r$$
+This argument has type $code size_t$$ and
+is number of directions for Taylor coefficients that we are computing.
+
+$head i_z$$
+This argument has type $code size_t$$ and
+is the variable index corresponding to the primary result for this operation;
+i.e. the row index in taylor corresponding to $icode z$$.
+If this operator has an auxillary result, its variable index is
+$icode%i_z% - 1%$$.
+
+$head i_x$$
+This argument has type $code size_t$$ and
+is variable index corresponding to the argument for this operator;
+i.e. the row index in taylor corresponding to $code x$$.
+
+$head cap_order$$
+This argument has type $code size_t$$ and
+is the maximum number of orders that will fit in $icode taylor$$.
+The zero order Taylor coefficient for a variable
+is the same for all directions.  We use the notation
+$codei%
+    %tpv% = (%cap_order% - 1) * r + 1
+%$$
+which is the number of Taylor coefficients per variable.
+
+$head taylor$$
+This argument has type $icode%Base%*%$$.
+The zero order Taylor coefficient for variable $icode i$$ is
+$codei%
+    %taylor%[ %i% * %tpv% + 0 ]
+%$$.
+For $icode k > 0$$,
+and $icode%ell% = 0 , %..% , %r-1%$$,
+The Taylor coefficient for variable $icode i$$,
+order $icode k$$, and direction $icode ell$$ is
+$codei%
+    %taylor%[ %i% * %tpv% + (%k% - 1) * %r% + %ell% + 1 ]
+%$$.
+
+$head Input$$
+$list number$$
+The Taylor coefficients for variable $icode i_x$$ up to order $icode q$$
+and all $icode r$$ directions.
+$lnext
+The Taylor coefficients for variable $icode i_z$$ up to order $icode q-1$$
+and all $icode r$$ directions.
+$lnext
+If this operator has an auxillary result,
+the Taylor coefficients for variable $icode%i_z%-1%$$
+up to order $icode%q%-1%$$.
+$lend
+
+$head Output$$
+The Taylor coefficients for variable $icode i_z$$ up to order $icode q$$
+and all $icode r$$ directions.
+
+$end
+-------------------------------------------------------------------------------
+/*
+$begin forward_unary_op_0$$
+$spell
+    NumRes
+    op
+    Taylor
+$$
+
+$section Zero Order Forward Unary Operators$$
+
+$head Syntax$$
+$codei%forward_%name%_op_0(%i_z%, %i_x%, %cap_order%, %taylor%)%$$
+
+$head Assumption$$
+The operator corresponding to $icode name$$ has one argument and one result.
+
+$head Notation$$
+
+$subhead x$$
+We use $icode x$$ to denote the argument of this unary operation.
+
+$subhead z$$
+We use $icode z$$ to denote the primary result of this unary operation.
+If this operator has two results, $codei%NumRes(%op%) == 2%$$,
+we call the other the auxillary result.
+
+$head Base$$
+is the 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 i_z$$
+This argument has type $code size_t$$ and
+is the variable index corresponding to the primary result for this operation;
+i.e. the row index in taylor corresponding to $icode z$$.
+If this operator has an auxillary result, its variable index is
+$icode%i_z% - 1%$$.
+
+$head i_x$$
+This argument has type $code size_t$$ and
+is variable index corresponding to the argument for this operator;
+i.e. the row index in taylor corresponding to $code x$$.
+
+$head cap_order$$
+The argument $icode%cap_order% > 0%$$ has type $code size_t$$ and
+is the maximum number of orders that will fit in $icode taylor$$.
+
+$head taylor$$
+This argument has type $icode%Base%*%$$.
+The Taylor coefficient corresponding to
+variable $icode i$$ and order $icode k$$ is
+$codei%
+    %taylor%[ %i% * %cap_order% + %k% ]
+%$$.
+
+$subhead Input$$
+The zero order Taylor coefficients for variable $icode i_x$$.
+
+$subhead Output$$
+The zero order Taylor coefficients for variable $icode i_z$$.
+If this operator has an auxillary result,
+the Taylor coefficient for variable $icode%i_z%-1%$$.
+
+$end
+------------------------------------------------------------------------------
+/*
+$begin reverse_unary_op$$
+$spell
+    NumRes
+    op
+    Taylor
+    nc
+    const
+$$
+
+$section Reverse Unary Operators$$
+
+$head Syntax$$
+$codei%reverse_%name%_op(
+    %d%, %i_z%, %i_x%, %cap_order%, %taylor%, %nc_partial%, %partial%
+)%$$
+
+$head Assumption$$
+The operator corresponding to $icode name$$ has one argument and one result.
+
+$head Notation$$
+
+$subhead x$$
+We use $icode x$$ to denote the argument of this unary operation.
+
+$subhead z$$
+We use $icode z$$ to denote the primary result of this unary operation.
+If this operator has two results, $codei%NumRes(%op%) == 2%$$,
+we call the other the auxillary result.
+
+$subhead G$$
+We use $latex G(z, x, w, \ldots )$$ to denote a scalar valued function of the
+variables up to variable index $icode i_z$$.
+
+$subhead H$$
+We use $latex H(x, w, \ldots )$$ to denote the scalar valued function of the
+variables up to variable index $icode%i_z%-1%$$ defined by
+$latex \[
+    H(x, w, \ldots ) = G [ z(x), x, w, \ldots ) ]
+\]$$
+
+$head Base$$
+is the 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 d$$
+This argument has type $code size_t$$ and
+is this highest order Taylor coefficient that we are computing
+partial derivatives with respect to.
+Furthermore $icode%d% < %cap_order%$$ and $icode%d% < %nc_partial%$$.
+
+$head i_z$$
+This argument has type $code size_t$$ and
+is the variable index corresponding to the primary result for this operation;
+i.e. the row index in taylor corresponding to $icode z$$.
+If this operator has an auxillary result, its variable index is
+$icode%i_z% - 1%$$.
+
+$head i_x$$
+This argument has type $code size_t$$ and
+is variable index corresponding to the argument for this operator;
+i.e. the row index in taylor corresponding to $code x$$.
+Furthermore $icode%i_x% < %i_z%$$.
+
+$head cap_order$$
+This argument has type $code size_t$$ and
+is the maximum number of orders that will fit in $icode taylor$$.
+
+$head taylor$$
+This argument has type $codei%const %Base%*%$$.
+The Taylor coefficient corresponding to
+variable $icode i$$ and order $icode k$$ is
+$codei%
+    %taylor%[ %i% * %cap_order% + %k% ]
+%$$.
+
+$head nc_partial$$
+This argument has type $code size_t$$ and
+is the number of columns in the partial array.
+
+$head partial$$
+This argument has type $icode%Base%*%$$.
+The partial derivative w.r.t. variable $icode i$$ and
+Taylor coefficient order $icode k$$ is
+$code%
+    %partial% [ %i% * %nc_partial% + k ]
+%$$
+for $icode%k% = 0 , %...%, %d%$$.
+
+$subhead Input$$
+For variable $icode%i% = 0 ,%...%, %i_z%$$,
+$icode partial$$ contains the
+partial derivatives of $latex G(z, x, w, \ldots)$$.
+
+$subhead Output$$
+The array $icode partial$$ contains the
+partial derivatives of $latex H(x, w, \ldots)$$.
+The partial derivative for variable $icode i_z$$ is unspecified.
+If this operator has an auxillary result,
+The partial derivative for variable $icode%i_z% - 1%$$ is unspecified.
+
+$end
+------------------------------------------------------------------------------
diff --git a/include/cppad/local/zmul_op.hpp b/include/cppad/local/op/zmul_op.hpp
similarity index 71%
rename from include/cppad/local/zmul_op.hpp
rename to include/cppad/local/op/zmul_op.hpp
index 13f9049ee..546a78e42 100644
--- a/include/cppad/local/zmul_op.hpp
+++ b/include/cppad/local/op/zmul_op.hpp
@@ -1,7 +1,7 @@
-# ifndef CPPAD_LOCAL_ZMUL_OP_HPP
-# define CPPAD_LOCAL_ZMUL_OP_HPP
+# ifndef CPPAD_LOCAL_OP_ZMUL_OP_HPP
+# define CPPAD_LOCAL_OP_ZMUL_OP_HPP
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-18 Bradley M. Bell
+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.
@@ -13,26 +13,10 @@ in the Eclipse Public License, Version 2.0 are satisfied:
 ---------------------------------------------------------------------------- */
 
 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
-*/
 
+// See dev documentation: forward_binary_op
 template <class Base>
 void forward_zmulvv_op(
     size_t        p           ,
@@ -61,20 +45,8 @@ void forward_zmulvv_op(
             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
-*/
 
+// See dev documentation: forward_binary_op
 template <class Base>
 void forward_zmulvv_op_dir(
     size_t        q           ,
@@ -106,20 +78,8 @@ void forward_zmulvv_op_dir(
     }
 }
 
-/*!
-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
-*/
 
+// See dev documentation: forward_binary_op
 template <class Base>
 void forward_zmulvv_op_0(
     size_t        i_z         ,
@@ -140,20 +100,8 @@ void forward_zmulvv_op_0(
     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
-*/
 
+// See dev documentation: reverse_binary_op
 template <class Base>
 void reverse_zmulvv_op(
     size_t        d           ,
@@ -193,19 +141,8 @@ void reverse_zmulvv_op(
     }
 }
 // --------------------------- 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
-*/
 
+// See dev documentation: forward_binary_op
 template <class Base>
 void forward_zmulpv_op(
     size_t        p           ,
@@ -232,19 +169,8 @@ void forward_zmulpv_op(
     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
-*/
 
+// See dev documentation: forward_binary_op
 template <class Base>
 void forward_zmulpv_op_dir(
     size_t        q           ,
@@ -273,19 +199,8 @@ void forward_zmulpv_op_dir(
     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
-*/
 
+// See dev documentation: forward_binary_op
 template <class Base>
 void forward_zmulpv_op_0(
     size_t        i_z         ,
@@ -308,19 +223,8 @@ void forward_zmulpv_op_0(
     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
-*/
 
+// See dev documentation: reverse_binary_op
 template <class Base>
 void reverse_zmulpv_op(
     size_t        d           ,
@@ -353,19 +257,8 @@ void reverse_zmulpv_op(
     }
 }
 // --------------------------- 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
-*/
 
+// See dev documentation: forward_binary_op
 template <class Base>
 void forward_zmulvp_op(
     size_t        p           ,
@@ -392,19 +285,8 @@ void forward_zmulvp_op(
     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
-*/
 
+// See dev documentation: forward_binary_op
 template <class Base>
 void forward_zmulvp_op_dir(
     size_t        q           ,
@@ -433,19 +315,8 @@ void forward_zmulvp_op_dir(
     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
-*/
 
+// See dev documentation: forward_binary_op
 template <class Base>
 void forward_zmulvp_op_0(
     size_t        i_z         ,
@@ -468,19 +339,8 @@ void forward_zmulvp_op_0(
     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
-*/
 
+// See dev documentation: reverse_binary_op
 template <class Base>
 void reverse_zmulvp_op(
     size_t        d           ,
diff --git a/include/cppad/local/op_code_dyn.hpp b/include/cppad/local/op_code_dyn.hpp
index 195d72ff5..0ab6d0e5f 100644
--- a/include/cppad/local/op_code_dyn.hpp
+++ b/include/cppad/local/op_code_dyn.hpp
@@ -1,7 +1,7 @@
 # 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: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
 
 CppAD is distributed under the terms of the
              Eclipse Public License Version 2.0.
@@ -74,30 +74,34 @@ This is the index that identifies this atomic function; see
 $code local/atomic_index.hpp$$.
 
 $subhead arg[1]$$
+This is the $cref/call_id/atomic_four_call/call_id/$$ for this
+function call.
+
+$subhead arg[2]$$
 This is the number of arguments to this atomic function.
 We use the notation $icode%n% = %arg%[1]%$$ below.
 
-$subhead arg[2]$$
+$subhead arg[3]$$
 This is the number of results for this atomic function.
 We use the notation $icode%m% = %arg%[2]%$$ below.
 
-$subhead arg[3]$$
+$subhead arg[4]$$
 This is the number of result values that are dynamic parameters
 for this function call.
 
-$subhead arg[4+j]$$
+$subhead arg[5+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]$$
+$subhead arg[5+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]$$
+$subhead arg[5+n+m]$$
 This is the number of arguments to this operator; i.e.,
-$codei%5+%n%+%m%$$.
+$codei%6+%n%+%m%$$.
 
 $head result_dyn$$
 This is a place holder for a result of an atomic function call
@@ -177,6 +181,7 @@ enum op_code_dyn {
     log1p_dyn,     // unary
     log_dyn,       // unary
     mul_dyn,       // binary
+    neg_dyn,       // unary
     pow_dyn,       // binary
     result_dyn,    // 0 arguments: atomic function result
     sign_dyn,      // unary
@@ -263,6 +268,7 @@ inline size_t num_arg_dyn(op_code_dyn op)
         /* log1p_dyn */    1,
         /* log_dyn */      1,
         /* mul_dyn */      2,
+        /* neg_dyn */      1,
         /* pow_dyn */      2,
         /* result_dyn */   0,
         /* sign_dyn */     1,
@@ -352,6 +358,7 @@ inline const char* op_name_dyn(op_code_dyn op)
         /* log1p_dyn */    "log1p",
         /* log_dyn */      "log",
         /* mul_dyn */      "mul",
+        /* neg_dyn */      "neg",
         /* pow_dyn */      "pow",
         /* result_dyn */   "result",
         /* sign_dyn */     "sign",
@@ -419,7 +426,7 @@ inline size_t num_non_par_arg_dyn(op_code_dyn op)
     size_t num;
     switch(op)
     {   case atom_dyn:
-        num = 4;
+        num = 5;
         break;
 
         case cond_exp_dyn:
diff --git a/include/cppad/local/op_code_var.hpp b/include/cppad/local/op_code_var.hpp
index f1115594a..f96aba9aa 100644
--- a/include/cppad/local/op_code_var.hpp
+++ b/include/cppad/local/op_code_var.hpp
@@ -1,7 +1,7 @@
 # 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: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
 
 CppAD is distributed under the terms of the
              Eclipse Public License Version 2.0.
@@ -56,6 +56,8 @@ $spell
     Funav
     Funrp
     Funrv
+    Powpv
+    Powvv
 $$
 
 $head Namespace$$
@@ -104,7 +106,7 @@ 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
+The binary $codei%pow(%x%, %y%)%$$ operators PowpvOp, PowvvOp are
 special because they have three variable results instead of one.
 To be specific, they compute
 $codei%log(%x%)%$$,
@@ -120,8 +122,9 @@ $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
+This is the $cref/call_id/atomic_four_call/call_id/$$ information.
+It is also he $cref/id/atomic_one/id/$$
+for atomic one functions which have been deprecated.
 
 $subhead arg[2]$$
 is the number of arguments to this atomic function.
@@ -448,13 +451,14 @@ enum OpCode {
     LtvvOp,   // ...
     MulpvOp,  // binary *
     MulvvOp,  // ...
+    NegOp,    // unary negative
     NeppOp,   // compare !=
     NepvOp,   // ...
     NevvOp,   // ...
     ParOp,    // see its heading above
-    PowpvOp,  // see Pow heading above
-    PowvpOp,  // ...
-    PowvvOp,  // ...
+    PowpvOp,  // see its heading above
+    PowvpOp,  // binary
+    PowvvOp,  // see its heading above
     PriOp,    // see its heading above
     SignOp,   // unary sign
     SinOp,    // unary sin
@@ -554,6 +558,7 @@ inline size_t NumArg( OpCode op)
         2, // LtvvOp
         2, // MulpvOp
         2, // MulvvOp
+        1, // NegOp
         2, // NeppOp
         2, // NepvOp
         2, // NevvOp
@@ -672,12 +677,13 @@ inline size_t NumRes(OpCode op)
         0, // LtvvOp
         1, // MulpvOp
         1, // MulvvOp
+        1, // NegOp
         0, // NeppOp
         0, // NepvOp
         0, // NevvOp
         1, // ParOp
         3, // PowpvOp
-        3, // PowvpOp
+        1, // PowvpOp
         3, // PowvvOp
         0, // PriOp
         1, // SignOp
@@ -768,6 +774,7 @@ inline const char* OpName(OpCode op)
         "Ltvv"  ,
         "Mulpv" ,
         "Mulvv" ,
+        "Neg"   ,
         "Nepp"  ,
         "Nepv"  ,
         "Nevv"  ,
@@ -1091,6 +1098,7 @@ void printOp(
         case Expm1Op:
         case LogOp:
         case Log1pOp:
+        case NegOp:
         case SignOp:
         case SinOp:
         case SinhOp:
@@ -1325,6 +1333,7 @@ void arg_is_variable(
         case ExpOp:
         case Log1pOp:
         case LogOp:
+        case NegOp:
         case SignOp:
         case SinhOp:
         case SinOp:
diff --git a/include/cppad/local/optimize/get_dyn_previous.hpp b/include/cppad/local/optimize/get_dyn_previous.hpp
index e36f0bba8..ba601cb13 100644
--- a/include/cppad/local/optimize/get_dyn_previous.hpp
+++ b/include/cppad/local/optimize/get_dyn_previous.hpp
@@ -1,7 +1,7 @@
 # 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: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
 
 CppAD is distributed under the terms of the
              Eclipse Public License Version 2.0.
@@ -251,6 +251,7 @@ void get_dyn_previous(
             case fabs_dyn:
             case log_dyn:
             case log1p_dyn:
+            case neg_dyn:
             case sign_dyn:
             case sin_dyn:
             case sinh_dyn:
@@ -434,9 +435,9 @@ void get_dyn_previous(
         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;
+            size_t n     = size_t( dyn_par_arg[i_arg + 2] );
+            size_t m     = size_t( dyn_par_arg[i_arg + 3] );
+            size_t n_arg = 6 + n + m;
             i_arg += n_arg;
         }
     }
diff --git a/include/cppad/local/optimize/get_op_previous.hpp b/include/cppad/local/optimize/get_op_previous.hpp
index 312a8470d..a3cb5df0e 100644
--- a/include/cppad/local/optimize/get_op_previous.hpp
+++ b/include/cppad/local/optimize/get_op_previous.hpp
@@ -1,7 +1,7 @@
 # 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: C++ Algorithmic Differentiation: Copyright (C) 2003-21 Bradley M. Bell
 
 CppAD is distributed under the terms of the
              Eclipse Public License Version 2.0.
@@ -207,6 +207,7 @@ bool get_op_previous(
             case LtvvOp:
             case MulpvOp:
             case MulvvOp:
+            case NegOp:
             case NepvOp:
             case NevvOp:
             case PowpvOp:
diff --git a/include/cppad/local/optimize/get_op_usage.hpp b/include/cppad/local/optimize/get_op_usage.hpp
index 504f2f857..5da9c5e4f 100644
--- a/include/cppad/local/optimize/get_op_usage.hpp
+++ b/include/cppad/local/optimize/get_op_usage.hpp
@@ -1,7 +1,7 @@
 # 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: C++ Algorithmic Differentiation: Copyright (C) 2003-21 Bradley M. Bell
 
 CppAD is distributed under the terms of the
              Eclipse Public License Version 2.0.
@@ -411,6 +411,7 @@ void get_op_usage(
             case Expm1Op:
             case LogOp:
             case Log1pOp:
+            case NegOp:
             case PowvpOp:
             case SignOp:
             case SinOp:
diff --git a/include/cppad/local/optimize/get_par_usage.hpp b/include/cppad/local/optimize/get_par_usage.hpp
index 645397166..e7d118250 100644
--- a/include/cppad/local/optimize/get_par_usage.hpp
+++ b/include/cppad/local/optimize/get_par_usage.hpp
@@ -1,7 +1,7 @@
 # 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: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
 
 CppAD is distributed under the terms of the
              Eclipse Public License Version 2.0.
@@ -150,7 +150,7 @@ void get_par_usage(
     // -----------------------------------------------------------------------
     //
     // 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;
+    size_t atom_index=0, call_id=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
@@ -233,6 +233,7 @@ void get_par_usage(
             case Log1pOp:
             case LtvvOp:
             case MulvvOp:
+            case NegOp:
             case NevvOp:
             case PowvvOp:
             case SignOp:
@@ -326,7 +327,7 @@ void get_par_usage(
             case AFunOp:
             if( atom_state == start_atom )
             {   atom_index        = size_t(arg[0]);
-                atom_old          = size_t(arg[1]);
+                call_id           = size_t(arg[1]);
                 atom_n            = size_t(arg[2]);
                 atom_m            = size_t(arg[3]);
                 atom_j            = 0;
@@ -350,13 +351,12 @@ void get_par_usage(
                 //
                 // call atomic function for this operation
                 sweep::call_atomic_rev_depend<Base, Base>(
-                atom_index, atom_old, parameter_x, type_x, depend_x, depend_y
+                atom_index, call_id, 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 );
+                    CPPAD_ASSERT_UNKNOWN( atom_ix[j] > 0 );
                     par_usage[ atom_ix[j] ] = true;
                 }
             }
@@ -379,9 +379,9 @@ void get_par_usage(
             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;
+                type_x[atom_j] = dynamic_enum;
             else
-                    type_x[atom_j] = dynamic_enum;
+                type_x[atom_j] = constant_enum;
             ++atom_j;
             if( atom_j == atom_n )
                 atom_state = ret_atom;
@@ -433,9 +433,10 @@ void get_par_usage(
             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 );
+            call_id    = size_t( dyn_par_arg[i_arg + 1] );
+            size_t n   = size_t( dyn_par_arg[i_arg + 2] );
+            size_t m   = size_t( dyn_par_arg[i_arg + 3] );
+            CPPAD_ASSERT_UNKNOWN( n_arg == 6 + n + m );
             //
             // parameter_x, type_x
             parameter_x.resize(n);
@@ -443,7 +444,7 @@ void get_par_usage(
             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];
+                addr_t arg_j = dyn_par_arg[i_arg + 5 + j];
                 parameter_x[j] = all_par_vec[arg_j];
                 if( arg_j == 0 )
                     type_x[j] = variable_enum;
@@ -458,20 +459,19 @@ void get_par_usage(
             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] );
+                size_t i_par = size_t( dyn_par_arg[i_arg + 5 + 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<Base, Base>(
-                atom_index, atom_old, parameter_x, type_x, depend_x, depend_y
+                atom_index, call_id, 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] );
+            {   size_t i_par = size_t( dyn_par_arg[i_arg + 5 + j] );
                 par_usage[i_par] = par_usage[i_par] | depend_x[j];
             }
         }
diff --git a/include/cppad/local/optimize/optimize_run.hpp b/include/cppad/local/optimize/optimize_run.hpp
index 48aab64d4..fe3a62d5b 100644
--- a/include/cppad/local/optimize/optimize_run.hpp
+++ b/include/cppad/local/optimize/optimize_run.hpp
@@ -1,7 +1,7 @@
 # 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: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
 
 CppAD is distributed under the terms of the
              Eclipse Public License Version 2.0.
@@ -298,7 +298,6 @@ bool optimize_run(
         dyn_previous
     );
     // -----------------------------------------------------------------------
-
     // conditional expression information
     //
     // Size of the conditional expression information structure.
@@ -394,17 +393,18 @@ bool optimize_run(
         //
         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;
+            size_t call_id    = size_t( dyn_par_arg[i_arg + 1]  );
+            size_t atom_n     = size_t( dyn_par_arg[i_arg + 2]  );
+            size_t atom_m     = size_t( dyn_par_arg[i_arg + 3]  );
+            n_dyn             = size_t( dyn_par_arg[i_arg + 4]  );
+            n_arg             = 6 + 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] );
+            {   size_t j_par = size_t( dyn_par_arg[i_arg + 5 + 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 );
@@ -416,7 +416,7 @@ bool optimize_run(
             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] );
+            {   size_t j_par = size_t( dyn_par_arg[i_arg + 5 + atom_n + i] );
                 if( dyn_par_is[j_par] )
                     call_used |= par_usage[j_par];
             }
@@ -424,11 +424,12 @@ bool optimize_run(
             if( call_used )
             {   arg_vec.resize(0);
                 arg_vec.push_back( addr_t( atom_index ) );
+                arg_vec.push_back( addr_t( call_id ) );
                 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];
+                {   addr_t arg_j = dyn_par_arg[i_arg + 5 + j];
                     if( arg_j > 0 && par_usage[arg_j] )
                         arg_vec.push_back( new_par[ arg_j ] );
                     else
@@ -436,7 +437,7 @@ bool optimize_run(
                 }
                 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];
+                {   addr_t res_i = dyn_par_arg[i_arg + 5 + atom_n + i];
                     CPPAD_ASSERT_UNKNOWN( dyn_par_is[res_i] || res_i == 0 );
                     //
                     if( dyn_par_is[res_i] )
@@ -459,7 +460,7 @@ bool optimize_run(
                         }
                     }
                 }
-                arg_vec.push_back( addr_t(5 + atom_n + atom_m ) );
+                arg_vec.push_back( addr_t(6 + atom_n + atom_m ) );
                 rec->put_dyn_arg_vec( arg_vec );
             }
         }
@@ -700,6 +701,7 @@ bool optimize_run(
             case Expm1Op:
             case LogOp:
             case Log1pOp:
+            case NegOp:
             case SignOp:
             case SinOp:
             case SinhOp:
@@ -1186,7 +1188,10 @@ bool optimize_run(
             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, so we put zero here. If we
+                // put nan here, atomic reverse mode would have to use azmul.
                 new_arg[0] = zero_par_index;
+            }
             rec->PutArg(new_arg[0]);
             new_op[i_op] = addr_t( rec->num_op_rec() );
             rec->PutOp(FunapOp);
@@ -1207,8 +1212,7 @@ bool optimize_run(
                 rec->PutOp(FunavOp);
             }
             else
-            {   // This argument does not affect the result and
-                // has been optimized out so use nan in its place.
+            {   // This argument does not affect the result.
                 new_arg[0] = zero_par_index;
                 rec->PutArg(new_arg[0]);
                 new_op[i_op] = addr_t( rec->num_op_rec() );
@@ -1246,7 +1250,7 @@ bool optimize_run(
             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
+            {   // This result is not used.
                 CPPAD_ASSERT_UNKNOWN( op_usage[i_op] == usage_t(no_usage) );
                 CPPAD_ASSERT_NARG_NRES(FunrpOp, 1, 0);
                 rec->PutArg( zero_par_index );
diff --git a/include/cppad/local/parameter_op.hpp b/include/cppad/local/parameter_op.hpp
deleted file mode 100644
index f8617f0cf..000000000
--- a/include/cppad/local/parameter_op.hpp
+++ /dev/null
@@ -1,89 +0,0 @@
-# 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<Base> 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 <class Base>
-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/include/cppad/local/play/atom_op_info.hpp b/include/cppad/local/play/atom_op_info.hpp
index 264055bfa..f75171d09 100644
--- a/include/cppad/local/play/atom_op_info.hpp
+++ b/include/cppad/local/play/atom_op_info.hpp
@@ -1,7 +1,7 @@
 # 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: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
 
 CppAD is distributed under the terms of the
              Eclipse Public License Version 2.0.
@@ -29,12 +29,12 @@ 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 call_id  [out]
+is the call_id for this atomic function call.
+
 \param atom_m   [out]
 is the number of results for this user atmoic function.
 
@@ -50,7 +50,7 @@ atomic_base<Base>* atom_op_info(
     const OpCode     op         ,
     const addr_t*    op_arg     ,
     size_t&          atom_index ,
-    size_t&          atom_old   ,
+    size_t&          call_id    ,
     size_t&          atom_m     ,
     size_t&          atom_n     )
 {   atomic_base<Base>* atom_fun;
@@ -59,7 +59,7 @@ atomic_base<Base>* atom_op_info(
     CPPAD_ASSERT_NARG_NRES(op, 4, 0);
     //
     atom_index = size_t(op_arg[0]);
-    atom_old   = size_t(op_arg[1]);
+    call_id    = 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 );
diff --git a/include/cppad/local/play/player.hpp b/include/cppad/local/play/player.hpp
index b3f3386fb..8b0897e2d 100644
--- a/include/cppad/local/play/player.hpp
+++ b/include/cppad/local/play/player.hpp
@@ -1,7 +1,7 @@
 # ifndef CPPAD_LOCAL_PLAY_PLAYER_HPP
 # define CPPAD_LOCAL_PLAY_PLAYER_HPP
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
+CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
 
 CppAD is distributed under the terms of the
              Eclipse Public License Version 2.0.
@@ -321,6 +321,7 @@ public:
                 case LogOp:
                 case Log1pOp:
                 case LtvpOp:
+                case NegOp:
                 case PowvpOp:
                 case SignOp:
                 case SinOp:
@@ -461,16 +462,16 @@ public:
             // 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;
+            {   size_t n = size_t( dyn_par_arg_[i_arg + 2] );
+                size_t m = size_t( dyn_par_arg_[i_arg + 3] );
+                n_arg    = 6 + n + m;
                 CPPAD_ASSERT_UNKNOWN(
-                    n_arg == size_t( dyn_par_arg_[i_arg + 4 + n + m] )
+                    n_arg == size_t( dyn_par_arg_[i_arg + 5 + n + m] )
                 );
-                for(size_t i = 4; i < n - 1; ++i)
+                for(size_t i = 5; 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)
+                for(size_t i = 5+n; i < 5+n+m; ++i)
                 {   addr_t j_par = dyn_par_arg_[i_arg + i];
                     CPPAD_ASSERT_UNKNOWN( (j_par == 0) || (j_par >= i_par) );
                 }
@@ -736,7 +737,7 @@ public:
 
     /// 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.
+    /// In user api as f.size_op_seq(); see the file fun_property.omh.
     size_t size_op_seq(void) const
     {   // check assumptions made by ad_fun<Base>::size_op_seq()
         CPPAD_ASSERT_UNKNOWN( op_vec_.size() == num_op_rec() );
@@ -756,7 +757,7 @@ public:
         ;
     }
     /// A measure of amount of memory used for random access routine
-    /// In user api as f.size_random(); see the file seq_property.omh.
+    /// In user api as f.size_random(); see the file fun_property.omh.
     size_t size_random(void) const
     {
 # ifndef NDEBUG
diff --git a/include/cppad/local/record/put_dyn_atomic.hpp b/include/cppad/local/record/put_dyn_atomic.hpp
index 51b0f0a17..f68e9b0b0 100644
--- a/include/cppad/local/record/put_dyn_atomic.hpp
+++ b/include/cppad/local/record/put_dyn_atomic.hpp
@@ -1,7 +1,7 @@
 # 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: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
 
 CppAD is distributed under the terms of the
              Eclipse Public License Version 2.0.
@@ -27,7 +27,7 @@ $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%
+    %tape_id%, %atomic_index%, %call_id%, %type_x%, %type_y%, %ax%, %ay%
 )%$$
 
 $head Prototype$$
@@ -43,6 +43,9 @@ $codei%AD<%Base%>.tape_ptr()%$$ is null.
 $head atomic_index$$
 is the $cref atomic_index$$ for this atomic function.
 
+$head call_id$$
+is the $cref/call_id/atomic_four_call/call_id/$$ for this atomic function.
+
 $head type_x$$
 is the $cref ad_type_enum$$ for each of the atomic function arguments.
 
@@ -85,6 +88,7 @@ template <class Base> template <class VectorAD>
 void recorder<Base>::put_dyn_atomic(
     tape_id_t                   tape_id      ,
     size_t                      atomic_index ,
+    size_t                      call_id      ,
     const vector<ad_type_enum>& type_x       ,
     const vector<ad_type_enum>& type_y       ,
     const VectorAD&             ax           ,
@@ -104,14 +108,16 @@ void recorder<Base>::put_dyn_atomic(
     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
+    dyn_par_arg_.push_back( addr_t(call_id ));      // arg[1] = call_id
+    dyn_par_arg_.push_back( addr_t( n ) );          // arg[2] = n
+    dyn_par_arg_.push_back( addr_t( m ) );          // arg[3] = m
+    dyn_par_arg_.push_back( addr_t( num_dyn ) );    // arg[4] = num_dyn
+    // arg[5 + 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:
+        {   case identical_zero_enum:
+            case constant_enum:
             arg = put_con_par( ax[j].value_ );
             break;
 
@@ -128,14 +134,15 @@ void recorder<Base>::put_dyn_atomic(
             arg = 0;
             CPPAD_ASSERT_UNKNOWN( false );
         }
-        dyn_par_arg_.push_back( arg ); // arg[4 + j]
+        dyn_par_arg_.push_back( arg );              // arg[5 + j]
     }
-    // arg[4 + n + i] for i = 0, ... , m-1
+    // arg[5 + 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:
+        {   case identical_zero_enum:
+            case constant_enum:
             arg = 0; // phantom parameter index
             break;
 
@@ -160,9 +167,9 @@ void recorder<Base>::put_dyn_atomic(
             arg = 0;
             CPPAD_ASSERT_UNKNOWN( false );
         }
-        dyn_par_arg_.push_back( arg ); // arg[4 + n + i]
+        dyn_par_arg_.push_back( arg );              // arg[5 + n + i]
     }
-    dyn_par_arg_.push_back( addr_t(5 + n + m) ); // arg[4 + n + m]
+    dyn_par_arg_.push_back( addr_t(6 + n + m) );    // arg[5 + n + m]
 }
 
 } } // END_CPPAD_LOCAL_NAMESPACE
diff --git a/include/cppad/local/record/put_var_atomic.hpp b/include/cppad/local/record/put_var_atomic.hpp
index ea4f0a8fd..762fe648d 100644
--- a/include/cppad/local/record/put_var_atomic.hpp
+++ b/include/cppad/local/record/put_var_atomic.hpp
@@ -1,7 +1,7 @@
 # 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: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
 
 CppAD is distributed under the terms of the
              Eclipse Public License Version 2.0.
@@ -27,7 +27,7 @@ $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%
+    %tape_id%, %atomic_index%, %call_id%, %type_x%, %type_y%, %ax%, %ay%
 )%$$
 
 $head Prototype$$
@@ -43,11 +43,19 @@ $codei%AD<%Base%>.tape_ptr()%$$ is null.
 $head atomic_index$$
 is the $cref atomic_index$$ for this atomic function.
 
+$head call_id$$
+Is the $cref/call_id/atomic_four_call/call_id/$$ for this
+atomic function call.
+
 $head type_x$$
 is the $cref ad_type_enum$$ for each of the atomic function arguments.
+This is one of the rare cases where constants can have type
+$code identical_zero_enum$$.
 
 $head type_y$$
 is the $code ad_type_enum$$ for each of the atomic function results.
+This is one of the rare cases where constants can have type
+$code identical_zero_enum$$.
 
 $head ax$$
 is the atomic function argument vector for this call.
@@ -83,6 +91,7 @@ template <class Base> template <class VectorAD>
 void recorder<Base>::put_var_atomic(
     tape_id_t                   tape_id      ,
     size_t                      atomic_index ,
+    size_t                      call_id      ,
     const vector<ad_type_enum>& type_x       ,
     const vector<ad_type_enum>& type_y       ,
     const VectorAD&             ax           ,
@@ -98,10 +107,9 @@ void recorder<Base>::put_var_atomic(
     );
     // 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));
+    PutArg(addr_t(atomic_index), addr_t(call_id), addr_t(n), addr_t(m));
     PutOp(local::AFunOp);
 
     // Now put n operators, one for each element of argument vector
@@ -116,7 +124,7 @@ void recorder<Base>::put_var_atomic(
         else
         {   // information for an argument that is parameter
             addr_t par = ax[j].taddr_;
-            if( type_x[j] == constant_enum )
+            if( type_x[j] <= constant_enum )
                 par = put_con_par(ax[j].value_);
             PutArg(par);
             PutOp(local::FunapOp);
@@ -134,7 +142,7 @@ void recorder<Base>::put_var_atomic(
         }
         else
         {   addr_t par = ay[i].taddr_;
-            if( type_y[i] == constant_enum )
+            if( type_y[i] <= constant_enum )
                 par = put_con_par( ay[i].value_ );
             PutArg(par);
             PutOp(local::FunrpOp);
@@ -142,7 +150,7 @@ void recorder<Base>::put_var_atomic(
     }
 
     // Put a duplicate AFunOp at end of AFunOp sequence
-    PutArg(addr_t(atomic_index), old_id, addr_t(n), addr_t(m));
+    PutArg(addr_t(atomic_index), addr_t(call_id), addr_t(n), addr_t(m));
     PutOp(local::AFunOp);
 }
 
diff --git a/include/cppad/local/record/recorder.hpp b/include/cppad/local/record/recorder.hpp
index 97c01bc85..24a6cf104 100644
--- a/include/cppad/local/record/recorder.hpp
+++ b/include/cppad/local/record/recorder.hpp
@@ -1,7 +1,7 @@
 # ifndef CPPAD_LOCAL_RECORD_RECORDER_HPP
 # define CPPAD_LOCAL_RECORD_RECORDER_HPP
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
+CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
 
 CppAD is distributed under the terms of the
              Eclipse Public License Version 2.0.
@@ -176,6 +176,7 @@ public:
     void put_dyn_atomic(
         tape_id_t                   tape_id    ,
         size_t                      atom_index ,
+        size_t                      call_id    ,
         const vector<ad_type_enum>& type_x     ,
         const vector<ad_type_enum>& type_y     ,
         const VectorAD&             ax         ,
@@ -187,6 +188,7 @@ public:
     void put_var_atomic(
         tape_id_t                   tape_id    ,
         size_t                      atom_index ,
+        size_t                      call_id    ,
         const vector<ad_type_enum>& type_x     ,
         const vector<ad_type_enum>& type_y     ,
         const VectorAD&             ax         ,
diff --git a/include/cppad/local/sweep/call_atomic.hpp b/include/cppad/local/sweep/call_atomic.hpp
index 39f9a8e03..ca1a8b455 100644
--- a/include/cppad/local/sweep/call_atomic.hpp
+++ b/include/cppad/local/sweep/call_atomic.hpp
@@ -1,7 +1,7 @@
 # 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: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
 
 CppAD is distributed under the terms of the
              Eclipse Public License Version 2.0.
@@ -13,63 +13,83 @@ in the Eclipse Public License, Version 2.0 are satisfied:
 ---------------------------------------------------------------------------- */
 
 # include <cppad/local/atomic_index.hpp>
-# include <cppad/core/atomic/atomic_two.hpp>
-# include <cppad/core/atomic/atomic_three.hpp>
+# include <cppad/core/atomic/two/atomic.hpp>
+# include <cppad/core/atomic/three/atomic.hpp>
+# include <cppad/core/atomic/four/atomic.hpp>
 
 // 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.
+/*
+$begin atomic_forward_callback$$
+$spell
+    Taylor
+    afun
+    CppAD
+$$
 
-\tparam Base
-Is the type corresponding to the Taylor coefficients.
+$section Forward Mode Callback to Atomic Functions$$
 
-\tparam RecBase
-Is the type corresponding to this atomic function.
+$head Prototype$$
+$srcthisfile%0%// BEGIN_FORWARD%// END_FORWARD%1%$$
 
-\param parameter_x [in]
+$head Base$$
+Is the base type corresponding to the atomic function call.
+
+$head RecBase$$
+Is the base type corresponding to this atomic function call.
+
+$head vector$$
+is the CppAD::vector template class.
+
+$head parameter_x$$
 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.
+$head type_x$$
+what is the type, in the call, for each component of x.
 
-\param need_y
+$head need_y$$
 specifies which components of taylor_y are necessary.
 
-\param order_low [in]
-lowerest order for this forward mode calculation.
+$head select_y$$
+specifies which components of taylor_x are necessary.
 
-\param order_up [in]
+$head order_low$$
+lowest order for this forward mode calculation.
+
+$head order_up$$
 highest order for this forward mode calculation.
 
-\param atom_index [in]
+$head atom_index$$
 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.
+$head call_id$$
+see the atomic_four $cref/call_id/atomic_four_call/call_id/$$ and
+the atomic_one $cref/id/atomic_one/id/$$.
 
-\param taylor_x [in]
+$head taylor_x$$
 Taylor coefficients corresponding to x.
 
-\param taylor_y [out]
+$head taylor_y$$
 Taylor coefficient corresponding to y.
+
+$end
 */
+// BEGIN_FORWARD
 template <class Base, class RecBase>
 void call_atomic_forward(
     const vector<Base>&          parameter_x ,
     const vector<ad_type_enum>&  type_x      ,
     size_t                       need_y      ,
+    const vector<bool>&          select_y    ,
     size_t                       order_low   ,
     size_t                       order_up    ,
     size_t                       atom_index  ,
-    size_t                       atom_old    ,
+    size_t                       call_id     ,
     const vector<Base>&          taylor_x    ,
     vector<Base>&                taylor_y    )
+// END_FORWARD
 {   CPPAD_ASSERT_UNKNOWN( 0 < atom_index );
     bool         set_null = false;
     size_t       type     = 0;          // set to avoid warning
@@ -83,13 +103,13 @@ void call_atomic_forward(
         if( type == 2 )
         {   atomic_base<RecBase>* afun =
                 reinterpret_cast< atomic_base<RecBase>* >(v_ptr);
-            afun->set_old(atom_old);
+            afun->set_old(call_id);
             vector<ad_type_enum> empty;
             ok = afun->forward(
                 order_low, order_up, empty, empty, taylor_x, taylor_y
             );
         }
-        else
+        else if( type == 3 )
         {   CPPAD_ASSERT_UNKNOWN( type == 3 );
             atomic_three<RecBase>* afun =
                 reinterpret_cast< atomic_three<RecBase>* >(v_ptr);
@@ -98,6 +118,14 @@ void call_atomic_forward(
                 need_y, order_low, order_up, taylor_x, taylor_y
             );
         }
+        else
+        {   CPPAD_ASSERT_UNKNOWN( type == 4 );
+            atomic_four<RecBase>* afun =
+                reinterpret_cast< atomic_four<RecBase>* >(v_ptr);
+            ok = afun->forward(
+                call_id, select_y, order_low, order_up, taylor_x, taylor_y
+            );
+        }
     }
     if( ! ok )
     {   // now take the extra time to copy the name
@@ -105,7 +133,7 @@ void call_atomic_forward(
         local::atomic_index<RecBase>(set_null, atom_index, type, &name, v_ptr);
         std::string msg = name;
         if( v_ptr == nullptr )
-            msg += ": this atomic_three function has been deleted";
+            msg += ": this atomic function has been deleted";
         else
             msg += ": atomic forward returned false";
         CPPAD_ASSERT_KNOWN(false, msg.c_str() );
@@ -115,12 +143,12 @@ void call_atomic_forward(
     {   atomic_base<RecBase>* afun =
             reinterpret_cast< atomic_base<RecBase>* >(v_ptr);
         vector<ad_type_enum> empty;
-        afun->set_old(atom_old);
+        afun->set_old(call_id);
         afun->forward(
             order_low, order_up, empty, empty, taylor_x, taylor_y
         );
     }
-    else
+    else if( type == 3 )
     {   atomic_three<RecBase>* afun =
             reinterpret_cast< atomic_three<RecBase>* >(v_ptr);
         afun->forward(
@@ -128,57 +156,86 @@ void call_atomic_forward(
             need_y, order_low, order_up, taylor_x, taylor_y
         );
     }
+    else
+    {   atomic_four<RecBase>* afun =
+            reinterpret_cast< atomic_four<RecBase>* >(v_ptr);
+        afun->forward(
+            call_id, select_y, order_low, order_up, taylor_x, taylor_y
+        );
+    }
 # endif
 }
 // ----------------------------------------------------------------------------
-/*!
-Reverse mode callback to atomic functions.
+/*
+$begin atomic_reverse_callback$$
+$spell
+    CppAD
+    Taylor
+    Jacobian
+$$
 
-\tparam Base
-Is the type corresponding to the Taylor coefficients.
+$section Reverse Mode callback to Atomic Functions$$
 
-\tparam RecBase
-Is the type corresponding to this atomic function.
+$head Prototype$$
+$srcthisfile%0%// BEGIN_REVERSE%// END_REVERSE%1%$$
 
-\param parameter_x [in]
+$head Base$$
+Is the base type corresponding to the atomic function call.
+
+$head RecBase$$
+Is the base type corresponding to this atomic function call.
+
+$head vector$$
+is the CppAD::vector template class.
+
+$head parameter_x$$
 value of the parameter arguments to the atomic function
 (other arguments have the value nan).
 
-\param type_x [in]
+$head type_x$$
 type for each component of x (not used by atomic_two interface).
 
-\param order_up [in]
+$head select_x$$
+specifies which components of partial_x are necessary.
+
+$head order_up$$
 highest order for this reverse mode calculation.
 
-\param atom_index [in]
+$head atom_index$$
 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.
+$head call_id$$
+see the atomic_four $cref/call_id/atomic_four_call/call_id/$$ and
+the atomic_one $cref/id/atomic_one/id/$$.
 
-\param taylor_x [in]
+$head taylor_x$$
 Taylor coefficients corresponding to x.
 
-\param taylor_y [in]
+$head taylor_y$$
 Taylor coefficient corresponding to y.
 
-\param partial_x [out]
+$head partial_x$$
 Partials w.r.t the x Taylor coefficients.
 
-\param partial_y [in]
+$head partial_y$$
 Partials w.r.t the y Taylor coefficients.
+
+$end
 */
+// BEGIN_REVERSE
 template <class Base, class RecBase>
 void call_atomic_reverse(
     const vector<Base>&          parameter_x ,
     const vector<ad_type_enum>&  type_x      ,
+    const vector<bool>&          select_x    ,
     size_t                       order_up    ,
     size_t                       atom_index  ,
-    size_t                       atom_old    ,
+    size_t                       call_id     ,
     const vector<Base>&          taylor_x    ,
     const vector<Base>&          taylor_y    ,
     vector<Base>&                partial_x   ,
     const vector<Base>&          partial_y   )
+// END_REVERSE
 {   CPPAD_ASSERT_UNKNOWN( 0 < atom_index );
     bool         set_null = false;
     size_t       type     = 0;          // set to avoid warning
@@ -192,20 +249,28 @@ void call_atomic_reverse(
         if( type == 2 )
         {   atomic_base<RecBase>* afun =
                 reinterpret_cast< atomic_base<RecBase>* >(v_ptr);
-            afun->set_old(atom_old);
+            afun->set_old(call_id);
             ok = afun->reverse(
                 order_up, taylor_x, taylor_y, partial_x, partial_y
             );
         }
-        else
-        {   CPPAD_ASSERT_UNKNOWN( type == 3 );
-            atomic_three<RecBase>* afun =
+        else if( type == 3 )
+        {   atomic_three<RecBase>* afun =
                 reinterpret_cast< atomic_three<RecBase>* >(v_ptr);
             ok = afun->reverse(
                 parameter_x, type_x,
                 order_up, taylor_x, taylor_y, partial_x, partial_y
             );
         }
+        else
+        {   CPPAD_ASSERT_UNKNOWN( type == 4 );
+            atomic_four<RecBase>* afun =
+                reinterpret_cast< atomic_four<RecBase>* >(v_ptr);
+            ok = afun->reverse(
+                call_id, select_x,
+                order_up, taylor_x, taylor_y, partial_x, partial_y
+            );
+        }
     }
     if( ! ok )
     {   // now take the extra time to copy the name
@@ -213,7 +278,7 @@ void call_atomic_reverse(
         local::atomic_index<RecBase>(set_null, atom_index, type, &name, v_ptr);
         std::string msg = name;
         if( v_ptr == nullptr )
-            msg += ": this atomic_three function has been deleted";
+            msg += ": this atomic function has been deleted";
         else
             msg += ": atomic reverse returned false";
         CPPAD_ASSERT_KNOWN(false, msg.c_str() );
@@ -222,12 +287,12 @@ void call_atomic_reverse(
     if( type == 2 )
     {   atomic_base<RecBase>* afun =
             reinterpret_cast< atomic_base<RecBase>* >(v_ptr);
-        afun->set_old(atom_old);
+        afun->set_old(call_id);
         afun->reverse(
             order_up, taylor_x, taylor_y, partial_x, partial_y
         );
     }
-    else
+    else if( type == 3 )
     {   atomic_three<RecBase>* afun =
             reinterpret_cast< atomic_three<RecBase>* >(v_ptr);
         afun->reverse(
@@ -235,60 +300,85 @@ void call_atomic_reverse(
             order_up, taylor_x, taylor_y, partial_x, partial_y
         );
     }
+    else
+    {   atomic_four<RecBase>* afun =
+            reinterpret_cast< atomic_four<RecBase>* >(v_ptr);
+        afun->reverse(
+            call_id, select_x,
+            order_up, taylor_x, taylor_y, partial_x, partial_y
+        );
+    }
 # endif
 }
 // ----------------------------------------------------------------------------
-/*!
-Forward Jacobian sparsity callback to atomic functions.
+/*
+$begin atomic_for_jac_sparsity_callback$$
+$spell
+    CppAD
+    setvec
+    var
+    Jacobian
+$$
 
-\tparam Base
-is the type corresponding to parameter_x
-and to this atomic function.
+$section Forward Jacobian Sparsity Callback to Atomic Functions$$
 
-\tparam InternalSparsity
+$head Prototype$$
+$srcthisfile%0%// BEGIN_FOR_JAC_SPARSITY%// END_FOR_JAC_SPARSITY%1%$$
+
+$head Base$$
+Is the base type corresponding to the atomic function call.
+
+$head vector$$
+is the CppAD::vector template class.
+
+$head InternalSparsity$$
 is the internal type used to represent sparsity; i.e.,
 sparse::pack_setvec or sparse::list_setvec.
 
-\param atom_index [in]
+$head atom_index$$
 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.
+$head call_id$$
+see the atomic_four $cref/call_id/atomic_four_call/call_id/$$ and
+the atomic_one $cref/id/atomic_one/id/$$.
 
-\param dependency [in]
+$head dependency$$
 is this a dependency or sparsity calculation.
 
-\param parameter_x [in]
+$head parameter_x$$
 value of the parameter arguments to the atomic function
 (other arguments have the value nan).
 
-\param type_x [in]
+$head type_x$$
 type for each component of x (not used by atomic_two interface).
 
-\param x_index [in]
+$head x_index$$
 is a mapping from the index of an atomic function argument
 to the corresponding variable on the tape.
 
-\param y_index [in]
+$head y_index$$
 is a mapping from the index of an atomic function result
 to the corresponding variable on the tape.
 
-\param var_sparsity [in/out]
+$head 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 j-th result for this atomic function.
+is the sparsity for the i-th result for this atomic function.
+$end
 */
+// BEGIN_FOR_JAC_SPARSITY
 template <class Base, class RecBase, class InternalSparsity>
 void call_atomic_for_jac_sparsity(
     size_t                       atom_index    ,
-    size_t                       atom_old      ,
+    size_t                       call_id       ,
     bool                         dependency    ,
     const vector<Base>&          parameter_x   ,
     const vector<ad_type_enum>&  type_x        ,
     const pod_vector<size_t>&    x_index       ,
     const pod_vector<size_t>&    y_index       ,
     InternalSparsity&            var_sparsity  )
+// END_FOR_JAC_SPARSITY
 {   CPPAD_ASSERT_UNKNOWN( 0 < atom_index );
     bool         set_null = false;
     size_t       type     = 0;          // set to avoid warning
@@ -302,19 +392,26 @@ void call_atomic_for_jac_sparsity(
         if( type == 2 )
         {   atomic_base<RecBase>* afun =
                 reinterpret_cast< atomic_base<RecBase>* >(v_ptr);
-            afun->set_old(atom_old);
+            afun->set_old(call_id);
             ok = afun->for_sparse_jac(
                 parameter_x, x_index, y_index, var_sparsity
             );
         }
-        else
-        {   CPPAD_ASSERT_UNKNOWN( type == 3 );
-            atomic_three<RecBase>* afun =
+        else if( type == 3 )
+        {   atomic_three<RecBase>* afun =
                 reinterpret_cast< atomic_three<RecBase>* >(v_ptr);
             ok = afun->for_jac_sparsity(
             dependency, parameter_x, type_x, x_index, y_index, var_sparsity
             );
         }
+        else
+        {   CPPAD_ASSERT_UNKNOWN( type == 4 );
+            atomic_four<RecBase>* afun =
+                reinterpret_cast< atomic_four<RecBase>* >(v_ptr);
+            ok = afun->for_jac_sparsity(
+                dependency, call_id, x_index, y_index, var_sparsity
+            );
+        }
     }
     if( ! ok )
     {   // now take the extra time to copy the name
@@ -324,7 +421,7 @@ void call_atomic_for_jac_sparsity(
         );
         std::string msg = name;
         if( v_ptr == nullptr )
-            msg += ": this atomic_three function has been deleted";
+            msg += ": this atomic function has been deleted";
         else
             msg += ": atomic jac_sparsity returned false";
         CPPAD_ASSERT_KNOWN(false, msg.c_str() );
@@ -333,73 +430,94 @@ void call_atomic_for_jac_sparsity(
    if( type == 2 )
     {   atomic_base<RecBase>* afun =
             reinterpret_cast< atomic_base<RecBase>* >(v_ptr);
-        afun->set_old(atom_old);
+        afun->set_old(call_id);
         afun->for_sparse_jac(
             parameter_x, x_index, y_index, var_sparsity
         );
     }
-    else
-    {   CPPAD_ASSERT_UNKNOWN( type == 3 );
-        atomic_three<RecBase>* afun =
+    else if( type == 3 )
+    {   atomic_three<RecBase>* afun =
             reinterpret_cast< atomic_three<RecBase>* >(v_ptr);
         afun->for_jac_sparsity(
             dependency, parameter_x, type_x, x_index, y_index, var_sparsity
         );
     }
+    else
+    {   atomic_four<RecBase>* afun =
+            reinterpret_cast< atomic_four<RecBase>* >(v_ptr);
+        afun->for_jac_sparsity(
+            dependency, call_id, x_index, y_index, var_sparsity
+        );
+    }
 # endif
 }
 // ----------------------------------------------------------------------------
-/*!
-Reverse Jacobian sparsity callback to atomic functions.
+/*
+$begin atomic_rev_jac_sparsity_callback$$
+$spell
+    Jacobian
+    setvec
+    var
+$$
+
+$section Reverse Jacobian sparsity Callback to Atomic Functions$$
 
-\tparam Base
+$head Prototype$$
+$srcthisfile%0%// BEGIN_REV_JAC_SPARSITY%// END_REV_JAC_SPARSITY%1%$$
+
+$head Base$$
 is the type corresponding to parameter_x
 and to this atomic function.
 
-\tparam InternalSparsity
+$head InternalSparsity$$
 is the internal type used to represent sparsity; i.e.,
 sparse::pack_setvec or sparse::list_setvec.
 
-\param atom_index [in]
+$head atom_index$$
 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.
+$head call_id$$
+see the atomic_four $cref/call_id/atomic_four_call/call_id/$$ and
+the atomic_one $cref/id/atomic_one/id/$$.
 
-\param dependency [in]
+$head dependency$$
 is this a dependency or sparsity calculation.
 
-\param parameter_x [in]
+$head parameter_x$$
 value of the parameter arguments to the atomic function
 (other arguments have the value nan).
 
-\param type_x [in]
+$head type_x$$
 type for each component of x (not used by atomic_two interface).
 
-\param x_index [in]
+$head x_index$$
 is a mapping from the index of an atomic function argument
 to the corresponding variable on the tape.
 
-\param y_index [in]
+$head y_index$$
 is a mapping from the index of an atomic function result
 to the corresponding variable on the tape.
 
-\param var_sparsity [in/out]
+$head 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.
+
+$end
 */
+// BEGIN_REV_JAC_SPARSITY
 template <class Base, class RecBase, class InternalSparsity>
 void call_atomic_rev_jac_sparsity(
     size_t                       atom_index    ,
-    size_t                       atom_old      ,
+    size_t                       call_id       ,
     bool                         dependency    ,
     const vector<Base>&          parameter_x   ,
     const vector<ad_type_enum>&  type_x        ,
     const pod_vector<size_t>&    x_index       ,
     const pod_vector<size_t>&    y_index       ,
     InternalSparsity&            var_sparsity  )
+// END_REV_JAC_SPARSITY
 {   CPPAD_ASSERT_UNKNOWN( 0 < atom_index );
     bool         set_null = false;
     size_t       type     = 0;          // set to avoid warning
@@ -413,19 +531,26 @@ void call_atomic_rev_jac_sparsity(
         if( type == 2 )
         {   atomic_base<RecBase>* afun =
                 reinterpret_cast< atomic_base<RecBase>* >(v_ptr);
-            afun->set_old(atom_old);
+            afun->set_old(call_id);
             ok = afun->rev_sparse_jac(
                 parameter_x, x_index, y_index, var_sparsity
             );
         }
-        else
-        {   CPPAD_ASSERT_UNKNOWN( type == 3 );
-            atomic_three<RecBase>* afun =
+        else if( type == 3 )
+        {   atomic_three<RecBase>* afun =
                 reinterpret_cast< atomic_three<RecBase>* >(v_ptr);
             ok = afun->rev_jac_sparsity(
             dependency, parameter_x, type_x, x_index, y_index, var_sparsity
             );
         }
+        else
+        {   CPPAD_ASSERT_UNKNOWN( type == 4 );
+            atomic_four<RecBase>* afun =
+                reinterpret_cast< atomic_four<RecBase>* >(v_ptr);
+            ok = afun->rev_jac_sparsity(
+            dependency, call_id, x_index, y_index, var_sparsity
+            );
+        }
     }
     if( ! ok )
     {   // now take the extra time to copy the name
@@ -435,7 +560,7 @@ void call_atomic_rev_jac_sparsity(
         );
         std::string msg = name;
         if( v_ptr == nullptr )
-            msg += ": this atomic_three function has been deleted";
+            msg += ": this atomic function has been deleted";
         else
             msg += ": atomic jac_sparsity returned false";
         CPPAD_ASSERT_KNOWN(false, msg.c_str() );
@@ -444,24 +569,30 @@ void call_atomic_rev_jac_sparsity(
     if( type == 2 )
     {   atomic_base<RecBase>* afun =
             reinterpret_cast< atomic_base<RecBase>* >(v_ptr);
-        afun->set_old(atom_old);
+        afun->set_old(call_id);
         afun->rev_sparse_jac(
             parameter_x, x_index, y_index, var_sparsity
         );
     }
-    else
-    {   CPPAD_ASSERT_UNKNOWN( type == 3 );
-        atomic_three<RecBase>* afun =
+    else if( type == 3 )
+    {   atomic_three<RecBase>* afun =
             reinterpret_cast< atomic_three<RecBase>* >(v_ptr);
         afun->rev_jac_sparsity(
             dependency, parameter_x, type_x, x_index, y_index, var_sparsity
         );
     }
+    else
+    {   atomic_four<RecBase>* afun =
+            reinterpret_cast< atomic_four<RecBase>* >(v_ptr);
+        afun->rev_jac_sparsity(
+            dependency, call_id, x_index, y_index, var_sparsity
+        );
+    }
 # endif
 }
 // ----------------------------------------------------------------------------
 /*
-$begin call_atomic_for_hes_sparsiy$$
+$begin atomic_for_hes_sparsiy_callback$$
 $spell
     hes
     np
@@ -472,26 +603,10 @@ $spell
     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%
-)%$$
+$section Forward Hessian Sparsity Callback to Atomic Functions$$
 
 $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)$$.
+$srcthisfile%0%// BEGIN_FOR_HES_SPARSITY%// END_FOR_HES_SPARSITY%1%$$
 
 $head Base$$
 is the type corresponding to $icode parameter_x$$
@@ -504,8 +619,9 @@ $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 call_id$$
+see the atomic_four $cref/call_id/atomic_four_call/call_id/$$ and
+the atomic_one $cref/id/atomic_one/id/$$.
 
 $head parameter_x$$
 value of the parameter arguments to the atomic function
@@ -567,11 +683,11 @@ after including the function $latex y = f(x)$$.
 
 $end
 */
-// BEGIN_call_atomic_for_hes_sparsity
+// BEGIN_FOR_HES_SPARSITY
 template <class Base, class RecBase, class InternalSparsity>
 void call_atomic_for_hes_sparsity(
     size_t                       atom_index        ,
-    size_t                       atom_old          ,
+    size_t                       call_id           ,
     const vector<Base>&          parameter_x       ,
     const vector<ad_type_enum>&  type_x            ,
     const pod_vector<size_t>&    x_index           ,
@@ -580,7 +696,7 @@ void call_atomic_for_hes_sparsity(
     size_t                       numvar            ,
     const InternalSparsity&      rev_jac_sparsity  ,
     InternalSparsity&            for_sparsity      )
-// END_call_atomic_for_hes_sparsity
+// END_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 );
@@ -597,7 +713,7 @@ void call_atomic_for_hes_sparsity(
         if( type == 2 )
         {   atomic_base<RecBase>* afun =
                 reinterpret_cast< atomic_base<RecBase>* >(v_ptr);
-            afun->set_old(atom_old);
+            afun->set_old(call_id);
             ok = afun->for_sparse_hes(
                 parameter_x,
                 x_index,
@@ -608,9 +724,8 @@ void call_atomic_for_hes_sparsity(
                 for_sparsity
             );
         }
-        else
-        {   CPPAD_ASSERT_UNKNOWN( type == 3 );
-            atomic_three<RecBase>* afun =
+        else if( type == 3 )
+        {   atomic_three<RecBase>* afun =
                 reinterpret_cast< atomic_three<RecBase>* >(v_ptr);
             ok = afun->for_hes_sparsity(
                 parameter_x,
@@ -623,6 +738,20 @@ void call_atomic_for_hes_sparsity(
                 for_sparsity
             );
         }
+        else
+        {   CPPAD_ASSERT_UNKNOWN( type == 4 );
+            atomic_four<RecBase>* afun =
+                reinterpret_cast< atomic_four<RecBase>* >(v_ptr);
+            ok = afun->for_hes_sparsity(
+                call_id,
+                x_index,
+                y_index,
+                np1,
+                numvar,
+                rev_jac_sparsity,
+                for_sparsity
+            );
+        }
     }
     if( ! ok )
     {   // now take the extra time to copy the name
@@ -641,7 +770,7 @@ void call_atomic_for_hes_sparsity(
     if( type == 2 )
     {   atomic_base<RecBase>* afun =
             reinterpret_cast< atomic_base<RecBase>* >(v_ptr);
-        afun->set_old(atom_old);
+        afun->set_old(call_id);
         afun->for_sparse_hes(
             parameter_x,
             x_index,
@@ -652,9 +781,8 @@ void call_atomic_for_hes_sparsity(
             for_sparsity
         );
     }
-    else
-    {   CPPAD_ASSERT_UNKNOWN( type == 3 );
-        atomic_three<RecBase>* afun =
+    else if( type == 3 )
+    {   atomic_three<RecBase>* afun =
             reinterpret_cast< atomic_three<RecBase>* >(v_ptr);
         afun->for_hes_sparsity(
             parameter_x,
@@ -667,65 +795,90 @@ void call_atomic_for_hes_sparsity(
             for_sparsity
         );
     }
+    else
+    {   atomic_four<RecBase>* afun =
+            reinterpret_cast< atomic_four<RecBase>* >(v_ptr);
+        afun->for_hes_sparsity(
+            call_id,
+            x_index,
+            y_index,
+            np1,
+            numvar,
+            rev_jac_sparsity,
+            for_sparsity
+        );
+    }
 # endif
 }
 // ----------------------------------------------------------------------------
-/*!
-Reverse Hessian sparsity callback to atomic functions.
+/*
+$begin atomic_rev_hes_sparsity_callback$$
+$spell
+    setvec
+    jac
+    Jacobian
+    hes
+$$
+
+$section Reverse Hessian Sparsity Callback to Atomic Functions$$
 
-\tparam Base
+$head Prototype$$
+$srcthisfile%0%// BEGIN_REV_HES_SPARSITY%// END_REV_HES_SPARSITY%1%$$
+
+$head Base$$
 is the type corresponding to parameter_x
 and to this atomic function.
 
-\tparam InternalSparsity
+$head 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.
+$head call_id$$
+see the atomic_four $cref/call_id/atomic_four_call/call_id/$$ and
+the atomic_one $cref/id/atomic_one/id/$$.
 
-\param parameter_x [in]
+$head parameter_x$$
 value of the parameter arguments to the atomic function
 (other arguments have the value nan).
 
-\param type_x [in]
+$head type_x$$
 type for each component of x (not used by atomic_two interface).
 
-\param x_index [in]
+$head x_index$$
 is a mapping from the index of an atomic function argument
 to the corresponding variable on the tape.
 
-\param y_index [in]
+$head y_index$$
 is a mapping from the index of an atomic function result
 to the corresponding variable on the tape.
 
-\param for_jac_sparsity
+$head 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
+$head 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)
+if the function (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].
+true any of the y_index variables are flagged depend on x_index[j].
 Otherwise, rev_jac_flag[ x_index[j] ] is not modified.
 
-\param rev_hes_sparsity
+$head 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].
+with one of the partials with respect 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].
+the atomic function with one of the partials w.r.t. x_index[j].
+
+$end
 */
+// BEGIN_REV_HES_SPARSITY
 template <class Base, class RecBase, class InternalSparsity>
 void call_atomic_rev_hes_sparsity(
     size_t                       atom_index        ,
-    size_t                       atom_old          ,
+    size_t                       call_id           ,
     const vector<Base>&          parameter_x       ,
     const vector<ad_type_enum>&  type_x            ,
     const pod_vector<size_t>&    x_index           ,
@@ -733,6 +886,7 @@ void call_atomic_rev_hes_sparsity(
     const InternalSparsity&      for_jac_sparsity  ,
     bool*                        rev_jac_flag      ,
     InternalSparsity&            rev_hes_sparsity  )
+// END_REV_HES_SPARSITY
 {   CPPAD_ASSERT_UNKNOWN( 0 < atom_index );
     bool         set_null = false;
     size_t       type     = 0;          // set to avoid warning
@@ -746,7 +900,7 @@ void call_atomic_rev_hes_sparsity(
         if( type == 2 )
         {   atomic_base<RecBase>* afun =
                 reinterpret_cast< atomic_base<RecBase>* >(v_ptr);
-            afun->set_old(atom_old);
+            afun->set_old(call_id);
             ok = afun->rev_sparse_hes(
                 parameter_x,
                 x_index,
@@ -756,9 +910,8 @@ void call_atomic_rev_hes_sparsity(
                 rev_hes_sparsity
             );
         }
-        else
-        {   CPPAD_ASSERT_UNKNOWN( type == 3 );
-            atomic_three<RecBase>* afun =
+        else if( type == 3 )
+        {   atomic_three<RecBase>* afun =
                 reinterpret_cast< atomic_three<RecBase>* >(v_ptr);
             ok = afun->rev_hes_sparsity(
                 parameter_x,
@@ -770,6 +923,19 @@ void call_atomic_rev_hes_sparsity(
                 rev_hes_sparsity
             );
         }
+        else
+        {   CPPAD_ASSERT_UNKNOWN( type == 4 );
+            atomic_four<RecBase>* afun =
+                reinterpret_cast< atomic_four<RecBase>* >(v_ptr);
+            ok = afun->rev_hes_sparsity(
+                call_id,
+                x_index,
+                y_index,
+                for_jac_sparsity,
+                rev_jac_flag,
+                rev_hes_sparsity
+            );
+        }
     }
     if( ! ok )
     {   // now take the extra time to copy the name
@@ -788,7 +954,7 @@ void call_atomic_rev_hes_sparsity(
     if( type == 2 )
     {   atomic_base<RecBase>* afun =
             reinterpret_cast< atomic_base<RecBase>* >(v_ptr);
-        afun->set_old(atom_old);
+        afun->set_old(call_id);
         afun->rev_sparse_hes(
             parameter_x,
             x_index,
@@ -798,9 +964,8 @@ void call_atomic_rev_hes_sparsity(
             rev_hes_sparsity
         );
     }
-    else
-    {   CPPAD_ASSERT_UNKNOWN( type == 3 );
-        atomic_three<RecBase>* afun =
+    else if( type == 3 )
+    {   atomic_three<RecBase>* afun =
             reinterpret_cast< atomic_three<RecBase>* >(v_ptr);
         afun->rev_hes_sparsity(
             parameter_x,
@@ -812,40 +977,61 @@ void call_atomic_rev_hes_sparsity(
             rev_hes_sparsity
         );
     }
+    else
+    {   atomic_four<RecBase>* afun =
+            reinterpret_cast< atomic_four<RecBase>* >(v_ptr);
+        afun->rev_hes_sparsity(
+            call_id,
+            x_index,
+            y_index,
+            for_jac_sparsity,
+            rev_jac_flag,
+            rev_hes_sparsity
+        );
+    }
 # endif
 }
 // ----------------------------------------------------------------------------
-/*!
-Reverse dependency callback to atomic functions.
+/*
+$begin atomic_rev_depend_callback$$
+
+$section Reverse Dependency Callback to Atomic Functions$$
+
+$head Prototype$$
+$srcthisfile%0%// BEGIN_REV_DEPEND%// END_REV_DEPEND%1%$$
 
-\param atom_index [in]
+$head atom_index$$
 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.
+$head call_id$$
+see the atomic_four $cref/call_id/atomic_four_call/call_id/$$ and
+the atomic_one $cref/id/atomic_one/id/$$.
+
+$head parameter_x$$
+is the value of the parameters in the corresponding atomic function call.
 
-\param parameter_x [in]
-is the value of the parameters in the corresponding function call
-afun(ax, ay).
+$head type_x$$
+is the type for each x component in the corresponding atomic function call.
 
-\param type_x [in]
-is the type for each x component in the corresponding function call
-afun(ax, ay).
+$head depend_x$$
+which components of x affect values we are interested in.
+This is the only output for this routine.
 
-\param depend_x [out]
-specifies which components of x affect values we are interested in.
+$head depend_y$$
+which components of y affect values we are interested in.
 
-\param depend_y [in]
-specifies which components of y affect values we are interested in.
+$end
 */
+// BEGIN_REV_DEPEND
 template <class Base, class RecBase>
 void call_atomic_rev_depend(
     size_t                      atom_index   ,
-    size_t                      atom_old     ,
+    size_t                      call_id      ,
     const vector<Base>&         parameter_x  ,
     const vector<ad_type_enum>& type_x       ,
     vector<bool>&               depend_x     ,
     const vector<bool>&         depend_y     )
+// END_REV_DEPEND
 {   CPPAD_ASSERT_UNKNOWN( 0 < atom_index );
     bool         set_null = false;
     size_t       type     = 0;          // set to avoid warning
@@ -859,16 +1045,21 @@ void call_atomic_rev_depend(
         if( type == 2 )
         {   atomic_base<RecBase>* afun =
                 reinterpret_cast< atomic_base<RecBase>* >(v_ptr);
-            afun->set_old(atom_old);
+            afun->set_old(call_id);
             vector<ad_type_enum> empty;
             ok = afun->rev_depend(parameter_x, type_x, depend_x, depend_y);
         }
-        else
-        {   CPPAD_ASSERT_UNKNOWN( type == 3 );
-            atomic_three<RecBase>* afun =
+        else if( type == 3 )
+        {   atomic_three<RecBase>* afun =
                 reinterpret_cast< atomic_three<RecBase>* >(v_ptr);
             ok = afun->rev_depend(parameter_x, type_x, depend_x, depend_y);
         }
+        else
+        {   CPPAD_ASSERT_UNKNOWN( type == 4 );
+            atomic_four<RecBase>* afun =
+                reinterpret_cast< atomic_four<RecBase>* >(v_ptr);
+            ok = afun->rev_depend(call_id, depend_x, depend_y);
+        }
     }
     if( ! ok )
     {   // now take the extra time to copy the name
@@ -886,14 +1077,19 @@ void call_atomic_rev_depend(
     {   atomic_base<RecBase>* afun =
             reinterpret_cast< atomic_base<RecBase>* >(v_ptr);
         vector<ad_type_enum> empty;
-        afun->set_old(atom_old);
+        afun->set_old(call_id);
         afun->rev_depend(parameter_x, type_x, depend_x, depend_y);
     }
-    else
+    else if( type == 3 )
     {   atomic_three<RecBase>* afun =
             reinterpret_cast< atomic_three<RecBase>* >(v_ptr);
         afun->rev_depend(parameter_x, type_x, depend_x, depend_y);
     }
+    else
+    {   atomic_four<RecBase>* afun =
+            reinterpret_cast< atomic_four<RecBase>* >(v_ptr);
+        afun->rev_depend(call_id, depend_x, depend_y);
+    }
 # endif
 }
 
diff --git a/include/cppad/local/sweep/dynamic.hpp b/include/cppad/local/sweep/dynamic.hpp
index a63a42f9a..fee4973bd 100644
--- a/include/cppad/local/sweep/dynamic.hpp
+++ b/include/cppad/local/sweep/dynamic.hpp
@@ -1,7 +1,7 @@
 # ifndef CPPAD_LOCAL_SWEEP_DYNAMIC_HPP
 # define CPPAD_LOCAL_SWEEP_DYNAMIC_HPP
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
+CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
 
 CppAD is distributed under the terms of the
              Eclipse Public License Version 2.0.
@@ -94,6 +94,7 @@ void dynamic(
     // vectors used in call to atomic fuctions
     vector<ad_type_enum> type_x;
     vector<Base>         taylor_x, taylor_y;
+    vector<bool>         select_y;
 # ifndef NDEBUG
     for(size_t j = 0; j < ind_dynamic.size(); ++j)
         CPPAD_ASSERT_UNKNOWN(
@@ -314,6 +315,12 @@ void dynamic(
             all_par_vec[i_par] = *par[0] * *par[1];
             break;
 
+            // neg
+            case neg_dyn:
+            CPPAD_ASSERT_UNKNOWN( n_arg == 1 );
+            all_par_vec[i_par] = - *par[0];
+            break;
+
             // pow
             case pow_dyn:
             CPPAD_ASSERT_UNKNOWN( n_arg == 2 );
@@ -412,23 +419,26 @@ void dynamic(
             // 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;
+                size_t call_id    = size_t( dyn_par_arg[i_arg + 1] );
+                size_t n          = size_t( dyn_par_arg[i_arg + 2] );
+                size_t m          = size_t( dyn_par_arg[i_arg + 3] );
+                n_dyn             = size_t( dyn_par_arg[i_arg + 4] );
+                n_arg             = 6 + n + m;
                 CPPAD_ASSERT_UNKNOWN(
-                    size_t( dyn_par_arg[i_arg + 4 + n + m] ) == n_arg
+                    size_t( dyn_par_arg[i_arg + 5 + 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);
+                select_y.resize(m);
+                //
+                // taylor_x, type_x
                 for(size_t j = 0; j < n; ++j)
-                {   addr_t arg_j = dyn_par_arg[i_arg + 4 + j];
+                {   addr_t arg_j = dyn_par_arg[i_arg + 5 + j];
                     taylor_x[j]   = all_par_vec[ arg_j ];
                     if( arg_j == 0 )
                         type_x[j] = variable_enum;
@@ -437,14 +447,20 @@ void dynamic(
                     else
                         type_x[j] = constant_enum;
                 }
+                // select_y
+                for(size_t i = 0; i < m; ++i)
+                {   i_par = size_t( dyn_par_arg[i_arg + 5 + n + i] );
+                    select_y[i] = dyn_par_is[i_par];
+                }
                 call_atomic_forward<Base, RecBase>(
                     taylor_x,
                     type_x,
                     need_y,
+                    select_y,
                     order_low,
                     order_up,
                     atom_index,
-                    atom_old,
+                    call_id,
                     taylor_x,
                     taylor_y
                 );
@@ -468,7 +484,7 @@ void dynamic(
                 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] );
+                {   i_par = size_t( dyn_par_arg[i_arg + 5 + n + i] );
                     if( dyn_par_is[i_par] )
                     {   CPPAD_ASSERT_UNKNOWN( i_par != 0 );
                         all_par_vec[i_par] = taylor_y[i];
diff --git a/include/cppad/local/sweep/for_hes.hpp b/include/cppad/local/sweep/for_hes.hpp
index b94746741..a902f6275 100644
--- a/include/cppad/local/sweep/for_hes.hpp
+++ b/include/cppad/local/sweep/for_hes.hpp
@@ -1,7 +1,7 @@
 # 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: C++ Algorithmic Differentiation: Copyright (C) 2003-21 Bradley M. Bell
 
 CppAD is distributed under the terms of the
              Eclipse Public License Version 2.0.
@@ -330,6 +330,7 @@ void for_hes(
             case CoshOp:
             case ExpOp:
             case LogOp:
+            case NegOp:
             case SinOp:
             case SinhOp:
             case SqrtOp:
@@ -427,7 +428,7 @@ void for_hes(
             // -------------------------------------------------
 
             case PowvpOp:
-            CPPAD_ASSERT_NARG_NRES(op, 2, 3)
+            CPPAD_ASSERT_NARG_NRES(op, 2, 1)
             sparse::for_hes_nl_unary_op(
                 np1, numvar, i_var, size_t(arg[0]), for_hes_sparse
             );
diff --git a/include/cppad/local/sweep/for_jac.hpp b/include/cppad/local/sweep/for_jac.hpp
index 228f1047d..429534ac6 100644
--- a/include/cppad/local/sweep/for_jac.hpp
+++ b/include/cppad/local/sweep/for_jac.hpp
@@ -1,7 +1,7 @@
 # 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: C++ Algorithmic Differentiation: Copyright (C) 2003-21 Bradley M. Bell
 
 CppAD is distributed under the terms of the
              Eclipse Public License Version 2.0.
@@ -416,6 +416,7 @@ void for_jac(
             // -------------------------------------------------
 
             case LogOp:
+            case NegOp:
             CPPAD_ASSERT_NARG_NRES(op, 1, 1);
             sparse::for_jac_unary_op(
                 i_var, size_t(arg[0]), var_sparsity
@@ -454,7 +455,7 @@ void for_jac(
             // -------------------------------------------------
 
             case PowvpOp:
-            CPPAD_ASSERT_NARG_NRES(op, 2, 3);
+            CPPAD_ASSERT_NARG_NRES(op, 2, 1);
             sparse::for_jac_unary_op(
                 i_var, size_t(arg[0]), var_sparsity
             );
diff --git a/include/cppad/local/sweep/forward0.hpp b/include/cppad/local/sweep/forward0.hpp
index 44397dd87..45b84f033 100644
--- a/include/cppad/local/sweep/forward0.hpp
+++ b/include/cppad/local/sweep/forward0.hpp
@@ -1,7 +1,7 @@
 # ifndef CPPAD_LOCAL_SWEEP_FORWARD0_HPP
 # define CPPAD_LOCAL_SWEEP_FORWARD0_HPP
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
+CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
 
 CppAD is distributed under the terms of the
              Eclipse Public License Version 2.0.
@@ -215,9 +215,11 @@ void forward0(
     vector<ad_type_enum> atom_type_x; // argument type
     vector<Base>         atom_tx;     // argument vector Taylor coefficients
     vector<Base>         atom_ty;     // result vector Taylor coefficients
+    vector<size_t>       atom_iy;     // variable indices for result vector
+    vector<bool>         atom_sy;     // select_y for this atomic function
     //
     // 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;
+    size_t atom_index=0, atom_id=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)
@@ -238,10 +240,6 @@ void forward0(
 # 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<size_t> atom_iy;
 # endif
 
     // skip the BeginOp at the beginning of the recording
@@ -272,7 +270,7 @@ void forward0(
                 {   // get information for this atomic function call
                     CPPAD_ASSERT_UNKNOWN( atom_state == start_atom );
                     play::atom_op_info<Base>(
-                        op, arg, atom_index, atom_old, atom_m, atom_n
+                        op, arg, atom_index, atom_id, atom_m, atom_n
                     );
                     //
                     // skip to the second AFunOp
@@ -638,6 +636,12 @@ void forward0(
             break;
             // -------------------------------------------------
 
+            case NegOp:
+            forward_neg_op_0(i_var, size_t(arg[0]), J, taylor);
+            break;
+
+            // -------------------------------------------------
+
             case NepvOp:
             if( compare_change_count )
             {   forward_nepv_op_0(
@@ -808,7 +812,7 @@ void forward0(
             // start or end an atomic function call
             flag = atom_state == start_atom;
             play::atom_op_info<RecBase>(
-                op, arg, atom_index, atom_old, atom_m, atom_n
+                op, arg, atom_index, atom_id, atom_m, atom_n
             );
             if( flag )
             {   atom_state = arg_atom;
@@ -819,14 +823,25 @@ void forward0(
                 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
+                atom_sy.resize(atom_m);
             }
             else
             {   CPPAD_ASSERT_UNKNOWN( atom_i == atom_m );
                 CPPAD_ASSERT_UNKNOWN( atom_j == atom_n );
                 atom_state = start_atom;
+                //
+                for(size_t i = 0; i < atom_m; ++i)
+                    atom_sy[i] = atom_iy[i] != 0;
+                //
+                // call atomic function for this operation
+                call_atomic_forward<Base, RecBase>(
+                    atom_par_x, atom_type_x, need_y, atom_sy,
+                    order_low, order_up, atom_index, atom_id, atom_tx, atom_ty
+                );
+                for(size_t i = 0; i < atom_m; ++i)
+                    if( atom_iy[i] > 0 )
+                        taylor[ atom_iy[i] * J + 0 ] = atom_ty[i];
 # if CPPAD_FORWARD0_TRACE
                 atom_trace = true;
 # endif
@@ -850,10 +865,6 @@ void forward0(
             //
             if( atom_j == atom_n )
             {   // call atomic function for this operation
-                call_atomic_forward<Base, RecBase>(
-                    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;
@@ -870,13 +881,7 @@ void forward0(
             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<Base, RecBase>(
-                    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:
@@ -886,10 +891,7 @@ void forward0(
             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++;
+            atom_iy[atom_i++] = 0;
             if( atom_i == atom_m )
                 atom_state = end_atom;
             break;
@@ -900,10 +902,7 @@ void forward0(
             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++];
+            atom_iy[atom_i++] = i_var;
             if( atom_i == atom_m )
                 atom_state = end_atom;
             break;
diff --git a/include/cppad/local/sweep/forward1.hpp b/include/cppad/local/sweep/forward1.hpp
index 4ce8d932d..0a9af62e2 100644
--- a/include/cppad/local/sweep/forward1.hpp
+++ b/include/cppad/local/sweep/forward1.hpp
@@ -1,7 +1,7 @@
 # ifndef CPPAD_LOCAL_SWEEP_FORWARD1_HPP
 # define CPPAD_LOCAL_SWEEP_FORWARD1_HPP
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
+CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
 
 CppAD is distributed under the terms of the
              Eclipse Public License Version 2.0.
@@ -233,9 +233,11 @@ void forward1(
     vector<ad_type_enum> atom_type_x; // argument type
     vector<Base>         atom_tx;     // argument vector Taylor coefficients
     vector<Base>         atom_ty;     // result vector Taylor coefficients
+    vector<size_t>       atom_iy;     // variable indices for result vector
+    vector<bool>         atom_sy;     // select_y for this atomic call
     //
     // 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;
+    size_t atom_index=0, atom_id=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)
@@ -262,10 +264,6 @@ void forward1(
     // (not needed for order zero)
     const size_t atom_q1 = q+1;
 
-    // variable indices for results vector
-    // (done differently for order zero).
-    vector<size_t> atom_iy;
-
     // skip the BeginOp at the beginning of the recording
     play::const_sequential_iterator itr = play->begin();
     // op_info
@@ -296,7 +294,7 @@ void forward1(
                 {   // get information for this atomic function call
                     CPPAD_ASSERT_UNKNOWN( atom_state == start_atom );
                     play::atom_op_info<Base>(
-                        op, arg, atom_index, atom_old, atom_m, atom_n
+                        op, arg, atom_index, atom_id, atom_m, atom_n
                     );
                     //
                     // skip to the second AFunOp
@@ -694,6 +692,11 @@ void forward1(
             case MulvvOp:
             forward_mulvv_op(p, q, i_var, arg, parameter, J, taylor);
             break;
+            // --------------------------------------------------
+
+            case NegOp:
+            forward_neg_op(p, q, i_var, size_t(arg[0]), J, taylor);
+            break;
             // -------------------------------------------------
 
             case NeppOp:
@@ -892,7 +895,7 @@ void forward1(
             // start or end an atomic function call
             flag = atom_state == start_atom;
             play::atom_op_info<RecBase>(
-                op, arg, atom_index, atom_old, atom_m, atom_n
+                op, arg, atom_index, atom_id, atom_m, atom_n
             );
             if( flag )
             {   atom_state = arg_atom;
@@ -904,16 +907,20 @@ void forward1(
                 atom_tx.resize(atom_n * atom_q1);
                 atom_ty.resize(atom_m * atom_q1);
                 atom_iy.resize(atom_m);
+                atom_sy.resize(atom_m);
             }
             else
             {   CPPAD_ASSERT_UNKNOWN( atom_i == atom_m );
                 CPPAD_ASSERT_UNKNOWN( atom_j == atom_n );
                 atom_state = start_atom;
                 //
+                for(i = 0; i < atom_m; ++i)
+                    atom_sy[i] = atom_iy[i] != 0;
+                //
                 // call atomic function for this operation
                 call_atomic_forward<Base, RecBase>(
-                    atom_par_x, atom_type_x, need_y,
-                    order_low, order_up, atom_index, atom_old, atom_tx, atom_ty
+                    atom_par_x, atom_type_x, need_y, atom_sy,
+                    order_low, order_up, atom_index, atom_id, atom_tx, atom_ty
                 );
                 for(i = 0; i < atom_m; i++)
                     if( atom_iy[i] > 0 )
diff --git a/include/cppad/local/sweep/forward2.hpp b/include/cppad/local/sweep/forward2.hpp
index 39d32a94b..812b42124 100644
--- a/include/cppad/local/sweep/forward2.hpp
+++ b/include/cppad/local/sweep/forward2.hpp
@@ -1,7 +1,7 @@
 # ifndef CPPAD_LOCAL_SWEEP_FORWARD2_HPP
 # define CPPAD_LOCAL_SWEEP_FORWARD2_HPP
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
+CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
 
 CppAD is distributed under the terms of the
              Eclipse Public License Version 2.0.
@@ -152,7 +152,7 @@ void forward2(
     vector<Base> 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;
+    size_t atom_index=0, atom_id=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)
@@ -170,9 +170,11 @@ void forward2(
     const size_t atom_q1 = q+1;
 
     // variable indices for results vector
-    // (done differently for order zero).
     vector<size_t> atom_iy;
 
+    // select_y for an atomic function call
+    vector<bool> atom_sy;
+
     // skip the BeginOp at the beginning of the recording
     play::const_sequential_iterator itr = play->begin();
     // op_info
@@ -202,7 +204,7 @@ void forward2(
                 {   // get information for this atomic function call
                     CPPAD_ASSERT_UNKNOWN( atom_state == start_atom );
                     play::atom_op_info<Base>(
-                        op, arg, atom_index, atom_old, atom_m, atom_n
+                        op, arg, atom_index, atom_id, atom_m, atom_n
                     );
                     //
                     // skip to the second AFunOp
@@ -429,6 +431,11 @@ void forward2(
             break;
             // -------------------------------------------------
 
+            case NegOp:
+            forward_neg_op_dir(q, r, i_var, size_t(arg[0]), J, taylor);
+            break;
+            // -------------------------------------------------
+
             case ParOp:
             k = i_var*(J-1)*r + i_var + (q-1)*r + 1;
             for(ell = 0; ell < r; ell++)
@@ -527,7 +534,7 @@ void forward2(
             // start or end an atomic function call
             flag = atom_state == start_atom;
             play::atom_op_info<RecBase>(
-                op, arg, atom_index, atom_old, atom_m, atom_n
+                op, arg, atom_index, atom_id, atom_m, atom_n
             );
             if( flag )
             {   atom_state = arg_atom;
@@ -544,6 +551,7 @@ void forward2(
                 atom_ty_all.resize(atom_m * (q * r + 1));
                 //
                 atom_iy.resize(atom_m);
+                atom_sy.resize(atom_m);
             }
             else
             {   CPPAD_ASSERT_UNKNOWN( atom_i == atom_m );
@@ -574,14 +582,18 @@ void forward2(
                             atom_ty_one[k_one] = atom_ty_all[k_all];
                         }
                     }
+                    // set atom_sy
+                    for(i = 0; i < atom_m; ++i)
+                        atom_sy[i] = atom_iy[i] != 0;
                     call_atomic_forward<Base,RecBase>(
                         atom_par_x,
                         atom_type_x,
                         need_y,
+                        atom_sy,
                         order_low,
                         order_up,
                         atom_index,
-                        atom_old,
+                        atom_id,
                         atom_tx_one,
                         atom_ty_one
                     );
diff --git a/include/cppad/local/sweep/rev_hes.hpp b/include/cppad/local/sweep/rev_hes.hpp
index 2ce3e443e..6277a7414 100644
--- a/include/cppad/local/sweep/rev_hes.hpp
+++ b/include/cppad/local/sweep/rev_hes.hpp
@@ -1,7 +1,7 @@
 # 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: C++ Algorithmic Differentiation: Copyright (C) 2003-21 Bradley M. Bell
 
 CppAD is distributed under the terms of the
              Eclipse Public License Version 2.0.
@@ -437,6 +437,7 @@ void rev_hes(
             // -------------------------------------------------
 
             case LogOp:
+            case NegOp:
             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
@@ -483,7 +484,7 @@ void rev_hes(
             // -------------------------------------------------
 
             case PowvpOp:
-            CPPAD_ASSERT_NARG_NRES(op, 2, 3)
+            CPPAD_ASSERT_NARG_NRES(op, 2, 1)
             sparse::rev_hes_nl_unary_op(
             i_var, size_t(arg[0]), RevJac, for_jac_sparse, rev_hes_sparse
             );
diff --git a/include/cppad/local/sweep/rev_jac.hpp b/include/cppad/local/sweep/rev_jac.hpp
index 5b344dc54..8403fd73e 100644
--- a/include/cppad/local/sweep/rev_jac.hpp
+++ b/include/cppad/local/sweep/rev_jac.hpp
@@ -1,7 +1,7 @@
 # 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: C++ Algorithmic Differentiation: Copyright (C) 2003-21 Bradley M. Bell
 
 CppAD is distributed under the terms of the
              Eclipse Public License Version 2.0.
@@ -444,6 +444,7 @@ void rev_jac(
             // -------------------------------------------------
 
             case LogOp:
+            case NegOp:
             CPPAD_ASSERT_NARG_NRES(op, 1, 1);
             sparse::rev_jac_unary_op(
                 i_var, size_t(arg[0]), var_sparsity
diff --git a/include/cppad/local/sweep/reverse.hpp b/include/cppad/local/sweep/reverse.hpp
index 84957d0a4..2e0660b8a 100644
--- a/include/cppad/local/sweep/reverse.hpp
+++ b/include/cppad/local/sweep/reverse.hpp
@@ -1,7 +1,7 @@
 # ifndef CPPAD_LOCAL_SWEEP_REVERSE_HPP
 # define CPPAD_LOCAL_SWEEP_REVERSE_HPP
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
+CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
 
 CppAD is distributed under the terms of the
              Eclipse Public License Version 2.0.
@@ -200,6 +200,7 @@ void reverse(
     const size_t         atom_k1 = d+1; // number orders for this calculation
     vector<Base>         atom_par_x;    // argument parameter values
     vector<ad_type_enum> atom_type_x;   // argument type
+    vector<bool>         atom_sx;       // slect_x for this function call
     vector<size_t>       atom_ix;       // variable indices for argument vector
     vector<Base>         atom_tx;       // argument vector Taylor coefficients
     vector<Base>         atom_ty;       // result vector Taylor coefficients
@@ -210,6 +211,10 @@ void reverse(
     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
 
+    // A vector with unspecified contents declared here so that operator
+    // routines do not need to re-allocate it
+    vector<Base> work;
+
     // temporary indices
     size_t j, ell;
 
@@ -525,6 +530,13 @@ void reverse(
                 d, i_var, arg, parameter, J, Taylor, K, Partial
             );
             break;
+            // -------------------------------------------------
+
+            case NegOp:
+            reverse_neg_op(
+                d, i_var, size_t(arg[0]), J, Taylor, K, Partial
+            );
+            break;
             // --------------------------------------------------
 
             case ParOp:
@@ -534,7 +546,7 @@ void reverse(
             case PowvpOp:
             CPPAD_ASSERT_UNKNOWN( size_t(arg[1]) < num_par );
             reverse_powvp_op(
-                d, i_var, arg, parameter, J, Taylor, K, Partial
+                d, i_var, arg, parameter, J, Taylor, K, Partial, work
             );
             break;
             // -------------------------------------------------
@@ -659,6 +671,7 @@ void reverse(
                 atom_ix.resize(atom_n);
                 atom_par_x.resize(atom_n);
                 atom_type_x.resize(atom_n);
+                atom_sx.resize(atom_n);
                 atom_tx.resize(atom_n * atom_k1);
                 atom_px.resize(atom_n * atom_k1);
                 atom_ty.resize(atom_m * atom_k1);
@@ -673,6 +686,7 @@ void reverse(
                 call_atomic_reverse<Base, RecBase>(
                     atom_par_x,
                     atom_type_x,
+                    atom_sx,
                     atom_k,
                     atom_index,
                     atom_old,
@@ -699,6 +713,7 @@ void reverse(
             //
             --atom_j;
             atom_ix[atom_j]               = 0;
+            atom_sx[atom_j]               = false;
             if( play->dyn_par_is()[ arg[0] ] )
                 atom_type_x[atom_j]       = dynamic_enum;
             else
@@ -721,6 +736,7 @@ void reverse(
             //
             --atom_j;
             atom_ix[atom_j]     = size_t( arg[0] );
+            atom_sx[atom_j]     = true;
             atom_type_x[atom_j] = variable_enum;
             atom_par_x[atom_j] = CppAD::numeric_limits<Base>::quiet_NaN();
             for(ell = 0; ell < atom_k1; ell++)
diff --git a/include/cppad/local/utility/cppad_vector_itr.hpp b/include/cppad/local/utility/cppad_vector_itr.hpp
index b4415d9c2..5be40b57e 100644
--- a/include/cppad/local/utility/cppad_vector_itr.hpp
+++ b/include/cppad/local/utility/cppad_vector_itr.hpp
@@ -1,7 +1,7 @@
 # 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: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
 
 CppAD is distributed under the terms of the
              Eclipse Public License Version 2.0.
@@ -306,19 +306,36 @@ $icode%element% = *%itr%
 %$$
 $codei%*%itr% = %element%
 %$$
+$icode%element% = %itr%[%n%]
+%$$
+$icode%itr%[%n%] = %element%
+%$$
 
 $head Source$$
 $srccode%hpp% */
 public:
+# if CPPAD_CONST
     const Type& operator*(void) const
     {   check_element();
         return (*data_)[index_];
     }
-# if ! CPPAD_CONST
+    const Type& operator[](difference_type n)
+    {   return *(*this + n);
+    }
+    const Type& operator[](size_t n)
+    {   return *( *this + difference_type(n) );
+    }
+# else
     Type& operator*(void)
     {   check_element();
         return (*data_)[index_];
     }
+    Type& operator[](difference_type n)
+    {   return *(*this + n);
+    }
+    Type& operator[](size_t n)
+    {   return *( *this + difference_type(n) );
+    }
 # endif
 /* %$$
 $end
@@ -334,10 +351,6 @@ $$
 $section Vector Class Iterator Random Access$$
 
 $head Syntax$$
-$icode%element% = %itr%[%n%]
-%$$
-$icode%itr%[%n%] = %element%
-%$$
 $icode%itr% %+-% = %n%
 %$$
 $icode%itr% = %other% %+-% %n%
@@ -373,9 +386,6 @@ $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;
diff --git a/include/cppad/utility/elapsed_seconds.hpp b/include/cppad/utility/elapsed_seconds.hpp
index 4e6890140..4dfa2f2c5 100644
--- a/include/cppad/utility/elapsed_seconds.hpp
+++ b/include/cppad/utility/elapsed_seconds.hpp
@@ -1,7 +1,7 @@
 # ifndef CPPAD_UTILITY_ELAPSED_SECONDS_HPP
 # define CPPAD_UTILITY_ELAPSED_SECONDS_HPP
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
+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.
@@ -16,10 +16,7 @@ in the Eclipse Public License, Version 2.0 are satisfied:
 $begin elapsed_seconds$$
 $spell
     cppad.hpp
-    Microsoft
-    gettimeofday
-    std
-    chrono
+    std::chrono
 $$
 
 $section Returns Elapsed Number of Seconds$$
@@ -30,21 +27,8 @@ $codei%# include <cppad/utility/elapsed_seconds.hpp>
 %$$
 $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 Accuracy$$
+This routine uses $code std::chrono::steady_clock$$ to do its timing.
 
 $head s$$
 is a $code double$$ equal to the
@@ -62,16 +46,8 @@ $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 <cppad/core/cppad_assert.hpp>
 
-// define nullptr
-# include <cppad/local/define.hpp>
-
 // needed before one can use CPPAD_ASSERT_FIRST_CALL_NOT_PARALLEL
 # include <cppad/utility/thread_alloc.hpp>
 
@@ -81,26 +57,7 @@ $end
 
 
 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;
@@ -118,4 +75,5 @@ inline double elapsed_seconds(void)
 }
 // --------------------------------------------------------------------------
 } // END_CPPAD_NAMESPACE
+
 # endif
diff --git a/include/cppad/utility/omh/cppad_vector.omh b/include/cppad/utility/omh/cppad_vector.omh
index 21aa56afa..f268e0050 100644
--- a/include/cppad/utility/omh/cppad_vector.omh
+++ b/include/cppad/utility/omh/cppad_vector.omh
@@ -1,5 +1,5 @@
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
+CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
 
 CppAD is distributed under the terms of the
              Eclipse Public License Version 2.0.
@@ -30,6 +30,8 @@ $spell
     iterator
     resized
     dereference
+    itr
+    citr
 $$
 
 
@@ -116,20 +118,9 @@ $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%;
-%$$
+It is no longer necessary for $icode vec$$ to have the
+same size as $icode other$$.
+This makes $code CppAD::vector$$ more like $code std::vector$$.
 
 $subhead Return Reference$$
 A reference to the vector $icode vec$$ is returned.
@@ -255,19 +246,19 @@ 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%>::iterator %itr%
 %$$
-$codei%typename CppAD::vector<%Scalar%>::const_iterator
+$codei%typename CppAD::vector<%Scalar%>::const_iterator %citr%
 %$$
 $icode%vec%.begin()
 %$$
 $icode%vec%.end()
 %$$
 
-$subhead iterator$$
+$subhead itr$$
 is a random access iterator type for non $code const$$ objects.
 
-$subhead const_iterator$$
+$subhead citr$$
 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.
@@ -282,6 +273,12 @@ 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 operator[]$$
+The syntax $icode%itr%[%i%]%$$
+and $icode%citr%[%i%]%$$ is extended
+(from a normal random access iterator) to include the case where
+$icode i$$ is $code size_t$$ object.
+
 $subhead Error Checking$$
 Each element access (dereference of the iterator)
 does an error check similar to the element access
diff --git a/include/cppad/utility/romberg_mul.hpp b/include/cppad/utility/romberg_mul.hpp
index e45753829..46636e032 100644
--- a/include/cppad/utility/romberg_mul.hpp
+++ b/include/cppad/utility/romberg_mul.hpp
@@ -1,7 +1,7 @@
 # ifndef CPPAD_UTILITY_ROMBERG_MUL_HPP
 # define CPPAD_UTILITY_ROMBERG_MUL_HPP
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
+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.
@@ -266,15 +266,17 @@ public:
 
         r  = RombergMulM1(Fm1, a, b, n, p, e);
 
-        size_t i, j;
         Float prod = 1;
+        for(size_t i = 0; i < m-1; i++)
+            prod *= (b[i] - a[i]);
+
+# ifndef NDEBUG
         size_t pow2 = 1;
-        for(i = 0; i < m-1; i++)
-        {   prod *= (b[i] - a[i]);
-            for(j = 0; j < (n[i] - 1); j++)
+        for(size_t i = 0; i < m-1; i++)
+            for(size_t j = 0; j < (n[i] - 1); j++)
                 pow2 *= 2;
-        }
         assert( Fm1.GetEcount() == (pow2+1) );
+# endif
 
         e = e + Fm1.GetEsum() * prod / Float( double(Fm1.GetEcount()) );
 
diff --git a/include/cppad/utility/sparse_rc.hpp b/include/cppad/utility/sparse_rc.hpp
index 3936988ce..9ca319150 100644
--- a/include/cppad/utility/sparse_rc.hpp
+++ b/include/cppad/utility/sparse_rc.hpp
@@ -1,7 +1,7 @@
 # ifndef CPPAD_UTILITY_SPARSE_RC_HPP
 # define CPPAD_UTILITY_SPARSE_RC_HPP
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
+CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
 
 CppAD is distributed under the terms of the
              Eclipse Public License Version 2.0.
@@ -24,6 +24,8 @@ $spell
     nr
     nc
     resize
+    std
+    ostream
 $$
 $section Row and Column Index Sparsity Patterns$$
 
@@ -34,6 +36,8 @@ $codei%sparse_rc<%SizeVector%>  %empty%
 %$$
 $codei%sparse_rc<%SizeVector%>  %pattern%(%nr%, %nc%, %nnz%)
 %$$
+$codei%sparse_rc<%SizeVector%>  %pattern%(%other%)
+%$$
 $icode%pattern% = %other%
 %$$
 $icode%pattern%.swap(%other%)
@@ -42,6 +46,8 @@ $icode%resize%(%nr%, %nc%, %nnz%)
 %$$
 $icode%pattern%.set(%k%, %r%, %c%)
 %$$
+$icode%pattern%.push_back(%r%, %c%)
+%$$
 $icode%pattern%.nr()
 %$$
 $icode%pattern%.nc()
@@ -56,6 +62,8 @@ $icode%row_major% = %pattern%.row_major()
 %$$
 $icode%col_major% = %pattern%.col_major()
 %$$
+$icode%os% << %pattern%
+%$$
 
 $head SizeVector$$
 We use $icode SizeVector$$ to denote $cref SimpleVector$$ class
@@ -77,20 +85,29 @@ The sparsity $icode pattern$$ is $code const$$
 except during its constructor, $code resize$$, and $code set$$.
 
 $head other$$
-The $icode other$$ variable has prototype
+
+$subhead Assignment and Constructor$$
+In the assignment and constructor, $icode other$$ has prototype
 $codei%
-    sparse_rc<%SizeVector%>  %other%
+    const sparse_rc<%SizeVector%>&  %other%
 %$$
+After the assignment and constructor, $icode pattern$$ is an independent copy
+of $icode other$$; i.e. it has all the same values as $icode other$$
+and changes to $icode pattern$$ do not affect $icode 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 Move Semantics Assignment and Constructor$$
+In the assignment and constructor, if $icode other$$ has prototype
+$codei%
+    sparse_rc<%SizeVector%>&&  %other%
+%$$
+A move semantics version of the assignment or constructor is used; e.g.,
+when $icode other$$ is a function return value.
 
 $subhead swap$$
+In the swap operation, $icode other$$ has prototype
+$codei%
+    sparse_rc<%SizeVector%>&  %other%
+%$$
 After the swap operation $icode other$$ ($icode pattern$$) is equivalent
 to $icode pattern$$ ($icode other$$) before the operation.
 
@@ -131,6 +148,14 @@ $codei%
     %col%[%k%] = %c%
 %$$
 
+$head push_back$$
+This function  the value $icode r$$ to the back of $icode row$$,
+the value $icode c$$ to the back of $icode col$$,
+and increases $icode nnz$$ by one.
+This operation requires $icode SizeVector$$ to support the
+$code push_back$$ operation
+(which is not part of the SimpleVector requirements).
+
 $subhead k$$
 This argument has type
 $codei%
@@ -208,6 +233,18 @@ $head Example$$
 The file $cref sparse_rc.cpp$$
 contains an example and test of this class.
 
+$head os$$
+If $icode os$$ is an $code std::ostream$$, the operation
+$codei%
+    %os% << %pattern%
+%$$
+outputs $icode pattern$$ to the $icode os$$ stream.
+The output begins with a left brace $code {$$
+and ends with a right brace $code }$$.
+The output is in row major order and has one line for each row.
+The row index is output at the beginning of a line
+and the column indices follow.
+
 $end
 */
 /*!
@@ -312,6 +349,22 @@ public:
         col_[k] = c;
         //
     }
+    /// push_back
+    void push_back(size_t r, size_t c)
+    {   CPPAD_ASSERT_KNOWN(
+            r < nr_,
+            "The index r is not less than nr in sparse_rc::push_back"
+        );
+        CPPAD_ASSERT_KNOWN(
+            c < nc_,
+            "The index c is to not less than nc in sparse_rc::push_back"
+        );
+        row_.push_back(r);
+        col_.push_back(c);
+        ++nnz_;
+        CPPAD_ASSERT_UNKNOWN( row_.size() == nnz_ );
+        CPPAD_ASSERT_UNKNOWN( col_.size() == nnz_ );
+    }
     /// number of rows in matrix
     size_t nr(void) const
     {   return nr_; }
@@ -375,6 +428,39 @@ public:
     }
 };
 
+template <class SizeVector>
+std::ostream& operator << (
+    std::ostream&                       os      ,
+    const CppAD::sparse_rc<SizeVector>& pattern )
+{   size_t nnz = pattern.nnz();
+    if( nnz == 0 )
+    {   os << "{ }";
+        return os;
+    }
+    const SizeVector& row       = pattern.row();
+    const SizeVector& col       = pattern.col();
+    SizeVector        row_major = pattern.row_major();
+    //
+    // k, r, c
+    size_t k = 0;
+    size_t r = row[ row_major[k] ];
+    size_t c = col[ row_major[k] ];
+    //
+    // os
+    os << "{\nrow = " << r << ", col = " << c;
+    while(++k < nnz )
+    {   bool new_row = r != row[ row_major[k] ];
+        r = row[ row_major[k] ];
+        c = col[ row_major[k] ];
+        if( new_row )
+            os << "\nrow = " << r << ", col = " << c;
+        else
+            os << ", " << c;
+    }
+    os << "\n}";
+    //
+    return os;
+}
 } // END_CPPAD_NAMESPACE
 
 # endif
diff --git a/include/cppad/utility/sparse_rcv.hpp b/include/cppad/utility/sparse_rcv.hpp
index 756a1c14c..fb5ca1a37 100644
--- a/include/cppad/utility/sparse_rcv.hpp
+++ b/include/cppad/utility/sparse_rcv.hpp
@@ -1,7 +1,7 @@
 # ifndef CPPAD_UTILITY_SPARSE_RCV_HPP
 # define CPPAD_UTILITY_SPARSE_RCV_HPP
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
+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.
@@ -77,7 +77,6 @@ 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%
@@ -96,18 +95,23 @@ 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
+
+$subhead Assignment and Constructor$$
+In the assignment and constructor, $icode other$$ has prototype
 $codei%
-    sparse_rcv<%SizeVector%, %ValueVector%>  %other%
+    const sparse_rcv<%SizeVector%, %ValueVector%>& %other%
 %$$
-
-$subhead Assignment$$
-After this assignment statement, $icode other$$ is an independent copy
+After this assignment and constructor, $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;
+and changes to $icode matrix$$ do not affect $icode other$$.
+
+$subhead Move Semantics Assignment and Constructor$$
+In the assignment and constructor, if $icode other$$ has prototype
+$codei%
+    sparse_rcv<%SizeVector%, %ValueVector%>&& %other%
+%$$
+A move semantics version of the assignment operator is used; e.g.,
+when $icode other$$ is a function return value;
 
 $subhead swap$$
 After the swap operation $icode other$$ ($icode matrix$$) is equivalent
@@ -245,6 +249,12 @@ public:
     sparse_rcv(void)
     : pattern_(0, 0, 0)
     { }
+    /// copy constructor
+    sparse_rcv(const sparse_rcv& other)
+    :
+    pattern_( other.pat() ) ,
+    val_( other.val() )
+    { }
     /// move semantics constructor
     /// (none of the default constructor values are used by destructor)
     sparse_rcv(sparse_rcv&& other)
diff --git a/include/cppad/utility/thread_alloc.hpp b/include/cppad/utility/thread_alloc.hpp
index 50b9a1be8..c05b25f7c 100644
--- a/include/cppad/utility/thread_alloc.hpp
+++ b/include/cppad/utility/thread_alloc.hpp
@@ -1,7 +1,7 @@
 # ifndef CPPAD_UTILITY_THREAD_ALLOC_HPP
 # define CPPAD_UTILITY_THREAD_ALLOC_HPP
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
+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.
@@ -845,6 +845,7 @@ $end
         // 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);
+        CPPAD_ASSERT_UNKNOWN( v_node != nullptr );
         node            = reinterpret_cast<block_t*>(v_node);
         node->tc_index_ = tc_index;
         void* v_ptr     = reinterpret_cast<void*>(node + 1);
diff --git a/include/cppad/utility/vector.hpp b/include/cppad/utility/vector.hpp
index 1b55b1c64..8548fef39 100644
--- a/include/cppad/utility/vector.hpp
+++ b/include/cppad/utility/vector.hpp
@@ -1,7 +1,7 @@
 # ifndef CPPAD_UTILITY_VECTOR_HPP
 # define CPPAD_UTILITY_VECTOR_HPP
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
+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.
@@ -285,7 +285,7 @@ $head Assignment$$
 see $cref/user API assignment/CppAD_vector/Assignment/$$
 
 $head Move Semantics$$
-A move semantics version of the assignment operator
+The move semantics version of the assignment operator
 is implemented using $code swap$$.
 
 $end
@@ -293,6 +293,7 @@ $end
 */
 // BEGIN_SWAP
 public:
+    // swap does not do any allocation and hence is declared noexcept
     void swap(vector& other) noexcept
 // END_SWAP
     {  // special case where vec and other are the same vector
@@ -306,27 +307,21 @@ public:
     }
 
 // 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
+    // move assingment does not doe any allocation and hence is declared noexcept
+    vector& operator=(vector&& other) noexcept
 // END_MOVE_ASSIGN
-    {   CPPAD_ASSERT_KNOWN(
-            length_ == other.length_ || (length_ == 0),
-            "vector: size miss match in assignment operation"
-        );
-        swap(other);
+    {   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"
-        );
+    {   // avoid copying old elements
+        resize(0);
+        // new size for this vector
+        resize( other.length_ );
+        // copy elements from other
         for(size_t i = 0; i < length_; i++)
             data_[i] = other.data_[i];
         return *this;
diff --git a/include/makefile.am b/include/makefile.am
index 1bb5f23c5..69134bf6f 100644
--- a/include/makefile.am
+++ b/include/makefile.am
@@ -1,5 +1,5 @@
 # -----------------------------------------------------------------------------
-# CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
+# CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
 #
 # CppAD is distributed under the terms of the
 #              Eclipse Public License Version 2.0.
@@ -20,6 +20,7 @@ myincludedir = $(includedir)/$(postfix_dir)
 #
 # BEGIN_SORT_THIS_LINE_PLUS_2
 nobase_myinclude_HEADERS =  \
+	cppad/example/atomic_four/mat_mul/rev_depend.hpp \
 	cppad/base_require.hpp \
 	cppad/configure.hpp \
 	cppad/core/abort_recording.hpp \
@@ -38,28 +39,39 @@ nobase_myinclude_HEADERS =  \
 	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/atomic/four/atomic.hpp \
+	cppad/core/atomic/four/call.hpp \
+	cppad/core/atomic/four/ctor.hpp \
+	cppad/core/atomic/four/devel/hes_sparsity.hpp \
+	cppad/core/atomic/four/devel/jac_sparsity.hpp\
+	cppad/core/atomic/four/for_type.hpp \
+	cppad/core/atomic/four/forward.hpp \
+	cppad/core/atomic/four/hes_sparsity.hpp \
+	cppad/core/atomic/four/jac_sparsity.hpp \
+	cppad/core/atomic/four/rev_depend.hpp \
+	cppad/core/atomic/four/reverse.hpp \
+	cppad/core/atomic/one/atomic.hpp \
+	cppad/core/atomic/three/afun.hpp \
+	cppad/core/atomic/three/atomic.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/atomic.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 \
@@ -118,15 +130,18 @@ nobase_myinclude_HEADERS =  \
 	cppad/core/fun_check.hpp \
 	cppad/core/fun_construct.hpp \
 	cppad/core/fun_eval.hpp \
+	cppad/core/graph/cpp_graph.hpp \
+	cppad/core/graph/from_graph.hpp \
+	cppad/core/graph/from_json.hpp \
+	cppad/core/graph/graph_op_enum.hpp \
+	cppad/core/graph/to_graph.hpp \
+	cppad/core/graph/to_json.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 \
@@ -173,6 +188,27 @@ nobase_myinclude_HEADERS =  \
 	cppad/core/vec_ad/vec_ad.hpp \
 	cppad/core/zdouble.hpp \
 	cppad/cppad.hpp \
+	cppad/example/atomic_four/mat_mul/base_mat_mul.hpp \
+	cppad/example/atomic_four/mat_mul/for_type.hpp \
+	cppad/example/atomic_four/mat_mul/forward.hpp \
+	cppad/example/atomic_four/mat_mul/get.hpp \
+	cppad/example/atomic_four/mat_mul/hes_sparsity.hpp \
+	cppad/example/atomic_four/mat_mul/jac_sparsity.hpp \
+	cppad/example/atomic_four/mat_mul/mat_mul.hpp \
+	cppad/example/atomic_four/mat_mul/reverse.hpp \
+	cppad/example/atomic_four/mat_mul/set.hpp \
+	cppad/example/atomic_four/vector/add_op.hpp \
+	cppad/example/atomic_four/vector/div_op.hpp \
+	cppad/example/atomic_four/vector/for_type.hpp \
+	cppad/example/atomic_four/vector/forward_op.hpp \
+	cppad/example/atomic_four/vector/hes_sparsity.hpp \
+	cppad/example/atomic_four/vector/jac_sparsity.hpp \
+	cppad/example/atomic_four/vector/mul_op.hpp \
+	cppad/example/atomic_four/vector/neg_op.hpp \
+	cppad/example/atomic_four/vector/rev_depend.hpp \
+	cppad/example/atomic_four/vector/reverse_op.hpp \
+	cppad/example/atomic_four/vector/sub_op.hpp \
+	cppad/example/atomic_four/vector/vector.hpp \
 	cppad/example/atomic_three/mat_mul.hpp \
 	cppad/example/atomic_two/eigen_cholesky.hpp \
 	cppad/example/atomic_two/eigen_mat_inv.hpp \
@@ -184,49 +220,60 @@ nobase_myinclude_HEADERS =  \
 	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_lexer.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/hash_code.hpp \
+	cppad/local/independent.hpp \
+	cppad/local/is_pod.hpp \
 	cppad/local/op.hpp \
+	cppad/local/op/abs_op.hpp \
+	cppad/local/op/acos_op.hpp \
+	cppad/local/op/acosh_op.hpp \
+	cppad/local/op/add_op.hpp \
+	cppad/local/op/asin_op.hpp \
+	cppad/local/op/asinh_op.hpp \
+	cppad/local/op/atan_op.hpp \
+	cppad/local/op/atanh_op.hpp \
+	cppad/local/op/comp_op.hpp \
+	cppad/local/op/cond_op.hpp \
+	cppad/local/op/cos_op.hpp \
+	cppad/local/op/cosh_op.hpp \
+	cppad/local/op/cskip_op.hpp \
+	cppad/local/op/csum_op.hpp \
+	cppad/local/op/discrete_op.hpp \
+	cppad/local/op/div_op.hpp \
+	cppad/local/op/erf_op.hpp \
+	cppad/local/op/exp_op.hpp \
+	cppad/local/op/expm1_op.hpp \
+	cppad/local/op/load_op.hpp \
+	cppad/local/op/log1p_op.hpp \
+	cppad/local/op/log_op.hpp \
+	cppad/local/op/mul_op.hpp \
+	cppad/local/op/neg_op.hpp \
+	cppad/local/op/parameter_op.hpp \
+	cppad/local/op/pow_op.hpp \
+	cppad/local/op/print_op.hpp \
+	cppad/local/op/prototype_op.hpp \
+	cppad/local/op/sign_op.hpp \
+	cppad/local/op/sin_op.hpp \
+	cppad/local/op/sinh_op.hpp \
+	cppad/local/op/sqrt_op.hpp \
+	cppad/local/op/store_op.hpp \
+	cppad/local/op/sub_op.hpp \
+	cppad/local/op/tan_op.hpp \
+	cppad/local/op/tanh_op.hpp \
+	cppad/local/op/zmul_op.hpp \
 	cppad/local/op_code_dyn.hpp \
 	cppad/local/op_code_var.hpp \
 	cppad/local/optimize/cexp_info.hpp \
@@ -246,7 +293,6 @@ nobase_myinclude_HEADERS =  \
 	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 \
@@ -255,29 +301,20 @@ nobase_myinclude_HEADERS =  \
 	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/cond_exp.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 \
@@ -294,11 +331,8 @@ nobase_myinclude_HEADERS =  \
 	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 \
diff --git a/include/makefile.in b/include/makefile.in
index 7a7f349a4..195006eab 100644
--- a/include/makefile.in
+++ b/include/makefile.in
@@ -263,7 +263,6 @@ 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@
@@ -318,6 +317,7 @@ pdfdir = @pdfdir@
 prefix = @prefix@
 program_transform_name = @program_transform_name@
 psdir = @psdir@
+runstatedir = @runstatedir@
 sbindir = @sbindir@
 sharedstatedir = @sharedstatedir@
 srcdir = @srcdir@
@@ -329,7 +329,7 @@ top_srcdir = @top_srcdir@
 @CppAD_POSTFIX_FALSE@postfix_dir = .
 
 # -----------------------------------------------------------------------------
-# CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
+# CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
 #
 # CppAD is distributed under the terms of the
 #              Eclipse Public License Version 2.0.
@@ -346,6 +346,7 @@ myincludedir = $(includedir)/$(postfix_dir)
 #
 # BEGIN_SORT_THIS_LINE_PLUS_2
 nobase_myinclude_HEADERS = \
+	cppad/example/atomic_four/mat_mul/rev_depend.hpp \
 	cppad/base_require.hpp \
 	cppad/configure.hpp \
 	cppad/core/abort_recording.hpp \
@@ -364,28 +365,39 @@ nobase_myinclude_HEADERS = \
 	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/atomic/four/atomic.hpp \
+	cppad/core/atomic/four/call.hpp \
+	cppad/core/atomic/four/ctor.hpp \
+	cppad/core/atomic/four/devel/hes_sparsity.hpp \
+	cppad/core/atomic/four/devel/jac_sparsity.hpp\
+	cppad/core/atomic/four/for_type.hpp \
+	cppad/core/atomic/four/forward.hpp \
+	cppad/core/atomic/four/hes_sparsity.hpp \
+	cppad/core/atomic/four/jac_sparsity.hpp \
+	cppad/core/atomic/four/rev_depend.hpp \
+	cppad/core/atomic/four/reverse.hpp \
+	cppad/core/atomic/one/atomic.hpp \
+	cppad/core/atomic/three/afun.hpp \
+	cppad/core/atomic/three/atomic.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/atomic.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 \
@@ -444,15 +456,18 @@ nobase_myinclude_HEADERS = \
 	cppad/core/fun_check.hpp \
 	cppad/core/fun_construct.hpp \
 	cppad/core/fun_eval.hpp \
+	cppad/core/graph/cpp_graph.hpp \
+	cppad/core/graph/from_graph.hpp \
+	cppad/core/graph/from_json.hpp \
+	cppad/core/graph/graph_op_enum.hpp \
+	cppad/core/graph/to_graph.hpp \
+	cppad/core/graph/to_json.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 \
@@ -499,6 +514,27 @@ nobase_myinclude_HEADERS = \
 	cppad/core/vec_ad/vec_ad.hpp \
 	cppad/core/zdouble.hpp \
 	cppad/cppad.hpp \
+	cppad/example/atomic_four/mat_mul/base_mat_mul.hpp \
+	cppad/example/atomic_four/mat_mul/for_type.hpp \
+	cppad/example/atomic_four/mat_mul/forward.hpp \
+	cppad/example/atomic_four/mat_mul/get.hpp \
+	cppad/example/atomic_four/mat_mul/hes_sparsity.hpp \
+	cppad/example/atomic_four/mat_mul/jac_sparsity.hpp \
+	cppad/example/atomic_four/mat_mul/mat_mul.hpp \
+	cppad/example/atomic_four/mat_mul/reverse.hpp \
+	cppad/example/atomic_four/mat_mul/set.hpp \
+	cppad/example/atomic_four/vector/add_op.hpp \
+	cppad/example/atomic_four/vector/div_op.hpp \
+	cppad/example/atomic_four/vector/for_type.hpp \
+	cppad/example/atomic_four/vector/forward_op.hpp \
+	cppad/example/atomic_four/vector/hes_sparsity.hpp \
+	cppad/example/atomic_four/vector/jac_sparsity.hpp \
+	cppad/example/atomic_four/vector/mul_op.hpp \
+	cppad/example/atomic_four/vector/neg_op.hpp \
+	cppad/example/atomic_four/vector/rev_depend.hpp \
+	cppad/example/atomic_four/vector/reverse_op.hpp \
+	cppad/example/atomic_four/vector/sub_op.hpp \
+	cppad/example/atomic_four/vector/vector.hpp \
 	cppad/example/atomic_three/mat_mul.hpp \
 	cppad/example/atomic_two/eigen_cholesky.hpp \
 	cppad/example/atomic_two/eigen_mat_inv.hpp \
@@ -510,49 +546,60 @@ nobase_myinclude_HEADERS = \
 	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_lexer.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/hash_code.hpp \
+	cppad/local/independent.hpp \
+	cppad/local/is_pod.hpp \
 	cppad/local/op.hpp \
+	cppad/local/op/abs_op.hpp \
+	cppad/local/op/acos_op.hpp \
+	cppad/local/op/acosh_op.hpp \
+	cppad/local/op/add_op.hpp \
+	cppad/local/op/asin_op.hpp \
+	cppad/local/op/asinh_op.hpp \
+	cppad/local/op/atan_op.hpp \
+	cppad/local/op/atanh_op.hpp \
+	cppad/local/op/comp_op.hpp \
+	cppad/local/op/cond_op.hpp \
+	cppad/local/op/cos_op.hpp \
+	cppad/local/op/cosh_op.hpp \
+	cppad/local/op/cskip_op.hpp \
+	cppad/local/op/csum_op.hpp \
+	cppad/local/op/discrete_op.hpp \
+	cppad/local/op/div_op.hpp \
+	cppad/local/op/erf_op.hpp \
+	cppad/local/op/exp_op.hpp \
+	cppad/local/op/expm1_op.hpp \
+	cppad/local/op/load_op.hpp \
+	cppad/local/op/log1p_op.hpp \
+	cppad/local/op/log_op.hpp \
+	cppad/local/op/mul_op.hpp \
+	cppad/local/op/neg_op.hpp \
+	cppad/local/op/parameter_op.hpp \
+	cppad/local/op/pow_op.hpp \
+	cppad/local/op/print_op.hpp \
+	cppad/local/op/prototype_op.hpp \
+	cppad/local/op/sign_op.hpp \
+	cppad/local/op/sin_op.hpp \
+	cppad/local/op/sinh_op.hpp \
+	cppad/local/op/sqrt_op.hpp \
+	cppad/local/op/store_op.hpp \
+	cppad/local/op/sub_op.hpp \
+	cppad/local/op/tan_op.hpp \
+	cppad/local/op/tanh_op.hpp \
+	cppad/local/op/zmul_op.hpp \
 	cppad/local/op_code_dyn.hpp \
 	cppad/local/op_code_var.hpp \
 	cppad/local/optimize/cexp_info.hpp \
@@ -572,7 +619,6 @@ nobase_myinclude_HEADERS = \
 	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 \
@@ -581,29 +627,20 @@ nobase_myinclude_HEADERS = \
 	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/cond_exp.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 \
@@ -620,11 +657,8 @@ nobase_myinclude_HEADERS = \
 	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 \
diff --git a/introduction/makefile.in b/introduction/makefile.in
index 6230b194c..4347c3769 100644
--- a/introduction/makefile.in
+++ b/introduction/makefile.in
@@ -294,7 +294,6 @@ 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@
@@ -349,6 +348,7 @@ pdfdir = @pdfdir@
 prefix = @prefix@
 program_transform_name = @program_transform_name@
 psdir = @psdir@
+runstatedir = @runstatedir@
 sbindir = @sbindir@
 sharedstatedir = @sharedstatedir@
 srcdir = @srcdir@
diff --git a/makefile.am b/makefile.am
index fb932d4c9..9acfb7381 100644
--- a/makefile.am
+++ b/makefile.am
@@ -63,6 +63,7 @@ SPEED_TESTS = \
 	speed/cppad \
 	speed/double \
 	speed/example \
+	speed/xpackage \
 	$(SPEED_FADBAD_TESTS) \
 	$(SPEED_SACADO_TESTS)
 #
diff --git a/makefile.in b/makefile.in
index ce43f8833..bbbba14b6 100644
--- a/makefile.in
+++ b/makefile.in
@@ -192,9 +192,9 @@ CTAGS = ctags
 CSCOPE = cscope
 DIST_SUBDIRS = cppad_ipopt/src example/ipopt_solve cppad_ipopt/example \
 	cppad_ipopt/speed cppad_ipopt/test speed/src speed/adolc \
-	speed/cppad speed/double speed/example speed/fadbad \
-	speed/sacado cppad_lib example/abs_normal example/atomic_two \
-	example/atomic_three test_more/deprecated \
+	speed/cppad speed/double speed/example speed/xpackage \
+	speed/fadbad speed/sacado cppad_lib example/abs_normal \
+	example/atomic_two example/atomic_three test_more/deprecated \
 	test_more/deprecated/atomic_two example/general \
 	example/get_started example/optimize example/print_for \
 	example/sparse example/utility include introduction \
@@ -342,7 +342,6 @@ 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@
@@ -397,6 +396,7 @@ pdfdir = @pdfdir@
 prefix = @prefix@
 program_transform_name = @program_transform_name@
 psdir = @psdir@
+runstatedir = @runstatedir@
 sbindir = @sbindir@
 sharedstatedir = @sharedstatedir@
 srcdir = @srcdir@
@@ -459,6 +459,7 @@ SPEED_TESTS = \
 	speed/cppad \
 	speed/double \
 	speed/example \
+	speed/xpackage \
 	$(SPEED_FADBAD_TESTS) \
 	$(SPEED_SACADO_TESTS)
 
diff --git a/omh/appendix/deprecated/deprecated.omh b/omh/appendix/deprecated/deprecated.omh
index 830a847b5..892e70860 100644
--- a/omh/appendix/deprecated/deprecated.omh
+++ b/omh/appendix/deprecated/deprecated.omh
@@ -1,5 +1,5 @@
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 Bradley M. Bell
+CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
 
   CppAD is distributed under the terms of the
                Eclipse Public License Version 2.0.
@@ -32,8 +32,8 @@ $childtable%
     include/cppad/core/epsilon.hpp%
     include/cppad/core/test_vector.hpp%
     cppad_ipopt/src/cppad_ipopt_nlp.hpp%
-    include/cppad/core/atomic/atomic_one.hpp%
-    include/cppad/core/atomic/atomic_two.hpp%
+    include/cppad/core/atomic/one/atomic.hpp%
+    include/cppad/core/atomic/two/atomic.hpp%
     example/multi_thread/multi_atomic_two.omh%
     include/cppad/core/chkpoint_one/chkpoint_one.hpp%
     example/multi_thread/multi_chkpoint_one.omh%
diff --git a/omh/appendix/deprecated/fun_deprecated.omh b/omh/appendix/deprecated/fun_deprecated.omh
index bf3eae318..e36b654b5 100644
--- a/omh/appendix/deprecated/fun_deprecated.omh
+++ b/omh/appendix/deprecated/fun_deprecated.omh
@@ -1,5 +1,5 @@
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-17 Bradley M. Bell
+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.
@@ -122,7 +122,7 @@ $subhead Deprecated 2006-04-03$$
 There are other sizes attached to an ADFun object, for example,
 the number of operations in the sequence.
 In order to avoid confusion with these other sizes,
-use $cref/size_var/seq_property/size_var/$$ to obtain
+use $cref/size_var/fun_property/size_var/$$ to obtain
 the number of variables in the operation sequence.
 
 $head taylor_size$$
diff --git a/omh/appendix/faq.omh b/omh/appendix/faq.omh
index 1917b0c30..17fc11fdc 100644
--- a/omh/appendix/faq.omh
+++ b/omh/appendix/faq.omh
@@ -1,5 +1,5 @@
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 Bradley M. Bell
+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.
@@ -150,7 +150,7 @@ Each call to $cref Reverse$$ computes the derivative of one
 range direction with respect to all the domain directions.
 The times required for (speed of)
 calls $code Forward$$ and $code Reverse$$ are about equal.
-The $cref/Parameter/seq_property/Parameter/$$
+The $cref/Parameter/fun_property/Parameter/$$
 function can be used to quickly determine that
 some range directions have derivative zero.
 
diff --git a/omh/appendix/glossary.omh b/omh/appendix/glossary.omh
index 306ac2d03..d58340172 100644
--- a/omh/appendix/glossary.omh
+++ b/omh/appendix/glossary.omh
@@ -1,5 +1,5 @@
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 Bradley M. Bell
+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.
@@ -36,8 +36,8 @@ defines a function
 $latex F : \B{R}^n \rightarrow \B{R}^m $$
 where $latex \B{R}$$ is the space corresponding to objects of type
 $icode Base$$ (usually the real numbers),
-$icode n$$ is the size of the $cref/domain/seq_property/Domain/$$ space, and
-$icode m$$ is the size of the $cref/range/seq_property/Range/$$ space.
+$icode n$$ is the size of the $cref/domain/fun_property/Domain/$$ space, and
+$icode m$$ is the size of the $cref/range/fun_property/Range/$$ space.
 We refer to $latex F$$ as the AD function corresponding to
 the operation sequence stored in the object $icode f$$.
 (See the $cref/FunCheck discussion/FunCheck/Discussion/$$ for
diff --git a/omh/appendix/whats_new/04.omh b/omh/appendix/whats_new/04.omh
index ade22191d..70c2dfd81 100644
--- a/omh/appendix/whats_new/04.omh
+++ b/omh/appendix/whats_new/04.omh
@@ -1,5 +1,5 @@
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-17 Bradley M. Bell
+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.
@@ -848,7 +848,7 @@ have been added to the $code cppad/Test$$ directory.
 $pre
 
 $$
-The $cref/f.Parameter()/seq_property/Parameter/$$ function was added so that
+The $cref/f.Parameter()/fun_property/Parameter/$$ function was added so that
 one can count how many components of the range space depend
 on the value of the domain space components.
 This helps when deciding whether to use forward or reverse mode.
@@ -862,7 +862,7 @@ when executing $cref Forward$$ and $cref Reverse$$ calculations.
 $pre
 
 $$
-The $cref Independent$$ and $cref/Parameter/seq_property/Parameter/$$ functions
+The $cref Independent$$ and $cref/Parameter/fun_property/Parameter/$$ functions
 were moved below $cref ADFun$$ in the documentation.
 
 
diff --git a/omh/appendix/whats_new/06.omh b/omh/appendix/whats_new/06.omh
index 39936ebc9..f99b46a64 100644
--- a/omh/appendix/whats_new/06.omh
+++ b/omh/appendix/whats_new/06.omh
@@ -1,5 +1,5 @@
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-18 Bradley M. Bell
+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.
@@ -394,7 +394,7 @@ $pre
 
 $$
 Correct some references to $code var_size$$ that should have been
-$cref/size_var/seq_property/size_var/$$.
+$cref/size_var/fun_property/size_var/$$.
 
 $head 11-04$$
 Put text written to standard output in the documentation for the
@@ -801,7 +801,7 @@ $pre
 
 $$
 The $code var_size$$ member function was changed to
-$cref/size_var/seq_property/size_var/$$
+$cref/size_var/fun_property/size_var/$$
 (this is not backward compatible, but $code var_size$$ was just added on
 $cref/04-03/whats_new_06/04-03/$$).
 
@@ -839,8 +839,8 @@ $head 04-02$$
 The member functions of $cref ADFun$$ that return properties of
 AD of $icode Base$$
 $cref/operation sequence/glossary/Operation/Sequence/$$
-have been grouped into the $cref seq_property$$ section.
-In addition, the $cref seq_property.cpp$$ example has been added.
+have been grouped into the $cref fun_property$$ section.
+In addition, the $cref fun_property.cpp$$ example has been added.
 $pre
 
 $$
diff --git a/omh/appendix/whats_new/09.omh b/omh/appendix/whats_new/09.omh
index e3d879dd8..af5e62cdc 100644
--- a/omh/appendix/whats_new/09.omh
+++ b/omh/appendix/whats_new/09.omh
@@ -1,5 +1,5 @@
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 Bradley M. Bell
+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.
@@ -106,12 +106,12 @@ $pre
 
 $$
 Add the following functions:
-$cref/size_op/seq_property/size_op/$$,
-$cref/size_op_arg/seq_property/size_op_arg/$$,
+$cref/size_op/fun_property/size_op/$$,
+$cref/size_op_arg/fun_property/size_op_arg/$$,
 and
-$cref/size_op_seq/seq_property/size_op_seq/$$.
+$cref/size_op_seq/fun_property/size_op_seq/$$.
 In addition, improve and extend the
-$cref seq_property.cpp$$ example.
+$cref fun_property.cpp$$ example.
 
 $head 11-28$$
 Fix bug in tape optimization with $cref VecAD$$ objects.
@@ -295,7 +295,7 @@ $pre
 
 $$
 The function
-$cref/size_VecAD/seq_property/size_VecAD/$$ function was added
+$cref/size_VecAD/fun_property/size_VecAD/$$ function was added
 so that the user could see the $code VecAD$$ vectors
 and elements corresponding to an operation sequence.
 
@@ -313,7 +313,7 @@ $head 08-06$$
 Add hash table coding to reduce the number of copies of the same
 parameter value necessary in a tape recording.
 In addition, add the function
-$cref/size_par/seq_property/size_par/$$ was added
+$cref/size_par/fun_property/size_par/$$ was added
 so that the user could see the number of parameters
 corresponding to an operation sequence.
 
diff --git a/omh/appendix/whats_new/10.omh b/omh/appendix/whats_new/10.omh
index dc3f32751..3f594e1d7 100644
--- a/omh/appendix/whats_new/10.omh
+++ b/omh/appendix/whats_new/10.omh
@@ -1,5 +1,5 @@
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
+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.
@@ -184,7 +184,7 @@ $code sizeof(size_t))$$.
 $head 02-11$$
 The $code speed$$ directory has been reorganized and the
 common part of the $cref/link routines/speed_main/Link Routines/$$,
-as well as the $cref microsoft_timer$$,
+as well as the $code microsoft_timer$$,
 have been moved to the subdirectory $code speed/src$$
 where a library is built.
 
diff --git a/omh/appendix/whats_new/11.omh b/omh/appendix/whats_new/11.omh
index a4c49f592..9952bbc55 100644
--- a/omh/appendix/whats_new/11.omh
+++ b/omh/appendix/whats_new/11.omh
@@ -1,5 +1,5 @@
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-18 Bradley M. Bell
+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.
@@ -710,7 +710,7 @@ $list number$$
 The $cref/tape_addr_type/autotools/tape_addr_type/$$ option was added
 to the $cref/configure/autotools/Configure/$$ command line.
 $lnext
-The function $cref/size_op_seq/seq_property/size_op_seq/$$ results uses
+The function $cref/size_op_seq/fun_property/size_op_seq/$$ results uses
 $code sizeof(CppAD_TAPE_ADDR_TYPE)$$
 where it used to use $code sizeof(size_t)$$.
 $lnext
@@ -782,7 +782,7 @@ $cref/
 description has been changed to explicitly specify that the
 default constructor is used to initialize elements of the array.
 $lnext
-The $cref/size_op_seq/seq_property/size_op_seq/$$ documentation
+The $cref/size_op_seq/fun_property/size_op_seq/$$ documentation
 has been improved to mention that the allocated memory may be larger.
 $lend
 
diff --git a/omh/appendix/whats_new/13.omh b/omh/appendix/whats_new/13.omh
index 264ef0f06..27d1bcca5 100644
--- a/omh/appendix/whats_new/13.omh
+++ b/omh/appendix/whats_new/13.omh
@@ -1,5 +1,5 @@
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
+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.
@@ -177,7 +177,7 @@ Add $cref/optimization/optimize/$$ of conditional expressions; see
 $cref/CondExp/CondExp/Optimize/$$.
 $lnext
 Add a phantom argument at the beginning of the operations sequence;
-$cref/size_op_arg/seq_property/size_op_arg/$$ and $cref seq_property.cpp$$.
+$cref/size_op_arg/fun_property/size_op_arg/$$ and $cref fun_property.cpp$$.
 (This helps with the optimization mentioned above.)
 $lnext
 Add the function $cref number_skip$$ to measure how much optimization
diff --git a/omh/appendix/whats_new/17.omh b/omh/appendix/whats_new/17.omh
index 4dc1dcfbb..e73508d76 100644
--- a/omh/appendix/whats_new/17.omh
+++ b/omh/appendix/whats_new/17.omh
@@ -1,5 +1,5 @@
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
+CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
 
   CppAD is distributed under the terms of the
                Eclipse Public License Version 2.0.
@@ -160,7 +160,7 @@ $codei%
     %f%.size_op() * sizeof(%tape_addr_type)
 %$$
 was added to the value returned by
-$cref/size_op_seq/seq_property/size_op_seq/$$.
+$cref/size_op_seq/fun_property/size_op_seq/$$.
 
 $head 11-04$$
 The method for iterating through the tape has been changed.
@@ -170,7 +170,7 @@ $codei%
     %f%.size_op() * sizeof(%tape_addr_type) * 2
 %$$
 was added to the value returned by
-$cref/size_op_seq/seq_property/size_op_seq/$$.
+$cref/size_op_seq/fun_property/size_op_seq/$$.
 In addition, some minor corrections were made to the
 $cref/tape_addr_type/cmake/cppad_tape_addr_type/$$
 requirements.
@@ -467,9 +467,16 @@ $cref/transpose/rev_hes_sparsity/transpose/$$ was reversed.
 
 $head 03-11$$
 Add sparse assignment statements; see $icode other$$ for
-$cref/sparse_rc/sparse_rc/other/Assignment/$$ and
-$cref/sparse_rcv/sparse_rcv/other/Assignment/$$.
-
+$cref/sparse_rc/
+    sparse_rc/
+    other/
+    Assignment and Constructor
+/$$ and
+$cref/sparse_rcv/
+    sparse_rcv/
+    other/
+    Assignment and Constructor
+/$$.
 $head 03-10$$
 Add the a sizing constructor to the
 $cref/sparse_rc syntax/sparse_rc/Syntax/$$; i.e.,
@@ -494,11 +501,8 @@ Fix warning during $cref cmake$$ command,
 on $href%https://www.cygwin.com/%cygwin%$$ systems,
 about $code WIN32$$ not being defined.
 $lnext
-Add $cref/element-wise atomic operations
-    /wish_list
-    /Element-wise Atomic Operations
-/$$
-to the wish list.
+Add element-wise atomic operations to the wish list.
+This was completed by the $cref atomic_four_vector$$ example.
 $lend
 
 $head 02-21$$
diff --git a/omh/appendix/whats_new/18.omh b/omh/appendix/whats_new/18.omh
index a4006721f..9dee8aaa5 100644
--- a/omh/appendix/whats_new/18.omh
+++ b/omh/appendix/whats_new/18.omh
@@ -1,5 +1,5 @@
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 Bradley M. Bell
+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.
@@ -385,7 +385,7 @@ $lend
 
 $head 08-05$$
 The amount of memory in an operation sequence has changed; see
-$cref/f.size_op_seq/seq_property/size_op_seq/$$.
+$cref/f.size_op_seq/fun_property/size_op_seq/$$.
 
 $head 08-04$$
 Remove the restrictions on dynamic parameters.
@@ -418,9 +418,9 @@ $cref/dynamic/Independent/dynamic/$$ parameters
 in a call to Independent.
 For this reason the function
 $icode%f%.size_dynamic()%$$ has been replaced by
-$cref/size_dyn_ind/seq_property/size_dyn_ind/$$,
-$cref/size_dyn_par/seq_property/size_dyn_par/$$, and
-$cref/size_dyn_arg/seq_property/size_dyn_arg/$$.
+$cref/size_dyn_ind/fun_property/size_dyn_ind/$$,
+$cref/size_dyn_par/fun_property/size_dyn_par/$$, and
+$cref/size_dyn_arg/fun_property/size_dyn_arg/$$.
 
 
 $head 07-23$$
@@ -453,14 +453,14 @@ $head 06-19$$
 Another (smaller) reduction in the amount of extra memory used during the
 $cref optimize$$ process.
 This time a vector of length
-$cref/size_op/seq_property/size_op/$$ was converted from the type
+$cref/size_op/fun_property/size_op/$$ was converted from the type
 used for C++ enums to a type that only used one byte.
 
 $head 06-13$$
 Reduce the amount of extra memory used during the $cref optimize$$ process.
 To be more specific, two vectors that were separate now share the same memory.
 These vectors have size equal to
-$cref/size_op/seq_property/size_op/$$
+$cref/size_op/fun_property/size_op/$$
 for the old operation sequence, and element type
 $cref/cppad_tape_addr_type/cmake/cppad_tape_addr_type/$$.
 
@@ -509,7 +509,7 @@ the size of an enum type to the size of an $code unsigned char$$; i.e.,
 one byte.
 This changed $code CppAD::local::OpCode$$ to
 $code CPPAD_VEC_ENUM_TYPE$$ in the expression used to compute
-$cref/size_op_arg/seq_property/size_op_seq/$$.
+$cref/size_op_arg/fun_property/size_op_seq/$$.
 Note $code CPPAD_VEC_ENUM_TYPE$$ is not in CppAD API and may change.
 $lnext
 There was a bug in the call to $code optimize$$ for the CppAD
@@ -543,10 +543,10 @@ $cref/11-20/whats_new_17/11-20/$$ in whats new for 2017.
 This caused CppAD to always use more memory for storing tapes.
 This has been fixed so this extra memory is only allocated when it is needed.
 In addition it can be freed; see
-$cref/size_random/seq_property/size_random/$$ and
+$cref/size_random/fun_property/size_random/$$ and
 $cref/clear_subgraph/subgraph_reverse/clear_subgraph/$$.
 In addition, this changed the amount of memory returned by
-$cref/size_op_seq/seq_property/size_op_seq/$$ so that it
+$cref/size_op_seq/fun_property/size_op_seq/$$ so that it
 no longer includes the part returned by $code size_random$$.
 
 $head 04-29$$
diff --git a/omh/appendix/whats_new/19.omh b/omh/appendix/whats_new/19.omh
index 7c2a16f8c..52dda3f79 100644
--- a/omh/appendix/whats_new/19.omh
+++ b/omh/appendix/whats_new/19.omh
@@ -1,5 +1,5 @@
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 Bradley M. Bell
+CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
 
   CppAD is distributed under the terms of the
                Eclipse Public License Version 2.0.
@@ -396,8 +396,8 @@ $code mat_mul.hpp$$
 from the $code include/cppad/example$$ directory
 to the $code include/cppad/example/atomic_three$$ directory.
 $lnext
-Improve the $cref/syntax/atomic_three/Syntax/$$,
-and $cref/parameter_x/atomic_three/parameter_x/$$ discussion,
+Improve the $cref/syntax/atomic_three_define/Syntax/$$,
+and $cref/parameter_x/atomic_three_define/parameter_x/$$ discussion,
 in the documentation for the $code atomic_three$$ functions.
 Furthermore, add an extra discussion of the parameters
 to the documentation for $icode taylor_x$$ in the
@@ -707,17 +707,17 @@ and its subsections, was improved.
 
 $head 01-17$$
 The arguments
-$cref/parameter_x/atomic_three/parameter_x/$$ and
-$cref/type_x/atomic_three/type_x/$$ were included
+$cref/parameter_x/atomic_three_define/parameter_x/$$ and
+$cref/type_x/atomic_three_define/type_x/$$ were included
 for all the $code atomic_three$$ virtual functions.
 
 $head 01-16$$
 More improvements, and bug fixes, in the optimization of $cref atomic$$
 operations.
 This results in a reduction in the number of parameters
-$cref/size_par/seq_property/size_par/$$
+$cref/size_par/fun_property/size_par/$$
 and the number of variables
-$cref/size_var/seq_property/size_var/$$.
+$cref/size_var/fun_property/size_var/$$.
 
 $head 01-15$$
 Fix a bug in the optimization of $cref atomic_three$$
@@ -760,7 +760,7 @@ Move the checkpoint examples below the
 $cref/checkpoint/chkpoint_one/$$ documentation.
 $lnext
 A phantom parameter, at index zero, was added; see
-$cref/size_par/seq_property/size_par/$$.
+$cref/size_par/fun_property/size_par/$$.
 $lnext
 There appears to have been a bug in $code put_con_par$$ (not tested for)
 whereby a constant parameter might match a dynamic parameter
diff --git a/omh/appendix/whats_new/20.omh b/omh/appendix/whats_new/20.omh
index b23fb5a64..2baa1af67 100644
--- a/omh/appendix/whats_new/20.omh
+++ b/omh/appendix/whats_new/20.omh
@@ -1,5 +1,5 @@
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
+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.
@@ -129,8 +129,16 @@ $cref/sparse_rc/sparse_rc/other/swap/$$ and
 $cref/sparse_rcv/sparse_rcv/other/swap/$$ template classes.
 $lnext
 A move semantics version of the assignment operator was added to the
-$cref/sparse_rc/sparse_rc/other/Assignment/$$ and
-$cref/sparse_rcv/sparse_rcv/other/Assignment/$$ template classes.
+$cref/sparse_rc/
+    sparse_rc/
+    other/
+    Move Semantics Assignment and Constructor
+/$$
+$cref/sparse_rcv/
+    sparse_rcv/
+    other/
+    Move Semantics Assignment and Constructor
+/$$ template classes.
 $lnext
 The $icode job$$ option was added to the
 $cref/det_minor/link_det_minor/job/$$ and
diff --git a/omh/appendix/whats_new/21.omh b/omh/appendix/whats_new/21.omh
new file mode 100644
index 000000000..bca604e66
--- /dev/null
+++ b/omh/appendix/whats_new/21.omh
@@ -0,0 +1,374 @@
+/* --------------------------------------------------------------------------
+CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
+
+  CppAD is distributed under the terms of the
+               Eclipse Public License Version 2.0.
+
+  This Source Code may also be made available under the following
+  Secondary License when the conditions 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 whats_new_21$$
+$spell
+    CppAD
+    cppad
+    cxx
+    cmake
+    json_lexer
+    std::isdigit
+    Microsoft
+    const
+    ifndef
+    iterator
+    azmul
+    nans
+    optimizer
+    eigen
+    cppadcg
+    ipopt
+    op_enum
+    fabs
+    hpp
+    var
+    vec
+    msys
+    cygwin
+    rcv
+    det
+    ltmain
+    lcppad
+    pkgconfig
+    cplusplus
+    txt
+    atan
+$$
+
+$section Changes and Additions to CppAD During 2021$$
+
+$head 12-17$$
+Add forward mode calculations using $code AD<double>$$ to the
+$cref atomic_four_vector$$ example.
+
+$head 12-16$$
+Change $code virtual$$ to $code override$$ in all the
+$cref atomic_three_example$$ files and
+$cref  multi_atomic_three_user$$.
+
+$head 12-10$$
+$list number$$
+Added the example $cref atomic_four_vector$$.
+$lnext
+Fix some compiler warnings when building with $code NDEBUG$$ defined.
+$lend
+
+$head 12-08$$
+Update to a newer version of the $cref autotools$$.
+
+$head 09-04$$
+There was a bug in the $cref atan2$$ function.
+For example, the derivative of $code atan2(0,1)$$ was incorrect; see
+$href%https://github.com/coin-or/CppAD/issues/120%issue 120%$$.
+This has been fixed and the $cref atan2.cpp$$ example has been
+extended to do more testing.
+
+$head 08-31$$
+There was a bug in the CMake configuration files such that
+$code make check_example_multi_thread$$ was not being constructed.
+Hence $code make check$$ did not include the multi_thread tests.
+This has been fixed.
+
+$head 08-27$$
+The following error occurred
+$codei%
+    compile_source_test: cplusplus_201100_ok is defined before expected
+%$$
+if the $cref cmake$$ command was run twice,
+without first removing the $code CMakeCache.txt$$ file.
+This has been fixed.
+
+
+$head 08-26$$
+The cmake command was extended to allow for one to specify
+$cref/CMAKE_BUILD_TYPE/cmake/cmake_build_type/$$.
+This forced changing the default for
+$cref/cppad_debug_which/cmake/cppad_debug_which/$$ from
+$code debug_all$$ to the empty string.
+
+$head 07-31$$
+Do more work on pkgconfig files:
+Remove duplicates and put $code -L$$ entries
+before $code -l$$ entries in $code Libs$$ section.
+Furthermore, move all information from private to normal section.
+
+$head 07-30$$
+Fix a bug in the $cref pkgconfig$$ files.
+To be specific, there was an extra $code -l$$ at the front of the list
+of library flags; e.g.,
+$code -l-lcppad_lib$$ was changed to $code -lcppad_lib$$.
+
+$head 07-12$$
+$list number$$
+Change all the scripts called by $cref get_optional.sh$$ to use
+all the processing units available on the system when compiling
+and linking the optional packages.
+$lnext
+Fix $cref get_colpack.sh$$ so that it does not leave behind
+$code ltmain.sh$$ and $code test-driver$$ in the top source directory.
+$lnext
+Change the $cref cmake$$ script use of $code CHECK_CXX_SOURCE_RUNS$$
+to $code CHECK_CXX_SOURCE_COMPILES$$.
+This makes it easier to use CppAD in a cross compiling context.
+$lend
+
+$head 06-22$$
+Improve $cref Var2Par$$ documentation and $cref var2par.cpp$$ example
+by separating dynamic and constant parameters.
+
+$head 06-06$$
+The $code CppAD::vector$$ assignment statement no longer requires the
+size of the vectors to be the same; see
+$cref/check size/CppAD_vector/Assignment/Check Size/$$.
+
+$head 06-02$$
+$list number$$
+Remove $code microsoft_timer$$ which is no longer needed by
+$cref elapsed_seconds$$ because c++11 required (starting this year).
+$lnext
+Remove any use of $code CMAKE_SOURCE_DIR$$.
+This allows CppAD's top source directory
+to be used as a subdirectory of a larger CMake package.
+$lend
+
+$head 05-12$$
+$list number$$
+The cmake
+$cref/include_cppadcg/cmake/include_cppadcg/$$ option was not working
+when cppadcg was the only optional package.
+This has been fixed.
+$lnext
+The smallest size
+for the $cref/det_minor/link_det_minor/$$ speed test
+was changed from one to two (a 2 by 2 matrix).
+$lend
+
+
+$head 04-30$$
+$list number$$
+The conditional expression example $cref cond_exp.cpp$$ was improved.
+$lnext
+Restore the
+$cref/
+    sparse_rcv copy constructor
+    /sparse_rcv
+    /other
+    /Assignment and Constructor
+/$$
+which was removed by mistake when the $code sparse_rcv$$
+move semantics constructor was added.
+$lend
+
+$head 04-28$$
+$list number$$
+The change to the $cref/pow(x,y)/pow/$$ function on
+$cref/02-06/whats_new_21/02-06/$$ handled the case where $icode x$$ is zero.
+The $cref pow_nan.cpp$$ example was modified to show when the new
+version of this function generates nans.
+$lnext
+Remove some uses of the deprecated
+$cref/nan(zero)/nan/nan(zero)/ Deprecated 2015-10-04/$$ function.
+$lend
+
+$head 04-27$$
+Fix the msys2 and cygwin system builds so that they use static
+(instead of dynamic) libraries.
+This is necessary so that static variables (in include files) can not have
+multiple instances in Windows.
+
+$head 04-26$$
+There was a problem with the $cref cmake$$ command when
+$cref ipopt$$ was the only optional package installed.
+This was related to the ipopt
+$cref/include directories/ipopt/Include Directories/$$ problem.
+
+$head 04-16$$
+Improve the instruction for adding a new speed test package; see
+$cref speed_xpackage$$.
+
+$head 04-09$$
+The $cref cpp_graph_print$$ operation was failing when there were
+atomic or discrete functions. This has been fixed.
+
+$head 04-07$$
+Documentation was added for the
+$cref/print_graph_op/cpp_ad_graph/operator_arg/print_graph_op/$$ operator.
+This is different from the function
+$cref cpp_graph_print$$ which prints an entire graph.
+
+
+$head 04-05$$
+The $cref cpp_graph_print$$ operation was modified so that it printed the
+text corresponding to atomic function names, discrete function names,
+and print operators.
+
+$head 04-02$$
+The enum value $code dis_graph_op$$ was corrected to $code discrete_graph_op$$
+in the documentation for
+$cref/discrete_graph_op/cpp_ad_graph/operator_arg/discrete_graph_op/$$.
+
+
+$head 03-29$$
+Include the $cref/dependent_vec/cpp_ad_graph/dependent_vec/$$
+in the output of $cref cpp_graph_print$$; see $code y nodes$$ in
+$cref print_graph.cpp$$ example output.
+
+$head 03-24$$
+The C++ AD graph constructor, $cref cpp_graph_ctor$$,
+cannot be called the first tile in parallel mode.
+This condition has been added to the documentation
+and assets were added to make sure it is true.
+
+$head 03-11$$
+Improve the discussion of identically equal; see
+$cref/more complicated case/base_identical/EqualOpSeq/More Complicated Case/$$.
+
+$head 03-09$$
+Simplify the $cref fabs.cpp$$ example.
+
+$head 03-08$$
+For years the following comment in reverse.hpp was forgotten:
+$codei%
+    // ? should use += here, first make test to demonstrate bug
+%$$
+A test case was created to demonstrate this bug and it was fixed
+(see $code duplicate_dependent_var$$ in $code test_more/general/reverse.cpp$$).
+This only affects reverse mode when
+$cref/w/reverse_any/w/$$ has size $icode%q% * %m%$$ and
+two of the dependent variables in the range of $icode f$$
+are identically equal (actually the same variable).
+
+$head 03-07$$
+$list number$$
+Fix bug in $cref/f.to_graph/to_graph/$$ that ocurred
+when $icode f$$ had $code fabs$$ dynamic parameter operators.
+To be more specific, if $code NDEBUG$$ was not defined,
+an error from an unknown source would be detected in the file $code to_graph.hpp$$.
+$lnext
+Make $cref UnaryMinus$$ an atomic operation,
+instead of using binary subtraction of zero minus the value being negated.
+In addition, add it to the $cref/json_graph unary operators/json_graph_op/Unary Operators/$$ and
+the $cref/graph_op_enum values/graph_op_enum/Enum Values/$$ values.
+$lend
+
+$head 02-21$$
+Add specifications for what is conditionally installed by the
+$cref/include_eigen/cmake/include_eigen/$$ and
+$cref/include_ipopt/cmake/include_ipopt/$$ options.
+In addition, make it clearer that
+$cref/include_cppadcg/cmake/include_cppadcg/$$ should only be used for testing.
+
+$head 02-16$$
+There was a problem with atomic functions, $cref optimize$$, and reverse mode
+that would lead to unexpected nans.
+This has been fixed by changing values,
+that the optimizer determines are not used, from nan to zero.
+A discussion of this was added below
+$cref/azmul/atomic_three_reverse/partial_x/azmul/$$
+in the atomic reverse documentation.
+
+$head 02-14$$
+$list number$$
+Add the $cref/print/cpp_graph_print/$$ command to the
+$code cpp_graph$$ class.
+$lnext
+Change the name of a documentation section form $code seq_property$$
+to $cref fun_property$$.
+$lnext
+Add setting and getting a $code ADFun$$ function's
+$cref/name/function_name/$$.
+$lend
+
+$head 02-12$$
+$list number$$
+In the case where
+$cref/cppad_debug_which/cmake/cppad_debug_which/$$ is
+$code debug_all$$ ($code debug_none$$) the corresponding
+$icode CMAKE_BUILD_TYPE$$ is now specified as
+$code Debug$$ ($code Release$$).
+$lnext
+Fix the $code Policy CMP0054$$ warning during the
+$cref/cmake command/cmake/CMake Command/$$.
+$lnext
+Fix the $cref/Visual Studio/cmake/CMake Command/Visual Studio/$$ build.
+This included commenting out part of the CppAD vector test
+because the MSC compiler is confused between the vector's const_iterator and
+iterator; see $code # ifndef _MSC_VER$$ in $cref cppad_vector.cpp$$.
+$lend
+
+$head 02-11$$
+Fix some problems with the linking of the $code cppad_lib$$ library
+when using the Microsoft compiler.
+
+$head 02-08$$
+Fix some problems in the
+$cref/cppad.pc/pkgconfig/cppad.pc/$$ file; see pull request
+$href%https://github.com/coin-or/CppAD/pull/95/files%95%$$.
+
+$head 02-06$$
+A special version of the $cref/pow(x, y)/pow/$$ function was added
+for the special case where $icode y$$ is a parameter.
+This properly handles the special case where $icode x$$ is zero
+and $icode y$$ is greater than the order of the derivative.
+In addition, it only requires one tape variable (instead of three)
+for each $code pow$$ operation.
+
+$head 01-27$$
+There was a bug in the converting to abs_normal form when
+the function $cref/f/abs_normal_fun/f/$$ made use of the
+$cref pow$$ operator.
+To be specific, when compiling without $code NDEBUG$$ defined,
+an assert was generated even though the code was correct.
+This has been fixed.
+
+$head 01-26$$
+Change the prototype for the cmake command
+$cref/options/cmake/CMake Command/Options/$$ to use $icode true_or_false$$,
+instead of $code true$$ to highlight the fact that one can choose either
+true or false.
+
+$head 01-08$$
+On some systems, the file $code cppad_lib/json_lexer.cpp$$ would not compile
+because the $code std::isdigit$$ function was not defined.
+This has been fixed.
+
+$head 01-07$$
+The example $cref pow_nan.cpp$$ was added.
+
+$head 01-05$$
+$list number$$
+Improve discussion of $cref/cppad_cxx/cmake/cppad_cxx_flags/$$
+and make sure all uses are exactly as described.
+In addition, change mention of optional features from C++11 to C++17.
+$lnext
+The required version of $cref cmake$$ was advanced from 2.8.4 to 3.0.
+This fixes a policy CMP0042 warning on Mac systems.
+$lnext
+If the compiler, plus the flags in
+$cref/cppad_cxx_flags/cmake/cppad_cxx_flags/$$,
+does not by default support C++11, cmake is used
+to find and add the flags necessary for this support.
+$lend
+
+$head 01-03$$
+$list number$$
+Fix a bug in $cref reverse$$ mode for an
+$codei%ADFun< AD<%Base%> >%$$ function that has
+$cref/dynamic/Independent/dynamic/$$ parameters and
+value of one of these parameters was zero or one when the function
+was recorded.
+$lnext
+Fix a bug in the $cref autotools$$ building of $code cppad_lib$$.
+$lend
+
+$end
diff --git a/omh/appendix/whats_new/22.omh b/omh/appendix/whats_new/22.omh
new file mode 100644
index 000000000..c0c6f8228
--- /dev/null
+++ b/omh/appendix/whats_new/22.omh
@@ -0,0 +1,171 @@
+/* --------------------------------------------------------------------------
+CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
+
+  CppAD is distributed under the terms of the
+               Eclipse Public License Version 2.0.
+
+  This Source Code may also be made available under the following
+  Secondary License when the conditions 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 whats_new_22$$
+$spell
+    CppAD
+    op
+    neg
+    mul
+    div
+    iterator
+    iterators
+    cppad_lib
+    hpp
+    rc
+    json
+    cmake
+    nx
+$$
+
+$section Changes and Additions to CppAD During 2022$$
+
+$head 02-26$$
+Change $code y(nx)$$ to $code y(ny)$$ in
+$cref  atomic_four_mat_mul_forward.cpp$$.
+
+$head 02-25$$
+$list number$$
+Fix $cref atomic_four_mat_mul$$ by changing it's base class
+from $code atomic_four<double>$$ to $codei%atomic_four<%Base%>%$$;
+see $cref atomic_four_mat_mul.hpp$$.
+$lnext
+Remove under construction warning from $cref atomic_four_mat_mul$$.
+$lnext
+Change $code atomic_vector$$ to $cref atomic_four_vector$$.
+$lend
+
+$head 02-24$$
+Fix $cref atomic_four_vector$$ by changing it's base class
+from $code atomic_four<double>$$ to $codei%atomic_four<%Base%>%$$.
+Make some other similar corrections in $cref atomic_four_vector.hpp$$.
+
+$head 02-23$$
+Improve error detection and message when both
+$cref/cmake_build_type/cmake/cmake_build_type/$$ and
+$cref/cppad_debug_which/cmake/cppad_debug_which/$$ are chosen
+during the install procedure.
+
+$head 02-21$$
+Extend the json graph representation to include
+$cref/atomic four/json_graph_op/Atomic Functions/Atomic Four/$$ functions.
+For example, see $cref json_atom4_op.cpp$$.
+
+$head 02-19$$
+Extend the C++ graph representation to include atomic four
+$cref/atomic functions/graph_op_enum/Atomic Function/$$.
+For example, see $cref graph_atom4_op.cpp$$.
+
+$head 02-18$$
+Fixed the value of $icode%after%[%i%]%$$ in the
+$cref/print_graph_op/cpp_ad_graph/operator_arg/print_graph_op/$$ documentation.
+To be specific, $code - 2$$ was changed to $code - 1$$.
+
+$head 02-17$$
+Add $code identical_zero$$ to the possible
+$cref/ad_type/atomic_four_for_type/ad_type/$$ values in
+the atomic four $code for_type$$ function.
+See $cref atomic_four_vector_for_type.hpp$$,
+$cref atomic_four_mat_mul_for_type.hpp$$, and
+$cref atomic_four_mat_mul_identical_zero.cpp$$
+for an examples using this feature.
+
+$head 02-16$$
+Use the $cref atomic_four_norm_sq.cpp$$ overrides
+as examples for the virtual functions in the $cref atomic_four$$
+base class.
+
+$head 02-13$$
+$list number$$
+The $cref atomic_four_mat_mul$$ example class was added.
+$lnext
+The $cref atomic_four_vector$$ include path has changed to
+$codei%
+    # include <cppad/example/atomic_four/vector.hpp>
+%$$
+$lend
+
+$head 02-12$$
+Add the $cref/push_back/sparse_rc/push_back/$$ and
+output stream (see $cref/os/sparse_rc/os/$$) operations
+to the $code sparse_rc$$ template class.
+
+$head 02-11$$
+The value of $code Libs:$$ in the $code cppad.pc$$ $cref pkgconfig$$ file
+was not being set correctly for some cases. This has been fixed.
+
+$head 02-01$$
+Fix a possible integer overflow in the $cref to_string.cpp$$ example
+(might cause the test to fail).
+
+$head 01-27$$
+Convert $cref atomic_four_forward.cpp$$ from an atomic_three
+to an atomic_four example.
+
+$head 01-25$$
+Convert $cref atomic_four_dynamic.cpp$$ from an atomic_three
+to an atomic_four example.
+
+$head 01-23$$
+$list number$$
+Add $cref atomic_four$$, a simpler interface to atomic functions.
+This has the optional $cref/call_id/atomic_four_call/call_id/$$ argument
+which can be used to attach extra information to an atomic function call.
+$lnext
+The $cref atomic_four_vector$$ is a good example that uses
+$icode call_id$$ to specify which
+element by element operator is being called; see
+$cref/call_id/atomic_four_vector/op/$$.
+$lnext
+Remove element-by-element atomic operations from $cref wish_list$$
+(completed by the atomic_vector class).
+$lend
+
+
+$head 01-19$$
+Edit wish_list cppad_lib
+$cref/requirement/wish_list/cppad_lib/Requirement/$$ item.
+Add an $cref/atomic functions/wish_list/Optimization/Atomic Functions/$$
+item to the optimization wish list.
+
+$head 01-15$$
+$list number$$
+Fix some conversion warnings generated by the clang compiler
+for the $cref atomic_four_vector$$ example.
+$lnext
+Correct the order of p, q in function calls in
+$cref atomic_four_vector_forward_op.hpp$$.
+$lend
+
+$head 01-06$$
+$list number$$
+Fix the $code []$$ operator using CppAD vector
+$cref/iterators/CppAD_vector/Iterators/operator[]/$$.
+In addition it was extended to include $code size_t$$ indices.
+$lnext
+Add reverse mode to the $cref atomic_four_vector$$,  mul, div, operators
+and fix some warning used $code size_t$$ iterator indices.
+$lend
+
+$head 01-04$$
+$list number$$
+Add the neg operator to $cref atomic_four_vector$$.
+$lnext
+Add reverse mode to the atomic_vector,  add, sub, and neg operators.
+$lend
+
+$head 01-01$$
+The $code example/atomic_three/vector_op.cpp$$ example
+(see $cref atomic_four_vector$$) was split into multiple files and moved into the
+$code example/atomic_vector$$ directory.
+
+$end
diff --git a/omh/appendix/whats_new/whats_new.omh b/omh/appendix/whats_new/whats_new.omh
index 4c7d36292..a21d983e0 100644
--- a/omh/appendix/whats_new/whats_new.omh
+++ b/omh/appendix/whats_new/whats_new.omh
@@ -1,5 +1,5 @@
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 Bradley M. Bell
+CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
 
   CppAD is distributed under the terms of the
                Eclipse Public License Version 2.0.
@@ -27,6 +27,8 @@ The purpose of these sections is to
 assist you in learning about changes between various versions of CppAD.
 
 $children%
+    omh/appendix/whats_new/22.omh%
+    omh/appendix/whats_new/21.omh%
     omh/appendix/whats_new/20.omh%
     omh/appendix/whats_new/19.omh%
     omh/appendix/whats_new/18.omh%
@@ -48,9 +50,11 @@ $children%
 %$$
 
 $head This Year$$
-$cref/2020/whats_new_20/$$
+$cref/2022/whats_new_22/$$
 
 $head Previous Years$$
+$cref/2021/whats_new_21/$$,
+$cref/2020/whats_new_20/$$,
 $cref/2019/whats_new_19/$$,
 $cref/2018/whats_new_18/$$,
 $cref/2017/whats_new_17/$$,
diff --git a/omh/appendix/wish_list.omh b/omh/appendix/wish_list.omh
index c279ba6b5..da5a3c1b4 100644
--- a/omh/appendix/wish_list.omh
+++ b/omh/appendix/wish_list.omh
@@ -1,5 +1,5 @@
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 Bradley M. Bell
+CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
 
   CppAD is distributed under the terms of the
                Eclipse Public License Version 2.0.
@@ -11,6 +11,7 @@ CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 Bradley M. Bell
 -------------------------------------------------------------------------- */
 $begin wish_list$$
 $spell
+    Taylor
     Subgraphs
     subgraph
     Jacobians
@@ -86,8 +87,10 @@ and the function above would return $code nan$$ for the derivative value.
 This may also be faster that using $code azmul$$.
 
 $head Atomic Examples$$
-Convert the remaining $cref/atomic_two_examples/atomic_two_example/$$
-to use the $cref atomic_three$$ interface.
+Convert the remaining
+$cref/atomic_two_examples/atomic_two_example/$$, and
+$cref/atomic_three_examples/atomic_three_example/$$
+to use the $cref atomic_four$$ interface.
 
 $comment ------------------------------------------------------------------- $$
 $head Abs-normal$$
@@ -119,8 +122,9 @@ $head cppad_lib$$
 $subhead Requirement$$
 Currently $code cppad_lib$$ library is only needed if one uses
 $cref/colpack/colpack_prefix/$$,
-$cref json_ad_graph$$, or
-$cref cpp_ad_graph$$.
+$cref json_ad_graph$$,
+$cref cpp_ad_graph$$, or
+$cref code_gen_fun$$..
 
 $subhead inline$$
 The C++ $code inline$$ specifier is used to avoid multiple copies
@@ -183,11 +187,6 @@ These sparsity patterns could be made more efficient
 by using the sparsity patterns for the atomic functions.
 
 $comment ------------------------------------------------------------------- $$
-$head Element-wise Atomic Operations$$
-Add atomic functions for element-wise addition, subtraction,
-multiplication, and division.
-Where the operands are $cref/simple vectors/SimpleVector/$$
-with elements of type $codei%AD<%Base%>%$$.
 
 $head check_finite$$
 $list number$$
@@ -214,6 +213,15 @@ into separate groups by the corresponding example subdirectory.
 $comment ----------------------------------------------------------------- $$
 $head Optimization$$
 
+$subhead Atomic Functions$$
+There is some confusion as to the value of the Taylor coefficients
+for atomic function arguments and results that have been optimized out.
+See $cref/atomic functions/optimize/Atomic Functions/$$ in optimize,
+$cref/02-16/whats_new_21/02-16/$$ in whats new for 2021,
+$cref/optimize/atomic_three_rev_depend/depend_x/Optimize/$$
+in atomic_three, and
+$cref/optimize/atomic_four_rev_depend/depend_x/Optimize/$$ in atomic_four.
+
 $subhead Taping$$
 Perhaps some of the optimization done while taping forward mode
 should be delayed to the $code optimization$$ step.
diff --git a/omh/base_require/base_identical.omh b/omh/base_require/base_identical.omh
index 31fc128aa..d9f3f9aa1 100644
--- a/omh/base_require/base_identical.omh
+++ b/omh/base_require/base_identical.omh
@@ -1,5 +1,5 @@
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-18 Bradley M. Bell
+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.
@@ -57,15 +57,19 @@ namespace CppAD {
 For example, see
 $cref/base_alloc/base_alloc.hpp/EqualOpSeq/$$.
 
-$subhead More Complicated Cases$$
+$subhead More Complicated Case$$
 The variables
-$icode u$$ and $icode v$$ are not identically equal in the following case
-(which CppAD automatically defines $code EqualOpSeq$$ for):
-The type $icode Base$$ is $codei%AD<double>%$$,
-$icode x[0] = x[1] = 1.$$,
-then $cref independent$$ is used to make $icode x$$ the independent
-variable vector,
-and then $icode u = x[0]$$, $icode v = x[1]$$,
+$icode u$$ and $icode v$$ are not identically equal in the following case:
+$list number$$
+The type $icode Base$$ is $codei%AD<double>%$$.
+$lnext
+The following assignment made using type $icode Base$$: $icode x[0] = x[1] = 1.$$,
+$lnext
+The $cref independent$$ operations is used to make $icode x$$
+the independent variable vector,
+$lnext
+During the corresponding recording, $icode u = x[0]$$, $icode v = x[1]$$.
+$lend
 Note that during a future $cref Forward$$ calculation,
 $icode u$$ and $icode v$$ could correspond to different values.
 For example, see
@@ -77,18 +81,8 @@ $subhead IdenticalCon$$
 A $icode Base$$ object is a
 $cref/constant/glossary/Parameter/Constant/$$ parameter
 when used in an $codei%AD<%Base%>%$$ operation sequence.
-It is however still possible for a parameter to change its value.
-For example,
-the $icode Base$$ value $icode u$$ is not identically constant
-in the following case
-(which CppAD automatically defines $code IdenticalCon$$ for):
-The type $icode Base$$ is $codei%AD<double>%$$,
-$icode x[0] = 1.$$,
-then $cref independent$$ is used to make $icode x$$ the independent
-variable vector,
-and then $icode u = x[0]$$,
-Note that during a future $cref Forward$$ calculation,
-$icode u$$ could correspond to different values.
+It is however still possible for a parameter to change its value; e.g.,
+see the more complicated case above.
 
 $subhead Prototypes$$
 The argument $icode u$$ has prototype
diff --git a/omh/cppad.omh b/omh/cppad.omh
index f8cf88bfa..1420b8b53 100644
--- a/omh/cppad.omh
+++ b/omh/cppad.omh
@@ -1,6 +1,6 @@
 $comment
 -----------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-21 Bradley M. Bell
+CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
 
   CppAD is distributed under the terms of the
                Eclipse Public License Version 2.0.
@@ -65,7 +65,7 @@ $$
 
 $comment bin/version assumes that : follows cppad version number here$$
 $section
-cppad-20210000.8: A C++ Algorithmic Differentiation Package$$
+cppad-20220327: A C++ Algorithmic Differentiation Package$$
 
 $comment =================================================================== $$
 $align middle$$
@@ -77,8 +77,8 @@ $comment ------------------------------------------------------------------- $$
 $table
 $href%https://github.com/coin-or/CppAD/releases%
     releases%$$, $cnext
-$href%https://github.com/coin-or/CppAD/archive/20210000.0.tar.gz%
-    20210000.0%$$, $cnext
+$href%https://github.com/coin-or/CppAD/archive/20220000.2.tar.gz%
+    20220000.2%$$, $cnext
 $href%https://github.com/coin-or/CppAD%
     github%$$, $cnext
 $href%https://travis-ci.org/coin-or/CppAD%
diff --git a/omh/devel/devel.omh b/omh/devel/devel.omh
index 4f1fa9130..5080d264c 100644
--- a/omh/devel/devel.omh
+++ b/omh/devel/devel.omh
@@ -1,5 +1,5 @@
 -----------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
+CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
 
   CppAD is distributed under the terms of the
                Eclipse Public License Version 2.0.
@@ -30,7 +30,10 @@ $childtable%
     include/cppad/utility/omh/dev_utility.omh%
     include/cppad/local/op_code_var.hpp%
     omh/devel/vec_ad.omh%
-    include/cppad/local/is_pod.hpp
+    include/cppad/local/is_pod.hpp%
+    include/cppad/local/op/unary_op.omh%
+    include/cppad/local/op/binary_op.omh%
+    include/cppad/core/atomic/four/devel/devel.omh
 %$$
 
 
diff --git a/omh/devel/vec_ad.omh b/omh/devel/vec_ad.omh
index 5036a9159..86514be92 100644
--- a/omh/devel/vec_ad.omh
+++ b/omh/devel/vec_ad.omh
@@ -1,5 +1,5 @@
 -----------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 Bradley M. Bell
+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.
@@ -18,8 +18,8 @@ $section Developer Documentation for VecAD Operations$$
 
 $childtable%
     include/cppad/core/vec_ad/vec_ad.hpp%
-    include/cppad/local/load_op.hpp%
-    include/cppad/local/store_op.hpp
+    include/cppad/local/op/load_op.hpp%
+    include/cppad/local/op/store_op.hpp
 %$$
 
 
diff --git a/omh/example_list.omh b/omh/example_list.omh
index 019ec7ae1..6ddad00bb 100644
--- a/omh/example_list.omh
+++ b/omh/example_list.omh
@@ -1,5 +1,5 @@
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
+CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
 
   CppAD is distributed under the terms of the
                Eclipse Public License Version 2.0.
@@ -22,6 +22,8 @@ $$
 
 $comment BEGIN_SORT_THIS_LINE_PLUS_2$$
 $table
+$rref AddEq.cpp$$
+$rref Rombergmul.cpp$$
 $rref a11c_bthread.cpp$$
 $rref a11c_openmp.cpp$$
 $rref a11c_pthread.cpp$$
@@ -37,17 +39,45 @@ $rref acos.cpp$$
 $rref acosh.cpp$$
 $rref ad_assign.cpp$$
 $rref ad_ctor.cpp$$
-$rref add.cpp$$
-$rref AddEq.cpp$$
 $rref ad_fun.cpp$$
 $rref ad_in_c.cpp$$
 $rref ad_input.cpp$$
 $rref ad_output.cpp$$
+$rref add.cpp$$
 $rref asin.cpp$$
 $rref asinh.cpp$$
-$rref atan2.cpp$$
 $rref atan.cpp$$
+$rref atan2.cpp$$
 $rref atanh.cpp$$
+$rref atomic_four_dynamic.cpp$$
+$rref atomic_four_forward.cpp$$
+$rref atomic_four_get_started.cpp$$
+$rref atomic_four_mat_mul_forward.cpp$$
+$rref atomic_four_mat_mul_identical_zero.cpp$$
+$rref atomic_four_mat_mul_rev_depend.cpp$$
+$rref atomic_four_mat_mul_reverse.cpp$$
+$rref atomic_four_mat_mul_sparsity.cpp$$
+$rref atomic_four_norm_sq.cpp$$
+$rref atomic_four_vector.hpp$$
+$rref atomic_four_vector_add.cpp$$
+$rref atomic_four_vector_add_op.hpp$$
+$rref atomic_four_vector_div.cpp$$
+$rref atomic_four_vector_div_op.hpp$$
+$rref atomic_four_vector_for_type.hpp$$
+$rref atomic_four_vector_forward_op.hpp$$
+$rref atomic_four_vector_hes_sparsity.cpp$$
+$rref atomic_four_vector_hes_sparsity.hpp$$
+$rref atomic_four_vector_jac_sparsity.cpp$$
+$rref atomic_four_vector_jac_sparsity.hpp$$
+$rref atomic_four_vector_mul.cpp$$
+$rref atomic_four_vector_mul_op.hpp$$
+$rref atomic_four_vector_neg.cpp$$
+$rref atomic_four_vector_neg_op.hpp$$
+$rref atomic_four_vector_rev_depend.cpp$$
+$rref atomic_four_vector_rev_depend.hpp$$
+$rref atomic_four_vector_reverse_op.hpp$$
+$rref atomic_four_vector_sub.cpp$$
+$rref atomic_four_vector_sub_op.hpp$$
 $rref atomic_three_base2ad.cpp$$
 $rref atomic_three_dynamic.cpp$$
 $rref atomic_three_forward.cpp$$
@@ -85,21 +115,21 @@ $rref chkpoint_two_compare.cpp$$
 $rref chkpoint_two_dynamic.cpp$$
 $rref chkpoint_two_get_started.cpp$$
 $rref chkpoint_two_ode.cpp$$
+$rref code_gen_fun_file.cpp$$
+$rref code_gen_fun_function.cpp$$
+$rref code_gen_fun_jac_as_fun.cpp$$
+$rref code_gen_fun_jacobian.cpp$$
+$rref code_gen_fun_sparse_jac_as_fun.cpp$$
+$rref code_gen_fun_sparse_jacobian.cpp$$
 $rref colpack_hes.cpp$$
 $rref colpack_hessian.cpp$$
 $rref colpack_jac.cpp$$
 $rref colpack_jacobian.cpp$$
-$rref compare_change.cpp$$
 $rref compare.cpp$$
-$rref code_gen_fun_file.cpp$$
-$rref code_gen_fun_function.cpp$$
-$rref code_gen_fun_jacobian.cpp$$
-$rref code_gen_fun_jac_as_fun.cpp$$
-$rref code_gen_fun_sparse_jacobian.cpp$$
-$rref code_gen_fun_sparse_jac_as_fun.cpp$$
+$rref compare_change.cpp$$
 $rref complex_poly.cpp$$
-$rref cond_exp.cpp$$
 $rref con_dyn_var.cpp$$
+$rref cond_exp.cpp$$
 $rref conj_grad.cpp$$
 $rref cos.cpp$$
 $rref cosh.cpp$$
@@ -115,8 +145,8 @@ $rref eigen_array.cpp$$
 $rref eigen_det.cpp$$
 $rref elapsed_seconds.cpp$$
 $rref equal_op_seq.cpp$$
-$rref erfc.cpp$$
 $rref erf.cpp$$
+$rref erfc.cpp$$
 $rref error_handler.cpp$$
 $rref exp.cpp$$
 $rref expm1.cpp$$
@@ -134,9 +164,12 @@ $rref forward_order.cpp$$
 $rref from_json.cpp$$
 $rref fun_assign.cpp$$
 $rref fun_check.cpp$$
+$rref fun_property.cpp$$
+$rref function_name.cpp$$
 $rref general.cpp$$
 $rref get_started.cpp$$
 $rref graph_add_op.cpp$$
+$rref graph_atom4_op.cpp$$
 $rref graph_atom_op.cpp$$
 $rref graph_azmul_op.cpp$$
 $rref graph_cexp_op.cpp$$
@@ -153,8 +186,8 @@ $rref harmonic.cpp$$
 $rref hes_lagrangian.cpp$$
 $rref hes_lu_det.cpp$$
 $rref hes_minor_det.cpp$$
-$rref hessian.cpp$$
 $rref hes_times_dir.cpp$$
+$rref hessian.cpp$$
 $rref independent.cpp$$
 $rref index_sort.cpp$$
 $rref integer.cpp$$
@@ -168,6 +201,7 @@ $rref jac_lu_det.cpp$$
 $rref jac_minor_det.cpp$$
 $rref jacobian.cpp$$
 $rref json_add_op.cpp$$
+$rref json_atom4_op.cpp$$
 $rref json_atom_op.cpp$$
 $rref json_azmul_op.cpp$$
 $rref json_cexp_op.cpp$$
@@ -182,9 +216,9 @@ $rref json_sparse.cpp$$
 $rref json_sub_op.cpp$$
 $rref json_sum_op.cpp$$
 $rref json_unary_op.cpp$$
+$rref log.cpp$$
 $rref log10.cpp$$
 $rref log1p.cpp$$
-$rref log.cpp$$
 $rref lp_box.cpp$$
 $rref lp_box.hpp$$
 $rref lu_factor.cpp$$
@@ -199,9 +233,9 @@ $rref min_nso_quad.cpp$$
 $rref min_nso_quad.hpp$$
 $rref mul.cpp$$
 $rref mul_eq.cpp$$
+$rref mul_level.cpp$$
 $rref mul_level_adolc.cpp$$
 $rref mul_level_adolc_ode.cpp$$
-$rref mul_level.cpp$$
 $rref mul_level_ode.cpp$$
 $rref multi_atomic_three.cpp$$
 $rref multi_atomic_two.cpp$$
@@ -212,15 +246,16 @@ $rref nan.cpp$$
 $rref near_equal.cpp$$
 $rref near_equal_ext.cpp$$
 $rref new_dynamic.cpp$$
+$rref num_limits.cpp$$
 $rref number_skip.cpp$$
 $rref numeric_type.cpp$$
-$rref num_limits.cpp$$
 $rref ode_err_control.cpp$$
 $rref ode_err_maxabs.cpp$$
 $rref ode_evaluate.cpp$$
-$rref ode_gear_control.cpp$$
 $rref ode_gear.cpp$$
+$rref ode_gear_control.cpp$$
 $rref ode_stiff.cpp$$
+$rref opt_val_hes.cpp$$
 $rref optimize_compare_op.cpp$$
 $rref optimize_conditional_skip.cpp$$
 $rref optimize_cumulative_sum.cpp$$
@@ -229,33 +264,32 @@ $rref optimize_nest_conditional.cpp$$
 $rref optimize_print_for.cpp$$
 $rref optimize_reverse_active.cpp$$
 $rref optimize_twice.cpp$$
-$rref opt_val_hes.cpp$$
 $rref poly.cpp$$
 $rref pow.cpp$$
 $rref pow_int.cpp$$
+$rref pow_nan.cpp$$
 $rref print_for_cout.cpp$$
 $rref print_for_string.cpp$$
+$rref print_graph.cpp$$
 $rref qp_box.cpp$$
 $rref qp_box.hpp$$
 $rref qp_interior.cpp$$
 $rref qp_interior.hpp$$
 $rref rc_sparsity.cpp$$
 $rref rev_checkpoint.cpp$$
-$rref reverse_one.cpp$$
-$rref reverse_three.cpp$$
-$rref reverse_two.cpp$$
 $rref rev_hes_sparsity.cpp$$
 $rref rev_jac_sparsity.cpp$$
 $rref rev_one.cpp$$
 $rref rev_sparse_hes.cpp$$
 $rref rev_sparse_jac.cpp$$
 $rref rev_two.cpp$$
-$rref Rombergmul.cpp$$
+$rref reverse_one.cpp$$
+$rref reverse_three.cpp$$
+$rref reverse_two.cpp$$
 $rref romberg_one.cpp$$
 $rref rosen_34.cpp$$
 $rref runge45_1.cpp$$
 $rref runge_45.cpp$$
-$rref seq_property.cpp$$
 $rref set_union.cpp$$
 $rref simple_ad_bthread.cpp$$
 $rref simple_ad_openmp.cpp$$
@@ -271,8 +305,8 @@ $rref sparse_hes_fun.cpp$$
 $rref sparse_hessian.cpp$$
 $rref sparse_jac_for.cpp$$
 $rref sparse_jac_fun.cpp$$
-$rref sparse_jacobian.cpp$$
 $rref sparse_jac_rev.cpp$$
+$rref sparse_jacobian.cpp$$
 $rref sparse_rc.cpp$$
 $rref sparse_rcv.cpp$$
 $rref sparse_sub_hes.cpp$$
@@ -284,11 +318,11 @@ $rref sqrt.cpp$$
 $rref stack_machine.cpp$$
 $rref sub.cpp$$
 $rref sub_eq.cpp$$
+$rref sub_sparse_hes.cpp$$
 $rref subgraph_hes2jac.cpp$$
 $rref subgraph_jac_rev.cpp$$
 $rref subgraph_reverse.cpp$$
 $rref subgraph_sparsity.cpp$$
-$rref sub_sparse_hes.cpp$$
 $rref switch_var_dyn.cpp$$
 $rref tan.cpp$$
 $rref tanh.cpp$$
diff --git a/omh/install/autotools.omh b/omh/install/autotools.omh
index fe73ce585..61ab9527d 100644
--- a/omh/install/autotools.omh
+++ b/omh/install/autotools.omh
@@ -1,5 +1,5 @@
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
+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.
@@ -440,11 +440,11 @@ $codei%
     std::numeric_limits<%tape_addr_type%>::max()
 %$$
 must be larger than any of the following:
-$cref/size_op/seq_property/size_op/$$,
-$cref/size_op_arg/seq_property/size_op_arg/$$,
-$cref/size_par/seq_property/size_text/$$,
-$cref/size_par/seq_property/size_par/$$,
-$cref/size_par/seq_property/size_VecAD/$$.
+$cref/size_op/fun_property/size_op/$$,
+$cref/size_op_arg/fun_property/size_op_arg/$$,
+$cref/size_par/fun_property/size_text/$$,
+$cref/size_par/fun_property/size_par/$$,
+$cref/size_par/fun_property/size_VecAD/$$.
 
 
 $head tape_id_type$$
diff --git a/omh/install/cmake.omh b/omh/install/cmake.omh
index 3cd47394b..60f3d1bea 100644
--- a/omh/install/cmake.omh
+++ b/omh/install/cmake.omh
@@ -1,5 +1,5 @@
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
+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.
@@ -13,6 +13,7 @@ CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
 $begin cmake$$
 $escape $$
 $spell
+    Rel
     cppadcg
     msys
     Hsc
@@ -131,6 +132,7 @@ The full version of the command, with all its optional arguments is:
 $codei%
 cmake %%                                                                     \
     -D CMAKE_VERBOSE_MAKEFILE=%cmake_verbose_makefile%                       \
+    -D CMAKE_BUILD_TYPE=%cmake_build_type%                                   \
     -G %generator%                                                           \
     \
     -D cppad_prefix=%cppad_prefix%                                           \
@@ -142,10 +144,10 @@ cmake %%                                                                     \
     -D cmake_install_datadir=%cmake_install_datadir%                         \
     -D cmake_install_docdir=%cmake_install_docdir%                           \
     \
-    -D include_adolc=true                                                    \
-    -D include_eigen=true                                                    \
-    -D include_ipopt=true                                                    \
-    -D include_cppadcg=true
+    -D include_adolc=%true_or_false%                                         \
+    -D include_eigen=%true_or_false%                                         \
+    -D include_ipopt=%true_or_false%                                         \
+    -D include_cppadcg=%true_or_false%                                       \
     \
     -D colpack_prefix=%colpack_prefix%                                       \
     -D fadbad_prefix=%fadbad_prefix%                                         \
@@ -206,6 +208,11 @@ $codep
     nmake check
 $$
 $lend
+Note that when using windows DLL's, CppAD builds a static version
+of $code cppad_lib$$. There are problems using a DLL for $code cppad_lib$$
+because Windows makes separate copies of static class member functions,
+one for library and one for the rest of the program.
+
 
 $subhead autotools$$
 The autotools build with the Visual Studio compiler should work
@@ -245,6 +252,16 @@ will include all of the files and flags used to run the compiler
 and linker. This can be useful for seeing how to compile and link
 your own applications.
 
+$head cmake_build_type$$
+This value should be one of the valid CMake build types; e.g.,
+$code Debug$$,
+$code Release$$,
+$code RelWithDebInfo$$,
+$code MinSizeRel$$.
+If this value is specified,
+$cref/cppad_debug_which/cmake/cppad_debug_which/$$
+must not be the empty string.
+
 $head generator$$
 The CMake program is capable of generating different kinds of files.
 Below is a table with a few of the possible files
@@ -370,29 +387,32 @@ If it is not specified, the documentation files are not installed.
 
 $head include_adolc$$
 The $cref adolc$$ examples
-will be compiled and tested if $icode include_adolc=true$$
+will be compiled and tested if $code include_adolc=true$$
 is in the command line.
 
 $head include_eigen$$
 The $cref eigen$$ examples
 will be compiled and tested if $code include_eigen=true$$
 is on the command line.
+In addition, the $cref sparse2eigen$$ utility will be installed.
 
 $head include_ipopt$$
 The $cref ipopt$$ examples
 will be compiled and tested if $code include_ipopt=true$$
 is on the command line.
+In addition, $cref ipopt_solve$$ and $cref cppad_ipopt_nlp$$
+will be installed.
 
 $head include_cppadcg$$
 The $cref cppadcg$$ examples
-will be compiled and tested if $code include_ipopt=true$$
+will be compiled and tested if $code include_cppadcg=true$$
 is on the command line.
 $bold Warning$$ :
 Do not use this option when installing cppad because
 the cppadcg package depends on cppad and using this option
 makes cppad depend on cppadcg.
-The script $cref get_cppadcg.sh$$ handles this confusion
-for testing purposes only.
+This option, and the script $cref get_cppadcg.sh$$ are only intended
+for testing purposes.
 
 $head package_prefix$$
 Each of these packages do not have $code pkg-config$$ files and
@@ -406,20 +426,21 @@ $rref sacado_prefix$$
 $tend
 
 $head cppad_cxx_flags$$
-This specifies the addition compiler flags
-that are used when compiling the CppAD examples and tests.
+This specifies the compiler flags
+that are used when compiling the CppAD examples, tests, and library.
+This flags are in addition to the flags automatically generated by
+cmake for debug and release build; i.e.,
+$icode CMAKE_CXX_FLAGS_DEBUG$$ and $icode CMAKE_CXX_FLAGS_RELEASE$$.
 The default value for these flags is the empty string $code ""$$.
 These flags must be valid for the C++ compiler
 on your system.
 For example, if you are using $code g++$$ you could specify
 $codep
-    -D cppad_cxx_flags="-Wall -ansi -pedantic-errors -std=c++11 -Wshadow"
+    -D cppad_cxx_flags="-Wall -ansi -pedantic-errors -std=c++17 -Wshadow"
 $$
-$subhead C++11$$
-In order for the compiler to take advantage of features that are new in C++11,
-the $icode cppad_cxx_flags$$ must enable these features.
-The compiler may still be used with a flag that disables the new features
-(unless it is a Microsoft compiler; i.e., $code _MSC_VER$$ is defined).
+$subhead C++17$$
+In order for the compiler to take advantage of features that are in C++17
+,but not in C++11, the $icode cppad_cxx_flags$$ must enable these features.
 
 $subhead debug and release$$
 The CppAD examples and tests decide which files to compile for debugging
@@ -500,11 +521,11 @@ $codei%
     std::numeric_limits<%cppad_tape_addr_type%>::max()
 %$$
 must be larger than any of the following:
-$cref/size_op/seq_property/size_op/$$,
-$cref/size_op_arg/seq_property/size_op_arg/$$,
-$cref/size_par/seq_property/size_par/$$,
-$cref/size_text/seq_property/size_text/$$,
-$cref/size_VecAD/seq_property/size_VecAD/$$.
+$cref/size_op/fun_property/size_op/$$,
+$cref/size_op_arg/fun_property/size_op_arg/$$,
+$cref/size_par/fun_property/size_par/$$,
+$cref/size_text/fun_property/size_text/$$,
+$cref/size_VecAD/fun_property/size_VecAD/$$.
 
 $subhead cstdint$$
 If all of the following $code cstdint$$ types are defined,
@@ -519,14 +540,16 @@ All of the CppAD examples and test can optionally be tested
 in debug or release mode (see exception below).
 This option controls which mode is chosen for the corresponding files.
 The value $icode cppad_debug_which$$ be one of the following:
-$code debug_even$$, $code debug_odd$$, $code debug_all$$, $code debug_none$$.
-If it is $code debug_even$$ ($code debug_odd$$),
-files with an even (old) index in a list for each case will be compiled
-in debug mode. The remaining files will be compiled in release mode.
-If it is $code debug_all$$ ($code debug_none$$),
-all the files will be compiled in debug (release) mode.
-If $icode cppad_debug_which$$ does not appear on the command line,
-the default value $code debug_all$$ is used.
+$table
+$icode cppad_debug_which$$ $cnext $icode CMAKE_BUILD_TYPE$$ $rnext
+$code debug_all$$          $cnext $code Debug$$             $rnext
+$code debug_none$$         $cnext $code Release$$           $rnext
+$code debug_even$$         $cnext not specified             $rnext
+$code debug_odd$$          $cnext not specified             $rnext
+empty string               $cnext not changed               $rnext
+$tend
+If $code CMAKE_BUILD_TYPE$$ is specified on the command line,
+then $icode cppad_debug_which$$ must be the empty string (its default value).
 
 $children%
     bin/get_optional.sh%
diff --git a/omh/install/ipopt.omh b/omh/install/ipopt.omh
index 00fb3d425..4e3c25358 100644
--- a/omh/install/ipopt.omh
+++ b/omh/install/ipopt.omh
@@ -1,4 +1,4 @@
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
+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.
@@ -19,6 +19,7 @@ $spell
     hpp
     config
     CppAD
+    cflags
 $$
 
 $section Including Ipopt Library Examples, Tests, and pkg-config$$
@@ -50,4 +51,11 @@ a copy of Ipopt using $cref get_ipopt.sh$$.
 The corresponding install prefix is
 $code build/prefix$$.
 
+$head Include Directories$$
+It may be necessary to remove $code /coin-or$$ from the end of the
+include directories reported by
+$codei%
+    pkg-config ipopt --cflags
+%$$
+
 $end
diff --git a/omh/multi_thread.omh b/omh/multi_thread.omh
index 18c0694bd..4acb31b16 100644
--- a/omh/multi_thread.omh
+++ b/omh/multi_thread.omh
@@ -1,5 +1,5 @@
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-17 Bradley M. Bell
+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.
@@ -16,6 +16,7 @@ $spell
     CppAD
     Rosen
     Runge
+    ctor
 $$
 
 $section Using CppAD in a Multi-Threading Environment$$
@@ -66,7 +67,8 @@ $cref/CheckSimpleVector/CheckSimpleVector/Parallel Mode/$$,
 $cref/CheckNumericType/CheckNumericType/Parallel Mode/$$,
 $cref/discrete functions/Discrete/Parallel Mode/$$,
 $cref/Rosen34/Rosen34/Parallel Mode/$$,
-$cref/Runge45/Runge45/Parallel Mode/$$.
+$cref/Runge45/Runge45/Parallel Mode/$$,
+$cref/cpp_graph_ctor/cpp_graph_ctor/Parallel Mode/$$.
 
 $head Same Thread$$
 Some operations must be preformed by the same thread:
diff --git a/omh/reverse/reverse_one.omh b/omh/reverse/reverse_one.omh
index 1368513fc..b79da8e4c 100644
--- a/omh/reverse/reverse_one.omh
+++ b/omh/reverse/reverse_one.omh
@@ -1,5 +1,5 @@
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-18 Bradley M. Bell
+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.
@@ -70,7 +70,7 @@ $codei%
 (see $cref/Vector/reverse_one/Vector/$$ below)
 and its size
 must be equal to $icode m$$, the dimension of the
-$cref/range/seq_property/Range/$$ space for $icode f$$.
+$cref/range/fun_property/Range/$$ space for $icode f$$.
 
 $head dw$$
 The result $icode dw$$ has prototype
@@ -81,7 +81,7 @@ $codei%
 and its value is the derivative $latex W^{(1)} (x)$$.
 The size of $icode dw$$
 is equal to $icode n$$, the dimension of the
-$cref/domain/seq_property/Domain/$$ space for $icode f$$.
+$cref/domain/fun_property/Domain/$$ space for $icode f$$.
 
 $head Vector$$
 The type $icode Vector$$ must be a $cref SimpleVector$$ class with
diff --git a/omh/reverse/reverse_two.omh b/omh/reverse/reverse_two.omh
index b6f6641ed..8706a7296 100644
--- a/omh/reverse/reverse_two.omh
+++ b/omh/reverse/reverse_two.omh
@@ -1,5 +1,5 @@
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-18 Bradley M. Bell
+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.
@@ -90,7 +90,7 @@ $codei%
 (see $cref/Vector/reverse_two/Vector/$$ below)
 and its size
 must be equal to $icode m$$, the dimension of the
-$cref/range/seq_property/Range/$$ space for $icode f$$.
+$cref/range/fun_property/Range/$$ space for $icode f$$.
 
 $head dw$$
 The result $icode dw$$ has prototype
@@ -103,7 +103,7 @@ $latex W^{(1)} (x)$$ and the derivative $latex U^{(1)} (x)$$.
 The size of $icode dw$$
 is equal to $latex n \times 2$$,
 where $latex n$$ is the dimension of the
-$cref/domain/seq_property/Domain/$$ space for $icode f$$.
+$cref/domain/fun_property/Domain/$$ space for $icode f$$.
 
 $subhead First Order Partials$$
 For $latex j = 0 , \ldots , n - 1$$,
diff --git a/omh/theory/forward_theory.omh b/omh/theory/forward_theory.omh
index 8d43e2af5..42f7c181b 100644
--- a/omh/theory/forward_theory.omh
+++ b/omh/theory/forward_theory.omh
@@ -1,5 +1,5 @@
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-17 Bradley M. Bell
+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.
@@ -157,20 +157,27 @@ $latex \[
     e^{(j)} = d^{(j)} + \sum_{k=0}^j a^{(j-k)} * z^{(k)}
 \] $$
 We need to complete the induction by finding formulas for $latex z^{(j+1)}$$.
-It follows for the formula for the
-$cref/multiplication/ForwardTheory/Binary Operators/Multiplication/$$
-operator that
+It follows from the definition of $latex E(t)$$ that
 $latex  \[
-\begin{array}{rcl}
-\left( \sum_{k=0}^j b^{(k)} t^k \right)
+\left( \sum_{k=0}^j b^{(k)} * t^k \right)
 *
 \left( \sum_{k=1}^{j+1} k z^{(k)} * t^{k-1} \right)
-& = &
+=
 \left( \sum_{k=0}^j e^{(k)} * t^k \right)
 *
 \left( \sum_{k=1}^{j+1} k x^{(k)} * t^{k-1} \right)
 +
 o( t^p )
+\] $$
+Setting the left and right side coefficients of $latex t^j$$ equal,
+and using the formula for
+$cref/multiplication/ForwardTheory/Binary Operators/Multiplication/$$,
+we obtain
+$latex  \[
+\begin{array}{rcl}
+\sum_{k=0}^j b^{(k)} (j+1-k) z^{(j+1-k)}
+& = &
+\sum_{k=0}^j e^{(k)} (j+1-k) x^{(j+1-k)}
 \\
 z^{(j+1)} & = & \frac{1}{j+1} \frac{1}{ b^{(0)} }
 \left(
@@ -189,8 +196,6 @@ This completes the induction that computes $latex e^{(j)}$$
 and $latex z^{(j+1)}$$.
 
 
-
-
 $children%
     omh/theory/exp_forward.omh%
     omh/theory/log_forward.omh%
@@ -200,7 +205,8 @@ $children%
     omh/theory/asin_forward.omh%
     omh/theory/acos_forward.omh%
     omh/theory/tan_forward.omh%
-    omh/theory/erf_forward.omh
+    omh/theory/erf_forward.omh%
+    omh/theory/pow_forward.omh
 %$$
 
 $subhead Cases that Apply Recursion Above$$
@@ -212,6 +218,7 @@ $rref sin_cos_forward$$
 $rref atan_forward$$
 $rref asin_forward$$
 $rref acos_forward$$
+$rref pow_forward$$
 $tend
 
 $subhead Special Cases$$
diff --git a/omh/theory/pow_forward.omh b/omh/theory/pow_forward.omh
new file mode 100644
index 000000000..0947da662
--- /dev/null
+++ b/omh/theory/pow_forward.omh
@@ -0,0 +1,116 @@
+/* --------------------------------------------------------------------------
+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 pow_forward$$
+$spell
+    Taylor
+$$
+
+$section Power Function Forward Mode Theory$$
+We consider the operation $latex F(x) = x^y$$ where $latex x$$
+is a variable and $latex y$$ is a parameter.
+
+$head Derivatives$$
+The corresponding derivative satisfies the equation
+$latex \[
+x * F^{(1)} (x) -  y F(x) = 0
+\] $$
+This is the
+$cref/standard math function differential equation
+    /ForwardTheory
+    /Standard Math Functions
+    /Differential Equation
+/$$,
+where
+$latex A(x) = y$$,
+$latex B(x) = x$$,
+and $latex D(x) = 0$$.
+We use $latex a$$, $latex b$$, $latex d$$,
+and $latex z$$ to denote the
+Taylor coefficients for
+$latex A [ X (t) ] $$,
+$latex B [ X (t) ]$$,
+$latex D [ X (t) ] $$,
+and $latex F [ X(t) ] $$ respectively.
+It follows that
+$latex b^j = x^j$$, $latex d^j = 0$$,
+$latex \[
+a^{(j)} = \left\{ \begin{array}{ll}
+    y & \R{if} \; j = 0
+    \\
+    0 & \R{otherwise}
+\end{array} \right.
+\] $$
+
+$head Taylor Coefficients Recursion$$
+
+$subhead z^(0)$$
+$latex \[
+    z^{(0)} = F ( x^{(0)} )
+\]$$
+
+$subhead e^(j)$$
+$latex \[
+\begin{array}{rcl}
+    e^{(j)} & = & d^{(j)} + \sum_{k=0}^j a^{(j-k)} * z^{(k)}
+    \\
+    e^{(j)} & = & y * z^{(j)}
+\end{array}
+\] $$
+
+$subhead z^j$$
+For $latex j = 0, \ldots , p-1$$
+$latex  \[
+\begin{array}{rcl}
+z^{(j+1)} & = & \frac{1}{j+1} \frac{1}{ b^{(0)} }
+\left(
+    \sum_{k=1}^{j+1} k x^{(k)} e^{(j+1-k)}
+    - \sum_{k=1}^j k z^{(k)}  b^{(j+1-k)}
+\right)
+\\
+& = & \frac{1}{j+1} \frac{1}{ x^{(0)} }
+\left(
+    y \sum_{k=1}^{j+1} k x^{(k)} z^{(j+1-k)}
+    - \sum_{k=1}^j k z^{(k)}  x^{(j+1-k)}
+\right)
+\\
+& = &
+\frac{1}{j+1} \frac{1}{ x^{(0)} }
+\left(
+    y (j+1) x^{(j+1)} z^{(0)}
+    +
+    \sum_{k=1}^j k ( y x^{(k)} z^{(j+1-k)} - z^{(k)}  x^{(j+1-k)} )
+\right)
+\\
+& = &
+y z^{(0)} x^{(j+1)} / x^{(0)}
++
+\frac{1}{j+1} \frac{1}{ x^{(0)} }
+\sum_{k=1}^j k ( y x^{(k)} z^{(j+1-k)} - z^{(k)}  x^{(j+1-k)} )
+\end{array}
+\] $$
+For $latex j = 1, \ldots , p$$
+$latex  \[
+\begin{array}{rcl}
+z^{(j)}
+& = &
+\left. \left(
+    y z^{(0)} x^{(j)}
+    +
+    \frac{1}{j} \sum_{k=1}^{j-1} k ( y x^{(k)} z^{(j-k)} - z^{(k)}  x^{(j-k)} )
+\right) \right/ x^{(0)}
+\end{array}
+\] $$
+
+
+
+$end
diff --git a/omh/theory/pow_reverse.omh b/omh/theory/pow_reverse.omh
new file mode 100644
index 000000000..94488f942
--- /dev/null
+++ b/omh/theory/pow_reverse.omh
@@ -0,0 +1,106 @@
+/* --------------------------------------------------------------------------
+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 pow_reverse$$
+$spell
+    Taylor
+$$
+
+$section Power Function Reverse Mode Theory$$
+
+We use the reverse theory
+$cref%standard math function
+    %ReverseTheory
+    %Standard Math Functions
+%$$
+definition for the functions $latex H$$ and $latex G$$.
+The zero order forward mode formula for the
+$cref/power/pow_forward/$$ function is
+$latex \[
+    z^{(0)}  =  F ( x^{(0)} )
+\] $$
+$latex \[
+\begin{array}{rcl}
+\D{H}{ x^{(0)} }
+& = & \D{G}{ x^{(0)} }  + \D{G}{ z^{(0)} } \D{ z^{(0)} }{ x^{(0)} }
+\\
+\D{ z^{(0)} }{ x^{(0)} } & = & y [ x^{(0)} ]^{y - 1}  = y z^{(0)} / x{(0)}
+\end{array}
+\] $$
+All the equations below apply to the case where $latex j > 0$$.
+For this case, the equation for $latex z^{(j)}$$ is
+$latex \[
+z^{(j)}
+=
+\left. \left(
+    y z^{(0)} x^{(j)}
+    +
+    \frac{1}{j} \sum_{k=1}^{j-1} k ( y x^{(k)} z^{(j-k)} - z^{(k)}  x^{(j-k)} )
+\right) \right/ x^{(0)}
+\] $$
+
+$head x^j$$
+$latex \[
+\begin{array}{rcl}
+\D{H}{ x^{(j)} }
+& = & \D{G}{ x^{(j)} }  + \D{G}{ z^{(j)} } \D{ z^{(j)} }{ x^{(j)} }
+\\
+\D{ z^{(j)} }{ x^{(j)} } & = & y z^{(0)} / x^{(0)}
+\end{array}
+\] $$
+
+$head x^k$$
+For $latex k = 1 , \ldots , j-1$$
+$latex \[
+\begin{array}{rcl}
+\D{H}{ x^{(k)} }
+& = & \D{G}{ x^{(k)} }  + \D{G}{ z^{(j)} } \D{ z^{(j)} }{ x^{(k)} }
+\\
+\D{ z^{(j)} }{ x^{(k)} } & = &
+\frac{1}{j} ( k y - (j-k) ) z^{(j-k)} / x^{(0)}
+\end{array}
+\] $$
+
+$head z^k$$
+For $latex k = 1 , \ldots , j-1$$
+$latex \[
+\begin{array}{rcl}
+\D{H}{ z^{(k)} }
+& = & \D{G}{ z^{(k)} }  + \D{G}{ z^{(j)} } \D{ z^{(j)} }{ z^{(k)} }
+\\
+\D{ z^{(j)} }{ z^{(k)} } & = &
+\frac{1}{j} ( (j-k) y - k ) x^{(j-k)} / x^{(0)}
+\end{array}
+\] $$
+
+$head x^0$$
+$latex \[
+\begin{array}{rcl}
+\D{H}{ x^{(0)} }
+& = & \D{G}{ x^{(0)} }  + \D{G}{ z^{(j)} } \D{ z^{(j)} }{ x^{(0)} }
+\\
+\D{ z^{(j)} }{ x^{(0)} } & = & - z^{(j)} / x^{(0)}
+\end{array}
+\] $$
+
+$head z^0$$
+$latex \[
+\begin{array}{rcl}
+\D{H}{ z^{(0)} }
+& = & \D{G}{ z^{(0)} }  + \D{G}{ z^{(j)} } \D{ z^{(j)} }{ z^{(0)} }
+\\
+\D{ z^{(j)} }{ z^{(0)} } & = &  y x^{(j)} / x^{(0)}
+\end{array}
+\] $$
+
+
+$end
diff --git a/omh/theory/reverse_theory.omh b/omh/theory/reverse_theory.omh
index 33a362761..97f1da740 100644
--- a/omh/theory/reverse_theory.omh
+++ b/omh/theory/reverse_theory.omh
@@ -1,5 +1,5 @@
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-17 Bradley M. Bell
+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.
@@ -178,7 +178,8 @@ $childtable%
     omh/theory/asin_reverse.omh%
     omh/theory/acos_reverse.omh%
     omh/theory/tan_reverse.omh%
-    omh/theory/erf_reverse.omh
+    omh/theory/erf_reverse.omh%
+    omh/theory/pow_reverse.omh
 %$$
 
 $end
diff --git a/pkgconfig/CMakeLists.txt b/pkgconfig/CMakeLists.txt
index 8b6c1d57a..74a881477 100644
--- a/pkgconfig/CMakeLists.txt
+++ b/pkgconfig/CMakeLists.txt
@@ -126,11 +126,24 @@ LIST(GET cmake_install_includedirs 0 cppad_includedir)
 #
 # cppad_libdir
 LIST(GET cmake_install_libdirs 0 cppad_libdir)
+#
+# add_to_set
+MACRO(add_to_set variable_name element)
+    IF( "${${variable_name}}" STREQUAL "" )
+        SET(${variable_name} ${element} )
+    ELSE( "${${variable_name}}" STREQUAL "" )
+        LIST(FIND ${variable_name} ${element} index)
+        IF( index EQUAL -1 )
+            SET(${variable_name} "${${variable_name}} ${element}")
+        ENDIF( index EQUAL -1 )
+    ENDIF( "${${variable_name}}" STREQUAL "" )
+ENDMACRO(add_to_set variable_name element)
 # -----------------------------------------------------------------------------
 # initialize
-SET(cppad_lib_list "-L${cppad_prefix}/${cppad_libdir} -l${cppad_lib}")
-SET(cppad_requires "")
-SET(cppad_libs_private "")
+SET(cppad_libdir_list "-L${cppad_prefix}/${cppad_libdir}")
+SET(cppad_lib_list    "-l${cppad_lib}")
+SET(cppad_requires         "")
+SET(cppad_libs_private     "")
 SET(cppad_requires_private "")
 #
 # Colpack does not have a pkgconfig file.
@@ -145,15 +158,14 @@ IF( cppad_has_colpack )
     IF( NOT colpack_libdir )
         MESSAGE(FATAL_ERROR "Cannit find libColPack.* below ${colpack_prefix}")
     ENDIF( NOT colpack_libdir )
-    SET(cppad_lib_list
-        "${cppad_lib_list} -L${colpack_libdir} -lColPack"
-    )
+    add_to_set(cppad_libdir_list "-L${colpack_libdir}")
+    add_to_set(cppad_lib_list    "-lColPack")
 ENDIF( cppad_has_colpack )
 #
 # Ipopt has a pkgconfig file.
 IF( cppad_has_ipopt )
-    SET(cppad_requires          "${cppad_requires} ipopt")
-    SET(cppad_lib_list          "${cppad_lib_list} -lcppad_ipopt")
+    SET(cppad_requires         "${cppad_requires} ipopt")
+    add_to_set(cppad_lib_list  "-lcppad_ipopt" )
 ENDIF( cppad_has_ipopt )
 # -----------------------------------------------------------------------------
 # cppad.pc
diff --git a/pkgconfig/cppad-uninstalled.pc.in b/pkgconfig/cppad-uninstalled.pc.in
index eac9a1c48..fb1f6c6d8 100644
--- a/pkgconfig/cppad-uninstalled.pc.in
+++ b/pkgconfig/cppad-uninstalled.pc.in
@@ -14,7 +14,7 @@
 # includedir=@cppad_SOURCE_DIR@/include
 #
 prefix=@cppad_prefix@
-exec_prefix=$(prefix)
+exec_prefix=${prefix}
 includedir=@cppad_SOURCE_DIR@/include
 libdir=${exec_prefix}/@cppad_libdir@
 #
@@ -24,7 +24,7 @@ Version:               @cppad_version@
 URL:                   @cppad_url@
 #
 Cflags:                -I${includedir}
-Libs:                  @cppad_lib_list@
+Libs:                  @cppad_libdir_list@ @cppad_lib_list@
 Requires:              @cppad_requires@
 Libs.private           @cppad_libs_private@
 Requires.private:      @cppad_requires_private@
diff --git a/pkgconfig/cppad.pc.in b/pkgconfig/cppad.pc.in
index 58be0e97d..672a9f09a 100644
--- a/pkgconfig/cppad.pc.in
+++ b/pkgconfig/cppad.pc.in
@@ -15,7 +15,7 @@
 # for the meaning of these variables.
 #
 prefix=@cppad_prefix@
-exec_prefix=$(prefix)
+exec_prefix=${prefix}
 includedir=${prefix}/@cppad_includedir@
 libdir=${exec_prefix}/@cppad_libdir@
 #
@@ -28,7 +28,7 @@ Version:               @cppad_version@
 URL:                   @cppad_url@
 #
 Cflags:                -I${includedir}
-Libs:                  @cppad_lib_list@
+Libs:                  @cppad_libdir_list@ @cppad_lib_list@
 Requires:              @cppad_requires@
 Libs.private           @cppad_libs_private@
 Requires.private:      @cppad_requires_private@
diff --git a/readme.md b/readme.md
index d10a83ba0..6aef9baa0 100644
--- a/readme.md
+++ b/readme.md
@@ -3,7 +3,7 @@ CppAD: A Package for Differentiation of C++ Algorithms
 
 # Links
 
-- [docmentation](https://coin-or.github.io/CppAD/doc)
+- [Documentation](https://coin-or.github.io/CppAD/doc)
 
 - [News](https://coin-or.github.io/CppAD/doc/whats_new.htm)
 
@@ -11,12 +11,12 @@ CppAD: A Package for Differentiation of C++ Algorithms
 
 - [Directories](https://coin-or.github.io/CppAD/doc/directory.htm)
 
-- [Coin-OR Download](https://www.coin-or.org/download/source/CppAD/)
+- [Downloads Before 2019](https://www.coin-or.org/download/source/CppAD/)
 
 
 # License
 <pre>
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-18 Bradley M. Bell
+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.
@@ -29,12 +29,12 @@ in the Eclipse Public License, Version 2.0 are satisfied:
 
 
 # Autotools
-The preferred method to test and install CppAD uses cmake.
-The deprecated autotools procedure can be used for this purpose,
+The preferred method to test and install CppAD uses [CMake](https://cmake.org).
+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.
+are used to support the Autotools test and install procedure.
 In addition,
 the following files, in this directory, are also for this purpose:
 `compile`,
@@ -46,5 +46,5 @@ the following files, in this directory, are also for this purpose:
 `missing`.
 
 
-# Copyright:
+# Copyright
 See the file `authors` in this directory.
diff --git a/speed/adolc/makefile.in b/speed/adolc/makefile.in
index b77b3102d..090a1f77a 100644
--- a/speed/adolc/makefile.in
+++ b/speed/adolc/makefile.in
@@ -276,7 +276,6 @@ 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@
@@ -331,6 +330,7 @@ pdfdir = @pdfdir@
 prefix = @prefix@
 program_transform_name = @program_transform_name@
 psdir = @psdir@
+runstatedir = @runstatedir@
 sbindir = @sbindir@
 sharedstatedir = @sharedstatedir@
 srcdir = @srcdir@
diff --git a/speed/cppad/makefile.in b/speed/cppad/makefile.in
index 2d590b946..0247796fa 100644
--- a/speed/cppad/makefile.in
+++ b/speed/cppad/makefile.in
@@ -263,7 +263,6 @@ 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@
@@ -318,6 +317,7 @@ pdfdir = @pdfdir@
 prefix = @prefix@
 program_transform_name = @program_transform_name@
 psdir = @psdir@
+runstatedir = @runstatedir@
 sbindir = @sbindir@
 sharedstatedir = @sharedstatedir@
 srcdir = @srcdir@
diff --git a/speed/cppad/mat_mul.cpp b/speed/cppad/mat_mul.cpp
index 548053c7c..869402574 100644
--- a/speed/cppad/mat_mul.cpp
+++ b/speed/cppad/mat_mul.cpp
@@ -1,5 +1,5 @@
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
+CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-22 Bradley M. Bell
 
 CppAD is distributed under the terms of the
              Eclipse Public License Version 2.0.
@@ -38,7 +38,7 @@ $srccode%cpp% */
 # include <cppad/cppad.hpp>
 # include <cppad/speed/mat_sum_sq.hpp>
 # include <cppad/speed/uniform_01.hpp>
-# include <cppad/example/atomic_three/mat_mul.hpp>
+# include <cppad/example/atomic_four/mat_mul/mat_mul.hpp>
 
 // Note that CppAD uses global_option["memory"] at the main program level
 # include <map>
@@ -92,8 +92,8 @@ bool link_mat_mul(
     w[0] = 1.;
 
     // atomic function information
-    CppAD::vector<ADScalar> ax(3 + 2 * n), ay(n);
-    atomic_mat_mul atom_mul;
+    CppAD::vector<ADScalar> ax(2 * n), ay(n);
+    CppAD::atomic_mat_mul<double> atom_mul("atom_mul");
     //
     // do not even record comparison operators
     size_t abort_op_index = 0;
@@ -113,15 +113,13 @@ bool link_mat_mul(
         if( ! global_option["atomic"] )
             mat_sum_sq(size, X, Y, Z);
         else
-        {   ax[0] = ADScalar( size ); // number of rows in left matrix
-            ax[1] = ADScalar( size ); // rows in left and columns in right
-            ax[2] = ADScalar( size ); // number of columns in right matrix
-            for(j = 0; j < n; j++)
-            {   ax[3 + j]     = X[j];
-                ax[3 + n + j] = X[j];
+        {   for(j = 0; j < n; j++)
+            {   ax[j]     = X[j];
+                ax[n + j] = X[j];
             }
             // Y = X * X
-            atom_mul(ax, ay);
+            size_t call_id = atom_mul.set(size, size, size);
+            atom_mul(call_id, ax, ay);
             Z[0] = 0.;
             for(j = 0; j < n; j++)
                 Z[0] += ay[j];
diff --git a/speed/cppadcg/det_minor.cpp b/speed/cppadcg/det_minor.cpp
index 752cc1288..2de4500cf 100644
--- a/speed/cppadcg/det_minor.cpp
+++ b/speed/cppadcg/det_minor.cpp
@@ -1,5 +1,5 @@
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
+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.
@@ -150,10 +150,10 @@ bool link_det_minor(
     }
     // --------------------------------------------------------------------
     //
-    // function object mapping matrix to gradiend of determinant
+    // function object mapping matrix to gradient of determinant
     static code_gen_fun static_fun;
     //
-    // size correspmnding to static_fun
+    // size corresponding static_fun
     static size_t static_size = 0;
     //
     // number of independent variables
diff --git a/speed/double/makefile.in b/speed/double/makefile.in
index 00e4e0b4a..5c93a1e45 100644
--- a/speed/double/makefile.in
+++ b/speed/double/makefile.in
@@ -263,7 +263,6 @@ 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@
@@ -318,6 +317,7 @@ pdfdir = @pdfdir@
 prefix = @prefix@
 program_transform_name = @program_transform_name@
 psdir = @psdir@
+runstatedir = @runstatedir@
 sbindir = @sbindir@
 sharedstatedir = @sharedstatedir@
 srcdir = @srcdir@
diff --git a/speed/example/CMakeLists.txt b/speed/example/CMakeLists.txt
index d56cd2c8d..cfe09866b 100644
--- a/speed/example/CMakeLists.txt
+++ b/speed/example/CMakeLists.txt
@@ -1,5 +1,5 @@
 # -----------------------------------------------------------------------------
-# CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 Bradley M. Bell
+# 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.
@@ -15,8 +15,6 @@
 # add_executable(<name> [WIN32] [MACOSX_BUNDLE] [EXCLUDE_FROM_ALL]
 #                 source1 source2 ... sourceN
 # )
-# We do not add ../src/speed_src library to avoid undefined externals.
-# Instead we build our own copy of ../src/microsoft_timer.cpp.
 SET(source_list example.cpp
     det_by_lu.cpp
     det_by_minor.cpp
@@ -28,7 +26,6 @@ SET(source_list example.cpp
     sparse_jac_fun.cpp
     speed_test.cpp
     time_test.cpp
-    "../src/microsoft_timer.cpp"
 )
 set_compile_flags( speed_example "${cppad_debug_which}" "${source_list}" )
 #
diff --git a/speed/example/makefile.in b/speed/example/makefile.in
index b3e6e1683..8e79215b5 100644
--- a/speed/example/makefile.in
+++ b/speed/example/makefile.in
@@ -285,7 +285,6 @@ 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@
@@ -340,6 +339,7 @@ pdfdir = @pdfdir@
 prefix = @prefix@
 program_transform_name = @program_transform_name@
 psdir = @psdir@
+runstatedir = @runstatedir@
 sbindir = @sbindir@
 sharedstatedir = @sharedstatedir@
 srcdir = @srcdir@
diff --git a/speed/fadbad/makefile.in b/speed/fadbad/makefile.in
index eaea584ee..bae55a55a 100644
--- a/speed/fadbad/makefile.in
+++ b/speed/fadbad/makefile.in
@@ -264,7 +264,6 @@ 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@
@@ -319,6 +318,7 @@ pdfdir = @pdfdir@
 prefix = @prefix@
 program_transform_name = @program_transform_name@
 psdir = @psdir@
+runstatedir = @runstatedir@
 sbindir = @sbindir@
 sharedstatedir = @sharedstatedir@
 srcdir = @srcdir@
diff --git a/speed/main.cpp b/speed/main.cpp
index 9d3801f37..cbbba0007 100644
--- a/speed/main.cpp
+++ b/speed/main.cpp
@@ -1,5 +1,5 @@
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
+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.
@@ -605,7 +605,7 @@ int main(int argc, char *argv[])
     CppAD::vector<size_t> size_sparse_hessian(n_size);
     CppAD::vector<size_t> size_sparse_jacobian(n_size);
     for(size_t i = 0; i < n_size; i++)
-    {   size_det_minor[i]   = i + 1;
+    {   size_det_minor[i]   = i + 2;
         size_det_lu[i]      = 10 * i + 1;
         size_mat_mul[i]     = 10 * i + 1;
         size_ode[i]         = 10 * i + 1;
diff --git a/speed/sacado/makefile.in b/speed/sacado/makefile.in
index 0e80508be..20a66564d 100644
--- a/speed/sacado/makefile.in
+++ b/speed/sacado/makefile.in
@@ -264,7 +264,6 @@ 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@
@@ -319,6 +318,7 @@ pdfdir = @pdfdir@
 prefix = @prefix@
 program_transform_name = @program_transform_name@
 psdir = @psdir@
+runstatedir = @runstatedir@
 sbindir = @sbindir@
 sharedstatedir = @sharedstatedir@
 srcdir = @srcdir@
diff --git a/speed/src/CMakeLists.txt b/speed/src/CMakeLists.txt
index cfde20da9..d9d5ae604 100644
--- a/speed/src/CMakeLists.txt
+++ b/speed/src/CMakeLists.txt
@@ -1,5 +1,5 @@
 # -----------------------------------------------------------------------------
-# CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 Bradley M. Bell
+# 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.
@@ -26,7 +26,6 @@ SET(source_list
     link_poly.cpp
     link_sparse_hessian.cpp
     link_sparse_jacobian.cpp
-    microsoft_timer.cpp
 )
 # END_SORT_THIS_LINE_MINUS_2
 
diff --git a/speed/src/link.omh b/speed/src/link.omh
index 9dfcc7627..a120e42a7 100644
--- a/speed/src/link.omh
+++ b/speed/src/link.omh
@@ -1,5 +1,5 @@
 -----------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
+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.
@@ -45,8 +45,7 @@ $childtable%
     speed/src/link_ode.cpp%
     speed/src/link_poly.cpp%
     speed/src/link_sparse_hessian.hpp%
-    speed/src/link_sparse_jacobian.hpp%
-    speed/src/microsoft_timer.cpp
+    speed/src/link_sparse_jacobian.hpp
 %$$
 
 $head Namespace$$
diff --git a/speed/src/makefile.am b/speed/src/makefile.am
index 705063e68..d0b074d3f 100644
--- a/speed/src/makefile.am
+++ b/speed/src/makefile.am
@@ -1,5 +1,5 @@
 # -----------------------------------------------------------------------------
-# CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-18 Bradley M. Bell
+# 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.
@@ -30,5 +30,4 @@ libspeed_a_SOURCES = \
 	link_ode.cpp \
 	link_poly.cpp \
 	link_sparse_hessian.cpp \
-	link_sparse_jacobian.cpp \
-	microsoft_timer.cpp
+	link_sparse_jacobian.cpp
diff --git a/speed/src/makefile.in b/speed/src/makefile.in
index e0705e4cb..650ca9d51 100644
--- a/speed/src/makefile.in
+++ b/speed/src/makefile.in
@@ -107,8 +107,7 @@ libspeed_a_AR = $(AR) $(ARFLAGS)
 libspeed_a_LIBADD =
 am_libspeed_a_OBJECTS = link_det_lu.$(OBJEXT) link_det_minor.$(OBJEXT) \
 	link_mat_mul.$(OBJEXT) link_ode.$(OBJEXT) link_poly.$(OBJEXT) \
-	link_sparse_hessian.$(OBJEXT) link_sparse_jacobian.$(OBJEXT) \
-	microsoft_timer.$(OBJEXT)
+	link_sparse_hessian.$(OBJEXT) link_sparse_jacobian.$(OBJEXT)
 libspeed_a_OBJECTS = $(am_libspeed_a_OBJECTS)
 AM_V_P = $(am__v_P_@AM_V@)
 am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
@@ -129,8 +128,7 @@ am__depfiles_remade = ./$(DEPDIR)/link_det_lu.Po \
 	./$(DEPDIR)/link_det_minor.Po ./$(DEPDIR)/link_mat_mul.Po \
 	./$(DEPDIR)/link_ode.Po ./$(DEPDIR)/link_poly.Po \
 	./$(DEPDIR)/link_sparse_hessian.Po \
-	./$(DEPDIR)/link_sparse_jacobian.Po \
-	./$(DEPDIR)/microsoft_timer.Po
+	./$(DEPDIR)/link_sparse_jacobian.Po
 am__mv = mv -f
 CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
 	$(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
@@ -201,7 +199,7 @@ CXX_FLAGS = @CXX_FLAGS@
 CYGPATH_W = @CYGPATH_W@
 
 # -----------------------------------------------------------------------------
-# CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-18 Bradley M. Bell
+# 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.
@@ -284,7 +282,6 @@ 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@
@@ -339,6 +336,7 @@ pdfdir = @pdfdir@
 prefix = @prefix@
 program_transform_name = @program_transform_name@
 psdir = @psdir@
+runstatedir = @runstatedir@
 sbindir = @sbindir@
 sharedstatedir = @sharedstatedir@
 srcdir = @srcdir@
@@ -365,8 +363,7 @@ libspeed_a_SOURCES = \
 	link_ode.cpp \
 	link_poly.cpp \
 	link_sparse_hessian.cpp \
-	link_sparse_jacobian.cpp \
-	microsoft_timer.cpp
+	link_sparse_jacobian.cpp
 
 all: all-am
 
@@ -423,7 +420,6 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/link_poly.Po@am__quote@ # am--include-marker
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/link_sparse_hessian.Po@am__quote@ # am--include-marker
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/link_sparse_jacobian.Po@am__quote@ # am--include-marker
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/microsoft_timer.Po@am__quote@ # am--include-marker
 
 $(am__depfiles_remade):
 	@$(MKDIR_P) $(@D)
@@ -578,7 +574,6 @@ distclean: distclean-am
 	-rm -f ./$(DEPDIR)/link_poly.Po
 	-rm -f ./$(DEPDIR)/link_sparse_hessian.Po
 	-rm -f ./$(DEPDIR)/link_sparse_jacobian.Po
-	-rm -f ./$(DEPDIR)/microsoft_timer.Po
 	-rm -f makefile
 distclean-am: clean-am distclean-compile distclean-generic \
 	distclean-tags
@@ -631,7 +626,6 @@ maintainer-clean: maintainer-clean-am
 	-rm -f ./$(DEPDIR)/link_poly.Po
 	-rm -f ./$(DEPDIR)/link_sparse_hessian.Po
 	-rm -f ./$(DEPDIR)/link_sparse_jacobian.Po
-	-rm -f ./$(DEPDIR)/microsoft_timer.Po
 	-rm -f makefile
 maintainer-clean-am: distclean-am maintainer-clean-generic
 
diff --git a/speed/src/microsoft_timer.cpp b/speed/src/microsoft_timer.cpp
deleted file mode 100644
index 0954681c0..000000000
--- a/speed/src/microsoft_timer.cpp
+++ /dev/null
@@ -1,89 +0,0 @@
-/* --------------------------------------------------------------------------
-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 microsoft_timer$$
-$spell
-    Microsoft
-    cpp
-    src
-$$
-
-$section Microsoft Version of Elapsed Number of Seconds$$
-
-
-$head Syntax$$
-$icode%s% = microsoft_timer()%$$
-
-$head Purpose$$
-This routine is accurate to within .02 seconds
-(see $cref elapsed_seconds$$ which uses this routine when
-the preprocessor symbol $code _MSC_VER$$ is defined).
-It does not necessary work for time intervals that are greater than a day.
-It uses $code ::GetSystemTime$$ for timing.
-
-$head s$$
-is a $code double$$ equal to the
-number of seconds since the first call to $code microsoft_timer$$.
-
-$head Linking$$
-The source code for this routine is located in
-$code speed/src/microsoft_timer.cpp$$.
-The preprocessor symbol $code _MSC_VER$$ must
-be defined, or this routine is not compiled.
-
-$end
------------------------------------------------------------------------
-*/
-# ifdef _MSC_VER
-# include <windows.h>
-# include <cassert>
-
-// Note that the doxygen for this routine does not get generated because
-// _MSC_VER is not defined during generation. In general, it is a problem
-// that not all preprocessor options get documented.
-/*!
-\{
-\file microsoft_timer.cpp
-\brief Microsoft version of elapsed_seconds.
-*/
-
-/*!
-Microsoft version of elapsed number of seconds since frist call.
-
-\copydetails elapsed_seconds
-*/
-double microsoft_timer(void)
-{   static bool       first_  = true;
-    static SYSTEMTIME st_;
-    SYSTEMTIME st;
-
-    if( first_ )
-    {   ::GetSystemTime(&st_);
-        first_ = false;
-        return 0.;
-    }
-    ::GetSystemTime(&st);
-
-    double hour   = double(st.wHour)         - double(st_.wHour);
-    double minute = double(st.wMinute)       - double(st_.wMinute);
-    double second = double(st.wSecond)       - double(st_.wSecond);
-    double milli  = double(st.wMilliseconds) - double(st_.wMilliseconds);
-
-    double diff   = 1e-3*milli + second + 60.*minute + 3600.*hour;
-    if( diff < 0. )
-        diff += 3600.*24.;
-    assert( 0 <= diff && diff < 3600.*24. );
-
-    return diff;
-}
-
-# endif
diff --git a/speed/xpackage/CMakeLists.txt b/speed/xpackage/CMakeLists.txt
index d00d0dbed..15d71ddf3 100644
--- a/speed/xpackage/CMakeLists.txt
+++ b/speed/xpackage/CMakeLists.txt
@@ -1,5 +1,5 @@
 # -----------------------------------------------------------------------------
-# CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
+# 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.
@@ -12,8 +12,8 @@
 # Build the speed/xpackage directory tests
 # Inherit build type from ../CMakeList.txt
 
-# assert xpackage_prefix is defined
-assert ( xpackage_prefix )
+# Set the install prefix for this package
+SET(xpackage_prefix "/usr")
 
 # Adds flags to the compiler command line for sources in the current directory
 # and below. This command can be used to add any flags, but it was originally
@@ -21,7 +21,10 @@ assert ( xpackage_prefix )
 ADD_DEFINITIONS("-DCPPAD_XPACKAGE_SPEED")
 
 # Local include directories to search (not in package_prefix/includdir)
-INCLUDE_DIRECTORIES( ${CMAKE_CURRENT_SOURCE_DIR}/../src )
+INCLUDE_DIRECTORIES(
+    ${CMAKE_CURRENT_SOURCE_DIR}/../src
+    ${xpackage_prefix}/include
+)
 
 # add_executable(<name> [WIN32] [MACOSX_BUNDLE] [EXCLUDE_FROM_ALL]
 #                 source1 source2 ... sourceN
diff --git a/speed/xpackage/makefile.in b/speed/xpackage/makefile.in
index 89e9f2496..b586909ab 100644
--- a/speed/xpackage/makefile.in
+++ b/speed/xpackage/makefile.in
@@ -1,7 +1,7 @@
-# makefile.in generated by automake 1.16.1 from makefile.am.
+# makefile.in generated by automake 1.16.2 from makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2018 Free Software Foundation, Inc.
+# 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,
@@ -203,7 +203,7 @@ ECHO_T = @ECHO_T@
 EIGEN_DIR = @EIGEN_DIR@
 EIGEN_INCLUDE = @EIGEN_INCLUDE@
 EXEEXT = @EXEEXT@
-XPACKAGE_DIR = @XPACKAGE_DIR@
+FADBAD_DIR = @FADBAD_DIR@
 FC = @FC@
 FCFLAGS = @FCFLAGS@
 FCLIBS = @FCLIBS@
@@ -264,7 +264,6 @@ 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@
@@ -273,7 +272,7 @@ 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_xpackage = @cppad_has_xpackage@
+cppad_has_fadbad = @cppad_has_fadbad@
 cppad_has_gettimeofday = @cppad_has_gettimeofday@
 cppad_has_ipopt = @cppad_has_ipopt@
 cppad_has_mkstemp = @cppad_has_mkstemp@
@@ -319,6 +318,7 @@ pdfdir = @pdfdir@
 prefix = @prefix@
 program_transform_name = @program_transform_name@
 psdir = @psdir@
+runstatedir = @runstatedir@
 sbindir = @sbindir@
 sharedstatedir = @sharedstatedir@
 srcdir = @srcdir@
@@ -329,7 +329,7 @@ top_builddir = @top_builddir@
 top_srcdir = @top_srcdir@
 
 # -----------------------------------------------------------------------------
-# CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-18 Bradley M. Bell
+# 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.
diff --git a/speed/xpackage/speed_xpackage.omh b/speed/xpackage/speed_xpackage.omh
index e97d624bd..36bc262e3 100644
--- a/speed/xpackage/speed_xpackage.omh
+++ b/speed/xpackage/speed_xpackage.omh
@@ -1,5 +1,5 @@
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
+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.
@@ -19,6 +19,14 @@ $spell
     cp
     ls
     sed
+    txt
+    cmake
+    det
+    lu
+    mul
+    jacobian
+    ifdef
+    endif
 $$
 
 
@@ -49,27 +57,55 @@ $codei%
     cp -r speed/xpackage speed/%your_package%
     for file in `ls speed/%your_package%`
     do
-        sed -i speed/%your_package%/@file -e 's|xpackage|%your_package%|'
+        sed -i speed/%your_package%/@file \
+            -e 's|xpackage|%your_package%|' \
+            -e 's|Xpackage|%Your_package%|' \
+            -e 's|CPPAD_XPACKAGE_SPEED|%YOUR_PACKGE%|'
     done
+    git checkout speed/CMakeLists.txt
+    sed -i speed/CMakeLists.txt \
+        -e 's|^.*(xpackage)|ADD_SUBDIRECTORY(%your_package%)\n&|'
+    git checkout speed/main.cpp
+    line1='# ifdef CPPAD_%YOUR_PACKAGE%_SPEED'
+    line2='# define AD_PACKAGE "%your_package%"'
+    line3='# endif'
+    sed -i speed/main.cpp \
+        -e "/CPPAD_XPACKAGE_SPEED/s|^|@line1\n@line2\n@line3\n|"
 %$$
-where $icode your_package$$ has been replaced by the name of the new package.
+where $icode your_package$$ has been replaced by the name of the new package
+$icode Your_package$$ is a capitalized version of the name, and
+$icode YOUR_PACKAGE$$ is an all caps version of the name.
 
 
 $head Running Tests$$
-To build the xpackage version of the tests,
-execute the following commands starting in the
-$cref/build directory/cmake/Build Directory/$$:
+Starting in the distribution directory,
+the following commands will build the new package version of the tests:
 $codei%
-    cd speed/xpackage
-    make check_speed_xpackage VERBOSE=1
+    bin/run_cmake.sh --no_optional
+    cd build/speed/%your_package%
+    make check_speed_%your_package% VERBOSE=1
 %$$
-You can then run the corresponding speed tests
-with the following command
-$codei%
-    ./speed_xpackage speed %seed%
-%$$
-where $icode seed$$ is a positive integer.
-See $cref speed_main$$ for more options.
+This should result in the following output:
+$codei|
+    |...|
+    |your_package|_det_lu_available = false
+    |your_package|_det_minor_available = false
+    |your_package|_mat_mul_available = false
+    |your_package|_ode_available = false
+    |your_package|_poly_available = false
+    |your_package|_sparse_hessian_available = false
+    |your_package|_sparse_jacobian_available = false
+    All 0 correctness tests passed.
+    No memory leak detected
+    speed main: OK
+    [100%] Built target check_speed_|your_package|
+|$$
+You can not edit one or more of the $icode%*%.cpp%$$ files in the
+$icode your_package$$ directory so that the corresponding speed test
+is available and then run the corresponding test using the
+$cref speed_main$$ instructions.
+See $cref speed_cppad$$ for examples of how to do this for each
+of the speed tests.
 
 $contents%
     speed/xpackage/det_minor.cpp%
diff --git a/test_more/CMakeLists.txt b/test_more/CMakeLists.txt
index a6d0beccb..02468ef52 100644
--- a/test_more/CMakeLists.txt
+++ b/test_more/CMakeLists.txt
@@ -1,5 +1,5 @@
 # -----------------------------------------------------------------------------
-# CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
+# 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.
@@ -21,10 +21,10 @@ ADD_SUBDIRECTORY(deprecated)
 ADD_SUBDIRECTORY(compare_c)
 
 # debug_rel tests
-IF( NOT CMAKE_VS_MSBUILD_COMMAND )
-    # during build Visual studio rejects this mix of debug and release flags
+IF( NOT "${CMAKE_GENERATOR}" STREQUAL "NMake Makefiles" )
+    # Visual studio rejects mixing debug and release flags
     ADD_SUBDIRECTORY(debug_rel)
-ENDIF( NOT CMAKE_VS_MSBUILD_COMMAND )
+ENDIF( NOT "${CMAKE_GENERATOR}" STREQUAL "NMake Makefiles" )
 #
 # cppad_for_tmb tests
 IF( OPENMP_FOUND )
diff --git a/test_more/compare_c/CMakeLists.txt b/test_more/compare_c/CMakeLists.txt
index 10583cc8b..86b5b4ff4 100644
--- a/test_more/compare_c/CMakeLists.txt
+++ b/test_more/compare_c/CMakeLists.txt
@@ -1,5 +1,5 @@
 # -----------------------------------------------------------------------------
-# CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-17 Bradley M. Bell
+# 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.
@@ -40,10 +40,13 @@
 # use cppad_debug_which to determine build type
 IF( "${cppad_debug_which}" STREQUAL debug_all )
     SET(CMAKE_BUILD_TYPE DEBUG)
+    SET(all_cxx_flags "${cppad_cxx_flags} ${CMAKE_CXX_FLAGSS_DEBUG}")
 ELSEIF( "${cppad_debug_which}" STREQUAL debug_odd )
     SET(CMAKE_BUILD_TYPE DEBUG)
+    SET(all_cxx_flags "${cppad_cxx_flags} ${CMAKE_CXX_FLAGSS_DEBUG}")
 ELSE( "${cppad_debug_which}" STREQUAL debug_odd )
     SET(CMAKE_BUILD_TYPE RELEASE)
+    SET(all_cxx_flags "${cppad_cxx_flags} ${CMAKE_CXX_FLAGSS_RELEASE}")
 ENDIF( "${cppad_debug_which}" STREQUAL debug_all )
 #
 # Loop though the C and C++ compilers
@@ -59,9 +62,9 @@ FOREACH( com c cpp )
     ADD_EXECUTABLE( det_by_minor_${com} EXCLUDE_FROM_ALL ${source})
     #
     IF( ${com} STREQUAL cpp )
-        # These are C++ compiler flags (may not be valid for C)
+        # cppad_cxx_flags are C++ compiler flags and may not be valid for C
         SET_TARGET_PROPERTIES(
-            det_by_minor_${com} PROPERTIES COMPILE_FLAGS "${cppad_cxx_flags}"
+            det_by_minor_${com} PROPERTIES COMPILE_FLAGS "${all_cxx_flags}"
         )
     ENDIF( ${com} STREQUAL cpp )
     #
diff --git a/test_more/compare_c/makefile.in b/test_more/compare_c/makefile.in
index 187f18747..b0fccf451 100644
--- a/test_more/compare_c/makefile.in
+++ b/test_more/compare_c/makefile.in
@@ -273,7 +273,6 @@ 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@
@@ -328,6 +327,7 @@ pdfdir = @pdfdir@
 prefix = @prefix@
 program_transform_name = @program_transform_name@
 psdir = @psdir@
+runstatedir = @runstatedir@
 sbindir = @sbindir@
 sharedstatedir = @sharedstatedir@
 srcdir = @srcdir@
diff --git a/test_more/debug_rel/CMakeLists.txt b/test_more/debug_rel/CMakeLists.txt
index 14b154340..ae699b652 100644
--- a/test_more/debug_rel/CMakeLists.txt
+++ b/test_more/debug_rel/CMakeLists.txt
@@ -1,5 +1,5 @@
 # -----------------------------------------------------------------------------
-# CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-18 Bradley M. Bell
+# 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.
@@ -13,24 +13,24 @@
 
 # set compiler flags for debug_rel.cpp and debug.cpp
 IF( "${debug_which}" STREQUAL "debug_all" )
-    SET(debug_extra    "${CMAKE_CXX_FLAGS_DEBUG}")
-    SET(release_extra  "${CMAKE_CXX_FLAGS_DEBUG}")
+    SET(debug_flags    "${cppad_cxx_flags} ${CMAKE_CXX_FLAGS_DEBUG}")
+    SET(release_flags  "${cppad_cxx_flags} ${CMAKE_CXX_FLAGS_DEBUG}")
 ELSEIF( "${debug_which}" STREQUAL "debug_none" )
-    SET(debug_extra    "${CMAKE_CXX_FLAGS_RELEASE}")
-    SET(release_extra  "${CMAKE_CXX_FLAGS_RELEASE}")
+    SET(debug_flags    "${cppad_cxx_flags} ${CMAKE_CXX_FLAGS_RELEASE}")
+    SET(release_flags  "${cppad_cxx_flags} ${CMAKE_CXX_FLAGS_RELEASE}")
 ELSE( "${debug_which}" )
-    SET(debug_extra    "${CMAKE_CXX_FLAGS_DEBUG}")
-    SET(release_extra  "${CMAKE_CXX_FLAGS_RELEASE}")
+    SET(debug_flags    "${cppad_cxx_flags} ${CMAKE_CXX_FLAGS_DEBUG}")
+    SET(release_flags  "${cppad_cxx_flags} ${CMAKE_CXX_FLAGS_RELEASE}")
 ENDIF( "${debug_which}" STREQUAL "debug_all" )
 #
 SET_SOURCE_FILES_PROPERTIES(
     debug_rel.cpp debug.cpp PROPERTIES COMPILE_FLAGS
-    "${cppad_cxx_flags} ${debug_extra} -DCPPAD_DEBUG_AND_RELEASE"
+    "${debug_flags} -DCPPAD_DEBUG_AND_RELEASE"
 )
 #
 SET_SOURCE_FILES_PROPERTIES(
     release.cpp PROPERTIES COMPILE_FLAGS
-    "${cppad_cxx_flags} ${release_extra} -DCPPAD_DEBUG_AND_RELEASE"
+    "${release_flags} -DCPPAD_DEBUG_AND_RELEASE"
 )
 
 # now that we have the properties, add the executable
diff --git a/test_more/deprecated/atomic_two/makefile.in b/test_more/deprecated/atomic_two/makefile.in
index 54ad95faf..0f975b19e 100644
--- a/test_more/deprecated/atomic_two/makefile.in
+++ b/test_more/deprecated/atomic_two/makefile.in
@@ -283,7 +283,6 @@ 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@
@@ -338,6 +337,7 @@ pdfdir = @pdfdir@
 prefix = @prefix@
 program_transform_name = @program_transform_name@
 psdir = @psdir@
+runstatedir = @runstatedir@
 sbindir = @sbindir@
 sharedstatedir = @sharedstatedir@
 srcdir = @srcdir@
diff --git a/test_more/deprecated/chkpoint_one/makefile.in b/test_more/deprecated/chkpoint_one/makefile.in
index 8c2430b21..f3be2b1fb 100644
--- a/test_more/deprecated/chkpoint_one/makefile.in
+++ b/test_more/deprecated/chkpoint_one/makefile.in
@@ -272,7 +272,6 @@ 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@
@@ -327,6 +326,7 @@ pdfdir = @pdfdir@
 prefix = @prefix@
 program_transform_name = @program_transform_name@
 psdir = @psdir@
+runstatedir = @runstatedir@
 sbindir = @sbindir@
 sharedstatedir = @sharedstatedir@
 srcdir = @srcdir@
diff --git a/test_more/deprecated/makefile.in b/test_more/deprecated/makefile.in
index 2d28af512..4cc48ebb8 100644
--- a/test_more/deprecated/makefile.in
+++ b/test_more/deprecated/makefile.in
@@ -288,7 +288,6 @@ 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@
@@ -343,6 +342,7 @@ pdfdir = @pdfdir@
 prefix = @prefix@
 program_transform_name = @program_transform_name@
 psdir = @psdir@
+runstatedir = @runstatedir@
 sbindir = @sbindir@
 sharedstatedir = @sharedstatedir@
 srcdir = @srcdir@
diff --git a/test_more/deprecated/old_usead_1.cpp b/test_more/deprecated/old_usead_1.cpp
index fa3215579..847acaea4 100644
--- a/test_more/deprecated/old_usead_1.cpp
+++ b/test_more/deprecated/old_usead_1.cpp
@@ -1,5 +1,5 @@
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
+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.
@@ -27,7 +27,7 @@ $head Purpose$$
 Consider the case where an inner function is used repeatedly in the
 definition of an outer function.
 In this case, it may reduce the number of variables
-$cref/size_var/seq_property/size_var/$$,
+$cref/size_var/fun_property/size_var/$$,
 and hence the required memory.
 
 $head Simple Case$$
diff --git a/test_more/deprecated/old_usead_2.cpp b/test_more/deprecated/old_usead_2.cpp
index d137d42b5..e03f41261 100644
--- a/test_more/deprecated/old_usead_2.cpp
+++ b/test_more/deprecated/old_usead_2.cpp
@@ -1,5 +1,5 @@
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
+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.
@@ -28,7 +28,7 @@ $head Purpose$$
 Consider the case where an inner function is used repeatedly in the
 definition of an outer function.
 In this case, it may reduce the number of variables
-$cref/size_var/seq_property/size_var/$$,
+$cref/size_var/fun_property/size_var/$$,
 and hence the required memory.
 
 $srcthisfile%0%// BEGIN C++%// END C++%1%$$
diff --git a/test_more/general/CMakeLists.txt b/test_more/general/CMakeLists.txt
index 997c37d6e..b55cbb21a 100644
--- a/test_more/general/CMakeLists.txt
+++ b/test_more/general/CMakeLists.txt
@@ -1,5 +1,5 @@
 # -----------------------------------------------------------------------------
-# CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
+# 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.
@@ -38,6 +38,7 @@ SET(source_list
     ${eigen_sources}
     ${ipopt_sources}
     general.cpp
+    abs_normal.cpp
     acos.cpp
     acosh.cpp
     add.cpp
@@ -84,6 +85,7 @@ SET(source_list
     forward_order.cpp
     from_base.cpp
     fun_check.cpp
+    cpp_graph.cpp
     hes_sparsity.cpp
     jacobian.cpp
     json_graph.cpp
diff --git a/test_more/general/abs_normal.cpp b/test_more/general/abs_normal.cpp
new file mode 100644
index 000000000..98187ce3e
--- /dev/null
+++ b/test_more/general/abs_normal.cpp
@@ -0,0 +1,116 @@
+/* --------------------------------------------------------------------------
+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 <cppad/cppad.hpp>
+
+namespace { // BEGIN_EMPTY_NAMESPACE
+// join
+CPPAD_TESTVECTOR(double) join(
+    const CPPAD_TESTVECTOR(double)& x ,
+    const CPPAD_TESTVECTOR(double)& u )
+{   size_t n = x.size();
+    size_t s = u.size();
+    CPPAD_TESTVECTOR(double) xu(n + s);
+    for(size_t j = 0; j < n; j++)
+        xu[j] = x[j];
+    for(size_t j = 0; j < s; j++)
+        xu[n + j] = u[j];
+    return xu;
+}
+// test_pow
+bool test_pow(void)
+{   bool ok = true;
+    //
+    using CppAD::AD;
+    using CppAD::ADFun;
+    //
+    typedef CPPAD_TESTVECTOR(double)       d_vector;
+    typedef CPPAD_TESTVECTOR( AD<double> ) ad_vector;
+    //
+    double eps99 = 99.0 * std::numeric_limits<double>::epsilon();
+    //
+    size_t n = 2; // size of x
+    size_t m = 1; // size of y
+    size_t s = 1; // number of absolute value terms
+    //
+    // record the function f(x)
+    ad_vector ad_x(n), ad_y(m);
+    for(size_t j = 0; j < n; j++)
+        ad_x[j] = double(j + 1);
+    Independent( ad_x );
+    //
+    // for this example, we the function is
+    // f(x) = pow( |x_0|, x_1) + pow( |x_0| , 2) + pow(2, |x_0|)
+    AD<double> abs_x0 = abs( ad_x[0] );
+    AD<double> pow_vv = pow( abs_x0 , ad_x[1] );
+    AD<double> pow_vp = pow( abs_x0 , 2.0 );
+    AD<double> pow_pv = pow( 2.0 , abs_x0 );
+    ad_y[0] = pow_vv + pow_vp + pow_pv;
+    ADFun<double> f(ad_x, ad_y);
+
+    // create its abs_normal representation in g, a
+    ADFun<double> g, a;
+    f.abs_normal_fun(g, a);
+
+    // check dimension of domain and range space for g
+    ok &= g.Domain() == n + s;
+    ok &= g.Range()  == m + s;
+
+    // check dimension of domain and range space for a
+    ok &= a.Domain() == n;
+    ok &= a.Range()  == s;
+
+    // --------------------------------------------------------------------
+    // Choose a point x_hat
+    d_vector x_hat(n);
+    x_hat[0] = -2.0;
+    x_hat[1] = 2.0;
+
+    // value of a_hat = a(x_hat)
+    d_vector a_hat = a.Forward(0, x_hat);
+
+    // (x_hat, a_hat)
+    d_vector xu_hat = join(x_hat, a_hat);
+
+    // value of g[ x_hat, a_hat ]
+    d_vector g_hat = g.Forward(0, xu_hat);
+
+    // Jacobian of g[ x_hat, a_hat ]
+    d_vector g_jac = g.Jacobian(xu_hat);
+
+    // value of delta_x
+    d_vector delta_x(n);
+    delta_x[0] =  4.0;
+    delta_x[1] =  1.0;
+
+    // value of x
+    d_vector x(n);
+    for(size_t j = 0; j < n; j++)
+        x[j] = x_hat[j] + delta_x[j];
+
+    // value of f(x)
+    d_vector y = f.Forward(0, x);
+
+    // check
+    double check = std::pow( std::fabs(x[0]) , x[1]);
+    check       += std::pow( std::fabs(x[0]) , 2.0 );
+    check       += std::pow( 2.0, std::fabs(x[0]) );
+    ok          &= CppAD::NearEqual(y[0], check, eps99, eps99);
+
+    return ok;
+}
+} // END_EMPYT_NAMESPACE
+
+bool abs_normal(void)
+{   bool ok = true;
+    ok     &= test_pow();
+    return ok;
+}
diff --git a/test_more/general/azmul.cpp b/test_more/general/azmul.cpp
index 7f21d4f7f..566e9decc 100644
--- a/test_more/general/azmul.cpp
+++ b/test_more/general/azmul.cpp
@@ -1,5 +1,5 @@
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-17 Bradley M. Bell
+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.
@@ -14,6 +14,48 @@ in the Eclipse Public License, Version 2.0 are satisfied:
 # include <cmath>
 
 namespace {
+    bool test_base2ad(void)
+    {   bool ok = true;
+        double eps99 = 99.0 * std::numeric_limits<double>::epsilon();
+
+        using CppAD::AD;
+
+        // Both recordiings are done with the dynamic  parameter p = 0, 1
+        // to make sure does not short circut multiply
+        for(size_t ip = 0; ip < 2; ++ip)
+        {
+            // f(p; x) = p[0] * x[0] * x[0]
+            CPPAD_TESTVECTOR(AD<double>)  ap(1), ax(1), ay(1), aw(1);
+            ap[0] = double(ip);
+            ax[0] = 0.0;
+            CppAD::Independent(ax, ap);
+            ay[0] = ap[0] * ax[0] * ax[0];
+            CppAD::ADFun<double> f(ax, ay);
+
+            // AD version of f
+            CppAD::ADFun< AD<double> , double > af = f.base2ad();
+
+            // g(p; x) = d/dx f(p, x) = 2 * p[0] * x[0]
+            CppAD::Independent(ax, ap);
+            af.new_dynamic(ap);
+            af.Forward(0, ax);
+            aw[0] = 1.0;
+            ay    = af.Reverse(1, aw);
+            CppAD::ADFun<double> g(ax, ay);
+
+            // Evaluate g(p, x)
+            CPPAD_TESTVECTOR(double) p(1), x(1), y(1);
+            p[0] = 2.0;
+            x[0] = 3.0;
+            g.new_dynamic(p);
+            y = g.Forward(0, x);
+
+            // check result
+            double check = 2.0 * p[0] * x[0];
+            ok &= CppAD::NearEqual(y[0], check, eps99, eps99);
+        }
+        return ok;
+    }
     bool test_forward(void)
     {   bool ok = true;
 
@@ -259,6 +301,7 @@ namespace {
 bool azmul(void)
 {   bool ok = true;
 
+    ok &= test_base2ad();
     ok &= test_forward();
     ok &= test_reverse();
     ok &= test_forward_dir();
diff --git a/test_more/general/cpp_graph.cpp b/test_more/general/cpp_graph.cpp
new file mode 100644
index 000000000..c8c34841f
--- /dev/null
+++ b/test_more/general/cpp_graph.cpp
@@ -0,0 +1,144 @@
+/* --------------------------------------------------------------------------
+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 graph_unary_op.cpp$$
+$spell
+    sin
+$$
+
+$section Graph Unary Operator: Example and Test$$
+
+$head Source Code$$
+$srcthisfile%0%// BEGIN C++%// END C++%1%$$
+
+$end
+*/
+// BEGIN C++
+# include <cppad/cppad.hpp>
+
+namespace { // BEGIN_EMPTY_NAMESPACE
+
+typedef double (*unary_fun_t)(double);
+
+bool test_unary_fun(unary_fun_t fun, CppAD::graph::graph_op_enum op_enum)
+{   bool ok = true;
+    double eps99 = 99.0 * std::numeric_limits<double>::epsilon();
+    //
+    // C++ graph object
+    CppAD::cpp_graph graph_obj;
+    //
+    // value of constant in function
+    CPPAD_TESTVECTOR(double) p(1), x(1), c(1);
+    c[0] = 0.1;
+    p[0] = 0.2;
+    x[0] = 0.3;
+    if( std::isnan( fun( c[0] ) ) )
+        c[0] = 1.0;
+    if( std::isnan( fun( p[0] ) ) )
+        p[0] = 2.0;
+    if( std::isnan( fun( x[0] ) ) )
+        x[0] = 3.0;
+    //
+    // set scalars
+    graph_obj.function_name_set("unary_op example");
+    size_t n_dynamic_ind = 1;
+    graph_obj.n_dynamic_ind_set(n_dynamic_ind);
+    size_t n_variable_ind = 1;
+    graph_obj.n_variable_ind_set(n_variable_ind);
+    graph_obj.constant_vec_push_back( c[0] );
+    //
+    // node_4 : sin(p[0])
+    graph_obj.operator_vec_push_back(op_enum);
+    graph_obj.operator_arg_push_back(1);
+    //
+    // node_5 : sin(x[0])
+    graph_obj.operator_vec_push_back(op_enum);
+    graph_obj.operator_arg_push_back(2);
+    //
+    // node_6 : sin(c[0])
+    graph_obj.operator_vec_push_back(op_enum);
+    graph_obj.operator_arg_push_back(3);
+    //
+    // y[0]   = sin(p[0])
+    graph_obj.dependent_vec_push_back(4);
+    // y[1]   = sin(x[0])
+    graph_obj.dependent_vec_push_back(5);
+    // y[2]   = sin(c[0])
+    graph_obj.dependent_vec_push_back(6);
+    //
+    // f(p, x) = y
+    CppAD::ADFun<double> f;
+    f.from_graph(graph_obj);
+    ok &= f.Domain() == 1;
+    ok &= f.size_dyn_ind() == 1;
+    ok &= f.Range() == 3;
+    //
+    //
+    // compute y = f(p, x)
+    f.new_dynamic(p);
+    CPPAD_TESTVECTOR(double) y = f.Forward(0, x);
+    //
+    // check result
+    ok &= CppAD::NearEqual(y[0], fun(p[0]), eps99, eps99);
+    ok &= CppAD::NearEqual(y[1], fun(x[0]), eps99, eps99);
+    ok &= CppAD::NearEqual(y[2], fun(c[0]), eps99, eps99);
+    // ------------------------------------------------------------------
+    // Convert to Graph graph and back again
+    f.to_graph(graph_obj);
+    f.from_graph(graph_obj);
+    // -------------------------------------------------------------------
+    //
+    // compute y = f(p, x)
+    f.new_dynamic(p);
+    y = f.Forward(0, x);
+    //
+    // check result
+    ok &= CppAD::NearEqual(y[0], fun(p[0]), eps99, eps99);
+    ok &= CppAD::NearEqual(y[1], fun(x[0]), eps99, eps99);
+    ok &= CppAD::NearEqual(y[2], fun(c[0]), eps99, eps99);
+    //
+    return ok;
+}
+
+double sign(double x)
+{   return CppAD::sign(x);
+}
+double neg(double x)
+{   return - x;
+}
+
+} // END_EMPTY_NAMESPACE
+
+bool cpp_graph(void)
+{   bool ok = true;
+    ok     &= test_unary_fun(std::fabs,   CppAD::graph::abs_graph_op);
+    ok     &= test_unary_fun(std::acos,   CppAD::graph::acos_graph_op);
+    ok     &= test_unary_fun(std::acosh,  CppAD::graph::acosh_graph_op);
+    ok     &= test_unary_fun(std::asinh,  CppAD::graph::asinh_graph_op);
+    ok     &= test_unary_fun(std::atanh,  CppAD::graph::atanh_graph_op);
+    ok     &= test_unary_fun(std::erf,    CppAD::graph::erf_graph_op);
+    ok     &= test_unary_fun(std::erfc,   CppAD::graph::erfc_graph_op);
+    ok     &= test_unary_fun(std::expm1,  CppAD::graph::expm1_graph_op);
+    ok     &= test_unary_fun(std::log1p,  CppAD::graph::log1p_graph_op);
+    ok     &= test_unary_fun(neg,         CppAD::graph::neg_graph_op);
+    ok     &= test_unary_fun(sign,        CppAD::graph::sign_graph_op);
+    ok     &= test_unary_fun(std::sinh,   CppAD::graph::sinh_graph_op);
+    ok     &= test_unary_fun(std::sin,    CppAD::graph::sin_graph_op);
+    ok     &= test_unary_fun(std::sqrt,   CppAD::graph::sqrt_graph_op);
+    ok     &= test_unary_fun(std::tanh,   CppAD::graph::tanh_graph_op);
+    ok     &= test_unary_fun(std::tan,    CppAD::graph::tan_graph_op);
+    ok     &= test_unary_fun(std::acosh,  CppAD::graph::acosh_graph_op);
+    ok     &= test_unary_fun(std::acosh,  CppAD::graph::acosh_graph_op);
+    ok     &= test_unary_fun(std::sin,    CppAD::graph::sin_graph_op);
+    //
+    return ok;
+}
diff --git a/test_more/general/cppad_vector.cpp b/test_more/general/cppad_vector.cpp
index 3d02bba36..3a9a88e9d 100644
--- a/test_more/general/cppad_vector.cpp
+++ b/test_more/general/cppad_vector.cpp
@@ -1,5 +1,5 @@
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 Bradley M. Bell
+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.
@@ -75,6 +75,7 @@ bool test_reverse(void)
     return ok;
 }
 
+# ifndef  _MSC_VER
 bool test_sort(void)
 {   // copy requires a random access iterator
     bool ok = true;
@@ -91,6 +92,7 @@ bool test_sort(void)
     //
     return ok;
 }
+# endif
 
 
 } // END_EMPTY_NAMESPACE
@@ -101,7 +103,10 @@ bool cppad_vector(void)
     ok &= test_find();
     ok &= test_copy();
     ok &= test_reverse();
+// 2DO: Determine out why this test fails with Visual Studio 2019
+# ifndef  _MSC_VER
     ok &= test_sort();
+# endif
     //
     return ok;
 }
diff --git a/test_more/general/general.cpp b/test_more/general/general.cpp
index 9993b5fda..11fcef8af 100644
--- a/test_more/general/general.cpp
+++ b/test_more/general/general.cpp
@@ -1,5 +1,5 @@
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
+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.
@@ -23,6 +23,7 @@ in the Eclipse Public License, Version 2.0 are satisfied:
 # include <cppad/utility/test_boolofvoid.hpp>
 
 // BEGIN_SORT_THIS_LINE_PLUS_1
+extern bool abs_normal(void);
 extern bool acosh(void);
 extern bool acos(void);
 extern bool AddEq(void);
@@ -72,6 +73,7 @@ extern bool forward_order(void);
 extern bool Forward(void);
 extern bool FromBase(void);
 extern bool FunCheck(void);
+extern bool cpp_graph(void);
 extern bool hes_sparsity(void);
 extern bool ipopt_solve(void);
 extern bool jacobian(void);
@@ -145,6 +147,7 @@ int main(void)
 
     // BEGIN_SORT_THIS_LINE_PLUS_1
     Run( acos,            "acos"           );
+    Run( abs_normal,      "abs_normal"     );
     Run( acosh,           "acosh"          );
     Run( Add,             "Add"            );
     Run( AddEq,           "AddEq"          );
@@ -188,6 +191,7 @@ int main(void)
     Run( forward_order,   "forward_order"  );
     Run( FromBase,        "FromBase"       );
     Run( FunCheck,        "FunCheck"       );
+    Run( cpp_graph,       "cpp_graph"      );
     Run( hes_sparsity,    "hes_sparsity"   );
     Run( jacobian,        "jacobian"       );
     Run( json_graph,      "json_graph"     );
diff --git a/test_more/general/json_graph.cpp b/test_more/general/json_graph.cpp
index f8fb47de9..e3446f41c 100644
--- a/test_more/general/json_graph.cpp
+++ b/test_more/general/json_graph.cpp
@@ -1,5 +1,5 @@
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
+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.
@@ -2547,6 +2547,86 @@ bool cumulative_sum(void)
     // std::cout << graph;
     return ok;
 }
+// ---------------------------------------------------------------------------
+// Test unary operators
+bool unary(bool p_first)
+{   bool ok   = true;
+    using CppAD::AD;
+    //
+    size_t np = 11;
+    size_t nx = 11;
+    size_t ny = np + nx;
+    CPPAD_TESTVECTOR(double)       p(np),  x(nx), y(ny);
+    CPPAD_TESTVECTOR( AD<double> ) ap(np), ax(nx), ay(ny);
+    for(size_t i = 0; i < np; ++i)
+    {   p[i]  = double(i + 1) / double( np + nx + 1 );
+        ap[i] = p[i] / 2.0;
+    }
+    for(size_t i = 0; i < nx; ++i)
+    {   x[i]  = double(i + 1 + np) / double( np + nx + 1);
+        ax[i] = x[i] / 2.0;
+    }
+    CppAD::Independent(ax, ap);
+    //
+    CPPAD_TESTVECTOR( AD<double> ) atmp(np + nx);
+    if( p_first )
+    {   for(size_t i = 0; i < np; ++i)
+            atmp[i] = ap[i];
+        for(size_t i = 0; i < nx; ++i)
+            atmp[i + np] = ax[i];
+    }
+    else
+    {   for(size_t i = 0; i < np; ++i)
+            atmp[i + nx] = ap[i];
+        for(size_t i = 0; i < nx; ++i)
+            atmp[i] = ax[i];
+    }
+    //
+    ay[0]  = fabs(atmp[0]);
+    ay[1]  = acos(atmp[1]);
+    ay[2]  = acosh(atmp[2] + 1.0);
+    ay[3]  = asin(atmp[3]);
+    ay[4]  = asinh(atmp[4]);
+    ay[5]  = atan(atmp[5]);
+    ay[6]  = atanh(atmp[6]);
+    ay[7]  = cos(atmp[7]);
+    ay[8]  = cosh(atmp[8]);
+    ay[9]  = erf(atmp[9]);
+    ay[10] = erfc(atmp[10]);
+    ay[11] = exp(atmp[11]);
+    ay[12] = expm1(atmp[12]);
+    ay[13] = log(atmp[13]);
+    ay[14] = log1p(atmp[14]);
+    ay[15] = - atmp[15];
+    ay[16] = sign(atmp[16]);
+    ay[17] = sin(atmp[17]);
+    ay[18] = sinh(atmp[18]);
+    ay[19] = sqrt(atmp[19]);
+    ay[20] = tan(atmp[20]);
+    ay[21] = sin(atmp[21]);
+    // Create function
+    CppAD::ADFun<double> f(ax, ay);
+    f.optimize();
+    //
+    // Evaluate function at x before
+    f.new_dynamic(p);
+    CPPAD_TESTVECTOR(double) y_before = f.Forward(0, x);
+    //
+    // Convert to Json and back again
+    std::string json = f.to_json();
+    // std::cout << graph;
+    f.from_json(json);
+    //
+    // Evaluate function at x after
+    f.new_dynamic(p);
+    CPPAD_TESTVECTOR(double) y_after = f.Forward(0, x);
+    //
+    double eps99 = 99.0 * std::numeric_limits<double>::epsilon();
+    for(size_t i = 0; i < ny; ++i)
+        ok &= CppAD::NearEqual( y_before[i], y_after[i], eps99, eps99 );
+    //
+    return ok;
+}
 
 // ---------------------------------------------------------------------------
 } // END_EMPTY_NAMESPACE
@@ -2587,6 +2667,8 @@ bool json_graph(void)
     ok     &= to_json_and_back();
     ok     &= binary_operators();
     ok     &= cumulative_sum();
+    ok     &= unary(true);
+    ok     &= unary(false);
     //
     return ok;
 }
diff --git a/test_more/general/makefile.am b/test_more/general/makefile.am
index 0c73cbed3..b808104bd 100644
--- a/test_more/general/makefile.am
+++ b/test_more/general/makefile.am
@@ -1,5 +1,5 @@
 # -----------------------------------------------------------------------------
-# CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
+# 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.
@@ -73,6 +73,7 @@ general_SOURCES  = \
 	$(EIGEN_SRC_FILES) \
 	$(IPOPT_SRC_FILES) \
 	$(OPENMP_SRC_FILES) \
+	abs_normal.cpp \
 	acos.cpp \
 	acosh.cpp \
 	add.cpp \
@@ -121,6 +122,7 @@ general_SOURCES  = \
 	from_base.cpp \
 	fun_check.cpp \
 	general.cpp \
+	cpp_graph.cpp \
 	hes_sparsity.cpp \
 	jacobian.cpp \
 	json_graph.cpp \
diff --git a/test_more/general/makefile.in b/test_more/general/makefile.in
index 40bc3f756..410aa6fbd 100644
--- a/test_more/general/makefile.in
+++ b/test_more/general/makefile.in
@@ -98,22 +98,22 @@ mkinstalldirs = $(install_sh) -d
 CONFIG_CLEAN_FILES =
 CONFIG_CLEAN_VPATH_FILES =
 am__general_SOURCES_DIST = base_adolc.cpp cppad_eigen.cpp \
-	eigen_mat_inv.cpp ipopt_solve.cpp alloc_openmp.cpp acos.cpp \
-	acosh.cpp add.cpp add_eq.cpp add_zero.cpp adfun.cpp asin.cpp \
-	asinh.cpp assign.cpp atan2.cpp atan.cpp atanh.cpp \
-	atomic_three.cpp azmul.cpp base_alloc.cpp bool_sparsity.cpp \
-	check_simple_vector.cpp chkpoint_one.cpp chkpoint_two.cpp \
-	compare_change.cpp compare.cpp cond_exp_ad.cpp cond_exp.cpp \
-	cond_exp_rev.cpp copy.cpp cos.cpp cosh.cpp cppad_vector.cpp \
-	dbl_epsilon.cpp dependency.cpp div.cpp div_eq.cpp \
-	div_zero_one.cpp erf.cpp exp.cpp expm1.cpp extern_value.cpp \
-	extern_value.hpp fabs.cpp for_hess.cpp for_sparse_hes.cpp \
-	for_sparse_jac.cpp forward.cpp forward_dir.cpp \
-	forward_order.cpp from_base.cpp fun_check.cpp general.cpp \
-	hes_sparsity.cpp jacobian.cpp json_graph.cpp local/is_pod.cpp \
-	local/json_lexer.cpp local/json_parser.cpp \
-	local/vector_set.cpp log10.cpp log1p.cpp log.cpp \
-	mul_cond_rev.cpp mul.cpp mul_cskip.cpp mul_eq.cpp \
+	eigen_mat_inv.cpp ipopt_solve.cpp alloc_openmp.cpp \
+	abs_normal.cpp acos.cpp acosh.cpp add.cpp add_eq.cpp \
+	add_zero.cpp adfun.cpp asin.cpp asinh.cpp assign.cpp atan2.cpp \
+	atan.cpp atanh.cpp atomic_three.cpp azmul.cpp base_alloc.cpp \
+	bool_sparsity.cpp check_simple_vector.cpp chkpoint_one.cpp \
+	chkpoint_two.cpp compare_change.cpp compare.cpp \
+	cond_exp_ad.cpp cond_exp.cpp cond_exp_rev.cpp copy.cpp cos.cpp \
+	cosh.cpp cppad_vector.cpp dbl_epsilon.cpp dependency.cpp \
+	div.cpp div_eq.cpp div_zero_one.cpp erf.cpp exp.cpp expm1.cpp \
+	extern_value.cpp extern_value.hpp fabs.cpp for_hess.cpp \
+	for_sparse_hes.cpp for_sparse_jac.cpp forward.cpp \
+	forward_dir.cpp forward_order.cpp from_base.cpp fun_check.cpp \
+	general.cpp cpp_graph.cpp hes_sparsity.cpp jacobian.cpp \
+	json_graph.cpp local/is_pod.cpp local/json_lexer.cpp \
+	local/json_parser.cpp local/vector_set.cpp log10.cpp log1p.cpp \
+	log.cpp mul_cond_rev.cpp mul.cpp mul_cskip.cpp mul_eq.cpp \
 	mul_level.cpp mul_zdouble.cpp mul_zero_one.cpp \
 	near_equal_ext.cpp neg.cpp new_dynamic.cpp num_limits.cpp \
 	ode_err_control.cpp optimize.cpp parameter.cpp poly.cpp \
@@ -133,8 +133,8 @@ am__general_SOURCES_DIST = base_adolc.cpp cppad_eigen.cpp \
 @CppAD_OPENMP_TRUE@am__objects_4 = alloc_openmp.$(OBJEXT)
 am__dirstamp = $(am__leading_dot)dirstamp
 am_general_OBJECTS = $(am__objects_1) $(am__objects_2) \
-	$(am__objects_3) $(am__objects_4) acos.$(OBJEXT) \
-	acosh.$(OBJEXT) add.$(OBJEXT) add_eq.$(OBJEXT) \
+	$(am__objects_3) $(am__objects_4) abs_normal.$(OBJEXT) \
+	acos.$(OBJEXT) acosh.$(OBJEXT) add.$(OBJEXT) add_eq.$(OBJEXT) \
 	add_zero.$(OBJEXT) adfun.$(OBJEXT) asin.$(OBJEXT) \
 	asinh.$(OBJEXT) assign.$(OBJEXT) atan2.$(OBJEXT) \
 	atan.$(OBJEXT) atanh.$(OBJEXT) atomic_three.$(OBJEXT) \
@@ -151,18 +151,18 @@ am_general_OBJECTS = $(am__objects_1) $(am__objects_2) \
 	for_sparse_jac.$(OBJEXT) forward.$(OBJEXT) \
 	forward_dir.$(OBJEXT) forward_order.$(OBJEXT) \
 	from_base.$(OBJEXT) fun_check.$(OBJEXT) general.$(OBJEXT) \
-	hes_sparsity.$(OBJEXT) jacobian.$(OBJEXT) json_graph.$(OBJEXT) \
-	local/is_pod.$(OBJEXT) local/json_lexer.$(OBJEXT) \
-	local/json_parser.$(OBJEXT) local/vector_set.$(OBJEXT) \
-	log10.$(OBJEXT) log1p.$(OBJEXT) log.$(OBJEXT) \
-	mul_cond_rev.$(OBJEXT) mul.$(OBJEXT) mul_cskip.$(OBJEXT) \
-	mul_eq.$(OBJEXT) mul_level.$(OBJEXT) mul_zdouble.$(OBJEXT) \
-	mul_zero_one.$(OBJEXT) near_equal_ext.$(OBJEXT) neg.$(OBJEXT) \
-	new_dynamic.$(OBJEXT) num_limits.$(OBJEXT) \
-	ode_err_control.$(OBJEXT) optimize.$(OBJEXT) \
-	parameter.$(OBJEXT) poly.$(OBJEXT) pow.$(OBJEXT) \
-	pow_int.$(OBJEXT) print_for.$(OBJEXT) reverse.$(OBJEXT) \
-	rev_sparse_jac.$(OBJEXT) rev_two.$(OBJEXT) \
+	cpp_graph.$(OBJEXT) hes_sparsity.$(OBJEXT) jacobian.$(OBJEXT) \
+	json_graph.$(OBJEXT) local/is_pod.$(OBJEXT) \
+	local/json_lexer.$(OBJEXT) local/json_parser.$(OBJEXT) \
+	local/vector_set.$(OBJEXT) log10.$(OBJEXT) log1p.$(OBJEXT) \
+	log.$(OBJEXT) mul_cond_rev.$(OBJEXT) mul.$(OBJEXT) \
+	mul_cskip.$(OBJEXT) mul_eq.$(OBJEXT) mul_level.$(OBJEXT) \
+	mul_zdouble.$(OBJEXT) mul_zero_one.$(OBJEXT) \
+	near_equal_ext.$(OBJEXT) neg.$(OBJEXT) new_dynamic.$(OBJEXT) \
+	num_limits.$(OBJEXT) ode_err_control.$(OBJEXT) \
+	optimize.$(OBJEXT) parameter.$(OBJEXT) poly.$(OBJEXT) \
+	pow.$(OBJEXT) pow_int.$(OBJEXT) print_for.$(OBJEXT) \
+	reverse.$(OBJEXT) rev_sparse_jac.$(OBJEXT) rev_two.$(OBJEXT) \
 	romberg_one.$(OBJEXT) rosen_34.$(OBJEXT) runge_45.$(OBJEXT) \
 	simple_vector.$(OBJEXT) sin_cos.$(OBJEXT) sin.$(OBJEXT) \
 	sinh.$(OBJEXT) sparse_hessian.$(OBJEXT) \
@@ -196,8 +196,8 @@ am__v_at_1 =
 DEFAULT_INCLUDES = 
 depcomp = $(SHELL) $(top_srcdir)/depcomp
 am__maybe_remake_depfiles = depfiles
-am__depfiles_remade = ./$(DEPDIR)/acos.Po ./$(DEPDIR)/acosh.Po \
-	./$(DEPDIR)/add.Po ./$(DEPDIR)/add_eq.Po \
+am__depfiles_remade = ./$(DEPDIR)/abs_normal.Po ./$(DEPDIR)/acos.Po \
+	./$(DEPDIR)/acosh.Po ./$(DEPDIR)/add.Po ./$(DEPDIR)/add_eq.Po \
 	./$(DEPDIR)/add_zero.Po ./$(DEPDIR)/adfun.Po \
 	./$(DEPDIR)/alloc_openmp.Po ./$(DEPDIR)/asin.Po \
 	./$(DEPDIR)/asinh.Po ./$(DEPDIR)/assign.Po ./$(DEPDIR)/atan.Po \
@@ -210,11 +210,12 @@ am__depfiles_remade = ./$(DEPDIR)/acos.Po ./$(DEPDIR)/acosh.Po \
 	./$(DEPDIR)/compare_change.Po ./$(DEPDIR)/cond_exp.Po \
 	./$(DEPDIR)/cond_exp_ad.Po ./$(DEPDIR)/cond_exp_rev.Po \
 	./$(DEPDIR)/copy.Po ./$(DEPDIR)/cos.Po ./$(DEPDIR)/cosh.Po \
-	./$(DEPDIR)/cppad_eigen.Po ./$(DEPDIR)/cppad_vector.Po \
-	./$(DEPDIR)/dbl_epsilon.Po ./$(DEPDIR)/dependency.Po \
-	./$(DEPDIR)/div.Po ./$(DEPDIR)/div_eq.Po \
-	./$(DEPDIR)/div_zero_one.Po ./$(DEPDIR)/eigen_mat_inv.Po \
-	./$(DEPDIR)/erf.Po ./$(DEPDIR)/exp.Po ./$(DEPDIR)/expm1.Po \
+	./$(DEPDIR)/cpp_graph.Po ./$(DEPDIR)/cppad_eigen.Po \
+	./$(DEPDIR)/cppad_vector.Po ./$(DEPDIR)/dbl_epsilon.Po \
+	./$(DEPDIR)/dependency.Po ./$(DEPDIR)/div.Po \
+	./$(DEPDIR)/div_eq.Po ./$(DEPDIR)/div_zero_one.Po \
+	./$(DEPDIR)/eigen_mat_inv.Po ./$(DEPDIR)/erf.Po \
+	./$(DEPDIR)/exp.Po ./$(DEPDIR)/expm1.Po \
 	./$(DEPDIR)/extern_value.Po ./$(DEPDIR)/fabs.Po \
 	./$(DEPDIR)/for_hess.Po ./$(DEPDIR)/for_sparse_hes.Po \
 	./$(DEPDIR)/for_sparse_jac.Po ./$(DEPDIR)/forward.Po \
@@ -331,7 +332,7 @@ CXX_FLAGS = @CXX_FLAGS@
 CYGPATH_W = @CYGPATH_W@
 
 # -----------------------------------------------------------------------------
-# CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
+# 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.
@@ -414,7 +415,6 @@ 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@
@@ -469,6 +469,7 @@ pdfdir = @pdfdir@
 prefix = @prefix@
 program_transform_name = @program_transform_name@
 psdir = @psdir@
+runstatedir = @runstatedir@
 sbindir = @sbindir@
 sharedstatedir = @sharedstatedir@
 srcdir = @srcdir@
@@ -523,6 +524,7 @@ general_SOURCES = \
 	$(EIGEN_SRC_FILES) \
 	$(IPOPT_SRC_FILES) \
 	$(OPENMP_SRC_FILES) \
+	abs_normal.cpp \
 	acos.cpp \
 	acosh.cpp \
 	add.cpp \
@@ -571,6 +573,7 @@ general_SOURCES = \
 	from_base.cpp \
 	fun_check.cpp \
 	general.cpp \
+	cpp_graph.cpp \
 	hes_sparsity.cpp \
 	jacobian.cpp \
 	json_graph.cpp \
@@ -692,6 +695,7 @@ mostlyclean-compile:
 distclean-compile:
 	-rm -f *.tab.c
 
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/abs_normal.Po@am__quote@ # am--include-marker
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/acos.Po@am__quote@ # am--include-marker
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/acosh.Po@am__quote@ # am--include-marker
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/add.Po@am__quote@ # am--include-marker
@@ -721,6 +725,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/copy.Po@am__quote@ # am--include-marker
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cos.Po@am__quote@ # am--include-marker
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cosh.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cpp_graph.Po@am__quote@ # am--include-marker
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cppad_eigen.Po@am__quote@ # am--include-marker
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cppad_vector.Po@am__quote@ # am--include-marker
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dbl_epsilon.Po@am__quote@ # am--include-marker
@@ -952,7 +957,8 @@ clean: clean-am
 clean-am: clean-checkPROGRAMS clean-generic mostlyclean-am
 
 distclean: distclean-am
-		-rm -f ./$(DEPDIR)/acos.Po
+		-rm -f ./$(DEPDIR)/abs_normal.Po
+	-rm -f ./$(DEPDIR)/acos.Po
 	-rm -f ./$(DEPDIR)/acosh.Po
 	-rm -f ./$(DEPDIR)/add.Po
 	-rm -f ./$(DEPDIR)/add_eq.Po
@@ -981,6 +987,7 @@ distclean: distclean-am
 	-rm -f ./$(DEPDIR)/copy.Po
 	-rm -f ./$(DEPDIR)/cos.Po
 	-rm -f ./$(DEPDIR)/cosh.Po
+	-rm -f ./$(DEPDIR)/cpp_graph.Po
 	-rm -f ./$(DEPDIR)/cppad_eigen.Po
 	-rm -f ./$(DEPDIR)/cppad_vector.Po
 	-rm -f ./$(DEPDIR)/dbl_epsilon.Po
@@ -1107,7 +1114,8 @@ install-ps-am:
 installcheck-am:
 
 maintainer-clean: maintainer-clean-am
-		-rm -f ./$(DEPDIR)/acos.Po
+		-rm -f ./$(DEPDIR)/abs_normal.Po
+	-rm -f ./$(DEPDIR)/acos.Po
 	-rm -f ./$(DEPDIR)/acosh.Po
 	-rm -f ./$(DEPDIR)/add.Po
 	-rm -f ./$(DEPDIR)/add_eq.Po
@@ -1136,6 +1144,7 @@ maintainer-clean: maintainer-clean-am
 	-rm -f ./$(DEPDIR)/copy.Po
 	-rm -f ./$(DEPDIR)/cos.Po
 	-rm -f ./$(DEPDIR)/cosh.Po
+	-rm -f ./$(DEPDIR)/cpp_graph.Po
 	-rm -f ./$(DEPDIR)/cppad_eigen.Po
 	-rm -f ./$(DEPDIR)/cppad_vector.Po
 	-rm -f ./$(DEPDIR)/dbl_epsilon.Po
diff --git a/test_more/general/ode_err_control.cpp b/test_more/general/ode_err_control.cpp
index aac02b0e7..a3ada7ca8 100644
--- a/test_more/general/ode_err_control.cpp
+++ b/test_more/general/ode_err_control.cpp
@@ -1,5 +1,5 @@
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-17 Bradley M. Bell
+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.
@@ -268,7 +268,7 @@ namespace {
             // case where ODE does not make sense
             if( x[0] < 0. || x[1] < 0. )
             {   was_negative_ = true;
-                f[0] = CppAD::nan(0.);
+                f[0] = std::numeric_limits<double>::quiet_NaN();
             }
         }
         // set f_t = df / dt
@@ -281,7 +281,7 @@ namespace {
             f_t[1] = 0.;
             if( x[0] < 0. || x[1] < 0. )
             {   was_negative_ = true;
-                f_t[0] = CppAD::nan(0.);
+                f_t[0] = std::numeric_limits<double>::quiet_NaN();
             }
         }
         // set f_x = df / dx
@@ -296,7 +296,7 @@ namespace {
             f_x[1 * 2 + 1] = 0.;                // f1 w.r.t. x1
             if( x[0] < 0. || x[1] < 0. )
             {   was_negative_ = true;
-                f_x[0] = CppAD::nan(0.);
+                f_x[0] = std::numeric_limits<double>::quiet_NaN();
             }
         }
         bool was_negative(void)
@@ -391,7 +391,7 @@ namespace {
             const CppAD::vector<double> &x,
             CppAD::vector<double>       &f)
         {   size_t i;
-            f[0] = CppAD::nan(0.);
+            f[0] = std::numeric_limits<double>::quiet_NaN();
             for(i = 1; i < n; i++)
                 f[i] = double(i+1) * x[i-1];
         }
@@ -469,4 +469,3 @@ bool ode_err_control(void)
     ok     &= OdeErrControl_four();
     return ok;
 }
-
diff --git a/test_more/general/pow.cpp b/test_more/general/pow.cpp
index 28dbdf5af..b1074b705 100644
--- a/test_more/general/pow.cpp
+++ b/test_more/general/pow.cpp
@@ -1,5 +1,5 @@
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
+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.
@@ -411,43 +411,6 @@ bool PowTestSix(void)
     return ok;
 }
 
-/*
-// This test does not pass because azmul is used be reverse mode to deteremine which
-// partials are slected and the result is zero instead of nan or infinity.
-// There is a wish list item to fix this problem.
-bool PowTestSeven(void)
-{   bool ok = true;
-
-    using std::cout;
-    using CppAD::AD;
-    using CppAD::vector;
-    //
-    vector< double> x(1), y(1), dx(1), dy(1), w(1), dw(2);
-    vector< AD<double> > ax(1), ay(1);
-    //
-    ax[0] = 0.0;
-    //
-    CppAD::Independent(ax);
-    ay[0] = pow(ax[0], 0.5);
-    CppAD::ADFun<double> f(ax, ay);
-    f.check_for_nan(false);
-    //
-    x[0]  = 0.0;
-    y     = f.Forward(0, x);
-    //
-    dx[0] = 1.0;
-    dy    = f.Forward(1, dx);
-    //
-    w[0]  = 1.0;
-    dw    = f.Reverse(2, w);
-    //
-    ok &= y[0] == 0.0;
-    ok &= ! std::isfinite( dw[0] );
-    ok &= ! std::isfinite( dw[1] );
-    //
-    return ok;
-}
-*/
 // Test x^e where x is negative and e is AD<double> equal to an integer
 bool PowTestEight(void)
 {   bool ok = true;
@@ -458,7 +421,7 @@ bool PowTestEight(void)
     using CppAD::NearEqual;
     double eps99 = 99.0 * std::numeric_limits<double>::epsilon();
     //
-    vector< double>      x(1), y(2), dx(1), dy(2), w(2), dw(2);
+    vector<double>      x(1), y(2), dx(1), dy(2), w(2), dw(2);
     vector< AD<double> > ax(1), ay(2);
     //
     x[0]  = -2.0;
@@ -502,6 +465,148 @@ bool PowTestEight(void)
     //
     return ok;
 }
+// k-th derivative of x^y .w.r.t. x
+double dpow_dx(double x, double y, size_t k)
+{   double result = std::pow(x, y - double(k));
+    for(size_t ell = 0; ell < k; ++ell)
+        result *= (y - double(ell));
+    return result;
+}
+// Testing PowvpOp
+bool PowTestNine(void)
+{   bool ok = true;
+    //
+    using std::cout;
+    using CppAD::AD;
+    using CppAD::vector;
+    using CppAD::NearEqual;
+    double eps99 = 99.0 * std::numeric_limits<double>::epsilon();
+    //
+    vector<double> x(1), dx(1);
+    vector<double> z(1), dz(1);
+    vector<double> w(1), dw(5);
+    vector< AD<double> > ax(1), az(1);
+    //
+    ax[0]    = 1.0;
+    double y = 2.5;
+    //
+    CppAD::Independent(ax);
+    az[0] = pow(ax[0], y);
+    CppAD::ADFun<double> f(ax, az);
+    //
+    double check;
+    //
+    // zero order forward
+    for(size_t ix = 0; ix < 3; ++ix)
+    {   x[0]  = double(ix);
+        z     = f.Forward(0, x);
+        check = dpow_dx(x[0], y, 0);
+        ok   &= NearEqual(z[0], check, eps99, eps99);
+        //
+        // first order forward
+        dx[0] = 1.0;
+        dz    = f.Forward(1, dx);
+        check = dpow_dx(x[0], y, 1);
+        ok   &= NearEqual(dz[0], check, eps99, eps99);
+        //
+        // ell-th order forward
+        double factorial = 1.0;
+        for(size_t k = 2; k < 5; ++k)
+        {   factorial *= double(k);
+            dx[0]      = 0.0; // x^(k)
+            dz         = f.Forward(k, dx);
+            check      = dpow_dx(x[0], y, k) / factorial;
+            ok        &= NearEqual(dz[0], check, eps99, eps99);
+        }
+        // second order reverse
+        w[0]  = 1.0;
+        dw    = f.Reverse(5, w);
+        factorial = 1.0;
+        for(size_t k = 0; k < 5; ++k)
+        {   check = dpow_dx(x[0], y, k+1) / factorial;
+            ok   &= NearEqual(dw[k], check, eps99, eps99);
+            factorial *= double(k+1);
+        }
+    }
+    //
+    return ok;
+}
+// Testing PowvpOp multiple direction forward
+bool PowTestTen(void)
+{   bool ok = true;
+    //
+    using std::cout;
+    using CppAD::AD;
+    using CppAD::vector;
+    using CppAD::NearEqual;
+    double eps99 = 99.0 * std::numeric_limits<double>::epsilon();
+    //
+    size_t n = 3;
+    vector<double> x(n), xq(n * n);
+    vector<double> z(n), zq(n * n);
+    vector<double> y(n);
+    vector< AD<double> > ax(n), az(n);
+    //
+    for(size_t j = 0; j < n; ++j)
+    {   ax[j] = double(j);
+        y[j]  = double(j) + 1.5;
+    }
+    //
+    CppAD::Independent(ax);
+    for(size_t j = 0; j < n; ++j)
+        az[j] = pow(ax[j], y[j]);
+    CppAD::ADFun<double> f(ax, az);
+    //
+    // zero order forward
+    for(size_t j = 0; j < n; ++j)
+        x[j]  = double(j) + 1.5;
+    z     = f.Forward(0, x);
+    double check;
+    for(size_t j = 0; j < n; ++j)
+    {   check = dpow_dx(x[j], y[j], 0);
+        ok   &= NearEqual(z[j], check, eps99, eps99);
+    }
+    //
+    // first order forward multiple directions
+    size_t r = n;
+    for(size_t j = 0; j < n; ++j)
+    {   for(size_t ell = 0; ell < r; ell++)
+        {   if( j == ell )
+                xq[ r * j + ell] = 1.0;
+            else
+                xq[ r * j + ell] = 0.0;
+        }
+    }
+    size_t q = 1;
+    zq = f.Forward(q, r, xq);
+    for(size_t j = 0; j < n; ++j)
+    {   for(size_t ell = 0; ell < r; ell++)
+        {   if( j == ell )
+                check = dpow_dx(x[j], y[j], 1);
+            else
+                check = 0.0;
+            ok   &= NearEqual(zq[r * j + ell], check, eps99, eps99);
+        }
+    }
+    //
+    // second order forward multiple directions
+    for(size_t j = 0; j < n; ++j)
+    {   for(size_t ell = 0; ell < r; ell++)
+                xq[ r * j + ell] = 0.0;
+    }
+    q = 2;
+    zq = f.Forward(q, r, xq);
+    for(size_t j = 0; j < n; ++j)
+    {   for(size_t ell = 0; ell < r; ell++)
+        {   if( j == ell )
+                check = dpow_dx(x[j], y[j], 2) / 2.0;
+            else
+                check = 0.0;
+            ok   &= NearEqual(zq[r * j + ell], check, eps99, eps99);
+        }
+    }
+    return ok;
+}
 
 } // END empty namespace
 
@@ -513,8 +618,10 @@ bool Pow(void)
     ok     &= PowTestFour();
     ok     &= PowTestFive();
     ok     &= PowTestSix();
-    // ok     &= PowTestSeven();
+    // PowTestSeven was removed
     ok     &= PowTestEight();
+    ok     &= PowTestNine();
+    ok     &= PowTestTen();
     //
     return ok;
 }
diff --git a/test_more/general/reverse.cpp b/test_more/general/reverse.cpp
index 233e68782..4fa95093a 100644
--- a/test_more/general/reverse.cpp
+++ b/test_more/general/reverse.cpp
@@ -1,5 +1,5 @@
 /* --------------------------------------------------------------------------
-CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 Bradley M. Bell
+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.
@@ -452,6 +452,49 @@ bool reverse_mul(void)
     return ok;
 }
 // ----------------------------------------------------------------------------
+bool duplicate_dependent_var(void)
+{   bool ok = true;
+    using CppAD::AD;
+
+    // f(x) = [ y_0, y_1 ] = [ x_0 * x_0 , x_0 * x_0 ]
+    size_t nx = 1;
+    size_t ny = 2;
+    CPPAD_TESTVECTOR( AD<double> ) ax(nx), ay(ny);
+    ax[0] = 1.0;
+    CppAD::Independent(ax);
+    ay[0] = ax[0] * ax[0];
+    ay[1] = ay[0];
+    CppAD::ADFun<double> f(ax, ay);
+    //
+    // Forward zero
+    CPPAD_TESTVECTOR(double) x0(nx), x1(nx), yk(ny);
+    x0[0] = 3.0;
+    yk = f.Forward(0, x0);
+    ok &= yk[0] == x0[0] * x0[0];
+    ok &= yk[1] == yk[0];
+    //
+    // Forward one
+    x1[0] = 1.0;
+    yk = f.Forward(1, x1);
+    ok &= yk[0] == 2.0 * x0[0];
+    ok &= yk[1] == yk[0];
+    //
+    // Reverse two
+    size_t q = 2; // number of orders
+    CPPAD_TESTVECTOR(double) w(ny * q), dw(nx * q);
+    for(size_t i = 0; i < ny; ++i)
+    {   w[ i * q + 0 ] = 0.0; // derivative w.r.t. zero order coefficient
+        w[ i * q + 1 ] = 1.0; // derivative w.r.t. first order coefficient
+    }
+    dw = f.Reverse(2, w);
+    // derivative w.r.t zero order coefficients
+    ok &= dw[nx * 0 + 0] == 4.0;
+    // derivative w.r.t first order coefficients
+    ok &= dw[nx * 0 + 1] == 4.0 * x0[0];
+    //
+    return ok;
+}
+
 } // End empty namespace
 
 # include <vector>
@@ -460,6 +503,7 @@ bool reverse(void)
 {   bool ok = true;
     ok &= reverse_one();
     ok &= reverse_mul();
+    ok &= duplicate_dependent_var();
 
     ok &= reverse_any_cases< CppAD::vector  <double> >();
     ok &= reverse_any_cases< std::vector    <double> >();