# ifndef CPPAD_LOCAL_INDEPENDENT_HPP
# define CPPAD_LOCAL_INDEPENDENT_HPP
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
// SPDX-FileCopyrightText: Bradley M. Bell <bradbell@seanet.com>
// SPDX-FileContributor: 2003-25 Bradley M. Bell
// ----------------------------------------------------------------------------
namespace CppAD { namespace local { //  BEGIN_CPPAD_LOCAL_NAMESPACE
/*
\file local/independent.hpp
Start recording AD<Base> operations.
*/

/*!
Start recording AD<Base> operations: Implementation in local namespace.

\tparam ADVector
This is simple vector type with elements of type AD<Base>.

\param x
Vector of the independent variables.

\param abort_op_index
operator index at which execution will be aborted (during  the recording

\param record_compare
should comparison operators be recorded.
of operations). The value zero corresponds to not aborting (will not match).

\param dynamic
Vector of dynamic parameters.
*/
template <class Base>
template <class ADVector>
void ADTape<Base>::Independent(
   ADVector&    x               ,
   size_t       abort_op_index  ,
   bool         record_compare  ,
   ADVector&    dynamic
) {
   // check ADVector is Simple Vector class with AD<Base> elements
   CheckSimpleVector< AD<Base>, ADVector>();

   // dimension of the domain space
   size_t n = x.size();
   CPPAD_ASSERT_KNOWN(
      n > 0,
      "Independent: the argument vector x has zero size"
   );
   CPPAD_ASSERT_UNKNOWN( Rec_.num_var() == 0 );
   CPPAD_ASSERT_UNKNOWN( Rec_.get_abort_op_index() == 0 );
   CPPAD_ASSERT_UNKNOWN( Rec_.get_record_compare() == true );
   CPPAD_ASSERT_UNKNOWN( Rec_.n_dyn_independent()    == 0 );

   // set record_compare and abort_op_index before doing anything else
   Rec_.set_record_compare(record_compare);
   Rec_.set_abort_op_index(abort_op_index);
   Rec_.set_n_dyn_independent( dynamic.size() );

   // mark the beginning of the tape and skip the first variable index
   // (zero) because parameters use taddr zero
   CPPAD_ASSERT_NARG_NRES(BeginOp, 1, 1);
   Rec_.PutOp(BeginOp);
   Rec_.PutArg(0);

   // place each of the independent variables in the tape
   CPPAD_ASSERT_NARG_NRES(InvOp, 0, 1);
   for(size_t j = 0; j < n; j++)
   {  // tape address for this independent variable
      CPPAD_ASSERT_UNKNOWN( ! Variable(x[j] ) );
      x[j].taddr_     = Rec_.PutOp(InvOp);
      x[j].tape_id_   = id_;
      x[j].ad_type_   = variable_enum;
      CPPAD_ASSERT_UNKNOWN( size_t(x[j].taddr_) == j+1 );
      CPPAD_ASSERT_UNKNOWN( Variable(x[j] ) );
   }

   // done specifying all of the independent variables
   size_independent_ = n;

   // parameter index zero is used by dynamic parameter tape
   // to indicate that an argument is a variable
   Base nan = CppAD::numeric_limits<Base>::quiet_NaN();
# ifndef NDEBUG
   CPPAD_ASSERT_UNKNOWN( Rec_.put_con_par(nan) == 0 );
# else
   Rec_.put_con_par(nan);
# endif

   // Place independent dynamic parameters at beginning of parameter vector,
   // just after the nan at index zero.
   CPPAD_ASSERT_UNKNOWN( Rec_.n_dyn_independent() <= dynamic.size() );
   for(size_t j = 0; j < Rec_.n_dyn_independent(); ++j)
   {  CPPAD_ASSERT_UNKNOWN( ! Dynamic( dynamic[j] ) );
      CPPAD_ASSERT_UNKNOWN( Parameter( dynamic[j] ) );
      //
      // dynamic parameters are placed at the end, so i == j
# ifndef NDEBUG
      addr_t i = Rec_.put_dyn_par(dynamic[j].value_ , ind_dyn);
      CPPAD_ASSERT_UNKNOWN( size_t(i) == j+1 );
# else
      Rec_.put_dyn_par(dynamic[j].value_ , ind_dyn);
# endif
      //
      // make this parameter dynamic
      dynamic[j].taddr_   = static_cast<addr_t>(j+1);
      dynamic[j].tape_id_ = id_;
      dynamic[j].ad_type_ = dynamic_enum;
      CPPAD_ASSERT_UNKNOWN( Dynamic( dynamic[j] ) );
   }
}
} } // END_CPPAD_LOCAL_NAMESPACE

# endif
