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>
+