mirror of
https://github.com/dragonpilot/dragonpilot.git
synced 2026-06-25 07:52:03 +08:00
external folder
This commit is contained in:
@@ -0,0 +1,175 @@
|
||||
# ifndef CPPAD_UTILITY_CHECK_NUMERIC_TYPE_HPP
|
||||
# define CPPAD_UTILITY_CHECK_NUMERIC_TYPE_HPP
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-17 Bradley M. Bell
|
||||
|
||||
CppAD is distributed under multiple licenses. This distribution is under
|
||||
the terms of the
|
||||
Eclipse Public License Version 1.0.
|
||||
|
||||
A copy of this license is included in the COPYING file of this distribution.
|
||||
Please visit http://www.coin-or.org/CppAD/ for information on other licenses.
|
||||
-------------------------------------------------------------------------- */
|
||||
/*
|
||||
$begin CheckNumericType$$
|
||||
$spell
|
||||
alloc
|
||||
cppad.hpp
|
||||
CppAD
|
||||
$$
|
||||
|
||||
$section Check NumericType Class Concept$$
|
||||
$mindex numeric CheckNumericType$$
|
||||
|
||||
|
||||
$head Syntax$$
|
||||
$codei%# include <cppad/utility/check_numeric_type.hpp>
|
||||
%$$
|
||||
$codei%CheckNumericType<%NumericType%>()%$$
|
||||
|
||||
|
||||
$head Purpose$$
|
||||
The syntax
|
||||
$codei%
|
||||
CheckNumericType<%NumericType%>()
|
||||
%$$
|
||||
preforms compile and run time checks that the type specified
|
||||
by $icode NumericType$$ satisfies all the requirements for
|
||||
a $cref NumericType$$ class.
|
||||
If a requirement is not satisfied,
|
||||
a an error message makes it clear what condition is not satisfied.
|
||||
|
||||
$head Include$$
|
||||
The file $code cppad/check_numeric_type.hpp$$ is included by $code cppad/cppad.hpp$$
|
||||
but it can also be included separately with out the rest
|
||||
if the CppAD include files.
|
||||
|
||||
$head Parallel Mode$$
|
||||
The routine $cref/thread_alloc::parallel_setup/ta_parallel_setup/$$
|
||||
must be called before it
|
||||
can be used in $cref/parallel/ta_in_parallel/$$ mode.
|
||||
|
||||
$head Example$$
|
||||
$children%
|
||||
example/utility/check_numeric_type.cpp
|
||||
%$$
|
||||
The file $cref check_numeric_type.cpp$$
|
||||
contains an example and test of this function.
|
||||
It returns true, if it succeeds an false otherwise.
|
||||
The comments in this example suggest a way to change the example
|
||||
so an error message occurs.
|
||||
|
||||
$end
|
||||
---------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
# include <cstddef>
|
||||
# include <cppad/utility/thread_alloc.hpp>
|
||||
|
||||
namespace CppAD {
|
||||
|
||||
# ifdef NDEBUG
|
||||
template <class NumericType>
|
||||
void CheckNumericType(void)
|
||||
{ }
|
||||
# else
|
||||
template <class NumericType>
|
||||
NumericType CheckNumericType(void)
|
||||
{ // Section 3.6.2 of ISO/IEC 14882:1998(E) states: "The storage for
|
||||
// objects with static storage duration (3.7.1) shall be zero-
|
||||
// initialized (8.5) before any other initialization takes place."
|
||||
static size_t count[CPPAD_MAX_NUM_THREADS];
|
||||
size_t thread = thread_alloc::thread_num();
|
||||
if( count[thread] > 0 )
|
||||
return NumericType(0);
|
||||
count[thread]++;
|
||||
/*
|
||||
contructors
|
||||
*/
|
||||
NumericType check_NumericType_default_constructor;
|
||||
NumericType check_NumericType_constructor_from_int(1);
|
||||
|
||||
const NumericType x(1);
|
||||
|
||||
NumericType check_NumericType_copy_constructor(x);
|
||||
|
||||
// assignment
|
||||
NumericType check_NumericType_assignment;
|
||||
check_NumericType_assignment = x;
|
||||
|
||||
/*
|
||||
unary operators
|
||||
*/
|
||||
const NumericType check_NumericType_unary_plus(1);
|
||||
NumericType check_NumericType_unary_plus_result =
|
||||
+ check_NumericType_unary_plus;
|
||||
|
||||
const NumericType check_NumericType_unary_minus(1);
|
||||
NumericType check_NumericType_unary_minus_result =
|
||||
- check_NumericType_unary_minus;
|
||||
|
||||
/*
|
||||
binary operators
|
||||
*/
|
||||
const NumericType check_NumericType_binary_addition(1);
|
||||
NumericType check_NumericType_binary_addition_result =
|
||||
check_NumericType_binary_addition + x;
|
||||
|
||||
const NumericType check_NumericType_binary_subtraction(1);
|
||||
NumericType check_NumericType_binary_subtraction_result =
|
||||
check_NumericType_binary_subtraction - x;
|
||||
|
||||
const NumericType check_NumericType_binary_multiplication(1);
|
||||
NumericType check_NumericType_binary_multiplication_result =
|
||||
check_NumericType_binary_multiplication * x;
|
||||
|
||||
const NumericType check_NumericType_binary_division(1);
|
||||
NumericType check_NumericType_binary_division_result =
|
||||
check_NumericType_binary_division / x;
|
||||
|
||||
/*
|
||||
compound assignment operators
|
||||
*/
|
||||
NumericType
|
||||
check_NumericType_computed_assignment_addition(1);
|
||||
check_NumericType_computed_assignment_addition += x;
|
||||
|
||||
NumericType
|
||||
check_NumericType_computed_assignment_subtraction(1);
|
||||
check_NumericType_computed_assignment_subtraction -= x;
|
||||
|
||||
NumericType
|
||||
check_NumericType_computed_assignment_multiplication(1);
|
||||
check_NumericType_computed_assignment_multiplication *= x;
|
||||
|
||||
NumericType
|
||||
check_NumericType_computed_assignment_division(1);
|
||||
check_NumericType_computed_assignment_division /= x;
|
||||
|
||||
/*
|
||||
use all values so as to avoid warnings
|
||||
*/
|
||||
check_NumericType_default_constructor = x;
|
||||
return
|
||||
+ check_NumericType_default_constructor
|
||||
+ check_NumericType_constructor_from_int
|
||||
+ check_NumericType_copy_constructor
|
||||
+ check_NumericType_assignment
|
||||
+ check_NumericType_unary_plus_result
|
||||
+ check_NumericType_unary_minus_result
|
||||
+ check_NumericType_binary_addition_result
|
||||
+ check_NumericType_binary_subtraction_result
|
||||
+ check_NumericType_binary_multiplication_result
|
||||
+ check_NumericType_binary_division_result
|
||||
+ check_NumericType_computed_assignment_addition
|
||||
+ check_NumericType_computed_assignment_subtraction
|
||||
+ check_NumericType_computed_assignment_multiplication
|
||||
+ check_NumericType_computed_assignment_division
|
||||
;
|
||||
}
|
||||
# endif
|
||||
|
||||
} // end namespace CppAD
|
||||
|
||||
# endif
|
||||
@@ -0,0 +1,200 @@
|
||||
# ifndef CPPAD_UTILITY_CHECK_SIMPLE_VECTOR_HPP
|
||||
# define CPPAD_UTILITY_CHECK_SIMPLE_VECTOR_HPP
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-17 Bradley M. Bell
|
||||
|
||||
CppAD is distributed under multiple licenses. This distribution is under
|
||||
the terms of the
|
||||
Eclipse Public License Version 1.0.
|
||||
|
||||
A copy of this license is included in the COPYING file of this distribution.
|
||||
Please visit http://www.coin-or.org/CppAD/ for information on other licenses.
|
||||
-------------------------------------------------------------------------- */
|
||||
/*
|
||||
$begin CheckSimpleVector$$
|
||||
$spell
|
||||
alloc
|
||||
const
|
||||
cppad.hpp
|
||||
CppAD
|
||||
$$
|
||||
|
||||
$section Check Simple Vector Concept$$
|
||||
$mindex CheckSimpleVector$$
|
||||
|
||||
|
||||
$head Syntax$$
|
||||
$codei%# include <cppad/utility/check_simple_vector.hpp>
|
||||
%$$
|
||||
$codei%CheckSimpleVector<%Scalar%, %Vector%>()%$$
|
||||
$pre
|
||||
$$
|
||||
$codei%CheckSimpleVector<%Scalar%, %Vector%>(%x%, %y%)%$$
|
||||
|
||||
|
||||
$head Purpose$$
|
||||
Preforms compile and run time checks that the type specified
|
||||
by $icode Vector$$ satisfies all the requirements for
|
||||
a $cref SimpleVector$$ class with
|
||||
$cref/elements of type/SimpleVector/Elements of Specified Type/$$
|
||||
$icode Scalar$$.
|
||||
If a requirement is not satisfied,
|
||||
a an error message makes it clear what condition is not satisfied.
|
||||
|
||||
$head x, y$$
|
||||
If the arguments $icode x$$ and $icode y$$ are present,
|
||||
they have prototype
|
||||
$codei%
|
||||
const %Scalar%& %x%
|
||||
const %Scalar%& %y%
|
||||
%$$
|
||||
In addition, the check
|
||||
$codei%
|
||||
%x% == %x%
|
||||
%$$
|
||||
will return the boolean value $code true$$, and
|
||||
$codei%
|
||||
%x% == %y%
|
||||
%$$
|
||||
will return $code false$$.
|
||||
|
||||
$head Restrictions$$
|
||||
If the arguments $icode x$$ and $icode y$$ are not present,
|
||||
the following extra assumption is made by $code CheckSimpleVector$$:
|
||||
If $icode x$$ is a $icode Scalar$$ object
|
||||
$codei%
|
||||
%x% = 0
|
||||
%y% = 1
|
||||
%$$
|
||||
assigns values to the objects $icode x$$ and $icode y$$.
|
||||
In addition,
|
||||
$icode%x% == %x%$$ would return the boolean value $code true$$ and
|
||||
$icode%x% == %y%$$ would return $code false$$.
|
||||
|
||||
$head Include$$
|
||||
The file $code cppad/check_simple_vector.hpp$$ is included by $code cppad/cppad.hpp$$
|
||||
but it can also be included separately with out the rest
|
||||
if the CppAD include files.
|
||||
|
||||
$head Parallel Mode$$
|
||||
The routine $cref/thread_alloc::parallel_setup/ta_parallel_setup/$$
|
||||
must be called before it
|
||||
can be used in $cref/parallel/ta_in_parallel/$$ mode.
|
||||
|
||||
$head Example$$
|
||||
$children%
|
||||
example/utility/check_simple_vector.cpp
|
||||
%$$
|
||||
The file $cref check_simple_vector.cpp$$
|
||||
contains an example and test of this function where $icode S$$
|
||||
is the same as $icode T$$.
|
||||
It returns true, if it succeeds an false otherwise.
|
||||
The comments in this example suggest a way to change the example
|
||||
so $icode S$$ is not the same as $icode T$$.
|
||||
|
||||
$end
|
||||
---------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
# include <cstddef>
|
||||
# include <cppad/core/cppad_assert.hpp>
|
||||
# include <cppad/core/define.hpp>
|
||||
# include <cppad/utility/thread_alloc.hpp>
|
||||
|
||||
namespace CppAD {
|
||||
|
||||
# ifdef NDEBUG
|
||||
template <class Scalar, class Vector>
|
||||
inline void CheckSimpleVector(const Scalar& x, const Scalar& y)
|
||||
{ }
|
||||
template <class Scalar, class Vector>
|
||||
inline void CheckSimpleVector(void)
|
||||
{ }
|
||||
# else
|
||||
template <class S, class T>
|
||||
struct ok_if_S_same_as_T { };
|
||||
|
||||
template <class T>
|
||||
struct ok_if_S_same_as_T<T,T> { T value; };
|
||||
|
||||
template <class Scalar, class Vector>
|
||||
void CheckSimpleVector(const Scalar& x, const Scalar& y)
|
||||
{ CPPAD_ASSERT_FIRST_CALL_NOT_PARALLEL
|
||||
static size_t count;
|
||||
if( count > 0 )
|
||||
return;
|
||||
count++;
|
||||
|
||||
// value_type must be type of elements of Vector
|
||||
typedef typename Vector::value_type value_type;
|
||||
|
||||
// check that elements of Vector have type Scalar
|
||||
struct ok_if_S_same_as_T<Scalar, value_type> x_copy;
|
||||
x_copy.value = x;
|
||||
|
||||
// check default constructor
|
||||
Vector d;
|
||||
|
||||
// size member function
|
||||
CPPAD_ASSERT_KNOWN(
|
||||
d.size() == 0,
|
||||
"default construtor result does not have size zero"
|
||||
);
|
||||
|
||||
// resize to same size as other vectors in test
|
||||
d.resize(1);
|
||||
|
||||
// check sizing constructor
|
||||
Vector s(1);
|
||||
|
||||
// check element assignment
|
||||
s[0] = y;
|
||||
CPPAD_ASSERT_KNOWN(
|
||||
s[0] == y,
|
||||
"element assignment failed"
|
||||
);
|
||||
|
||||
// check copy constructor
|
||||
s[0] = x_copy.value;
|
||||
const Vector c(s);
|
||||
s[0] = y;
|
||||
CPPAD_ASSERT_KNOWN(
|
||||
c[0] == x,
|
||||
"copy constructor is shallow"
|
||||
);
|
||||
|
||||
// vector assignment operator
|
||||
d[0] = x;
|
||||
s = d;
|
||||
s[0] = y;
|
||||
CPPAD_ASSERT_KNOWN(
|
||||
d[0] == x,
|
||||
"assignment operator is shallow"
|
||||
);
|
||||
|
||||
// element access, right side const
|
||||
// element assignment, left side not const
|
||||
d[0] = c[0];
|
||||
CPPAD_ASSERT_KNOWN(
|
||||
d[0] == x,
|
||||
"element assignment from const failed"
|
||||
);
|
||||
}
|
||||
template <class Scalar, class Vector>
|
||||
void CheckSimpleVector(void)
|
||||
{ Scalar x;
|
||||
Scalar y;
|
||||
|
||||
// use assignment and not constructor
|
||||
x = 0;
|
||||
y = 1;
|
||||
|
||||
CheckSimpleVector<Scalar, Vector>(x, y);
|
||||
}
|
||||
|
||||
# endif
|
||||
|
||||
} // end namespace CppAD
|
||||
|
||||
# endif
|
||||
@@ -0,0 +1,175 @@
|
||||
// $Id: elapsed_seconds.hpp 3845 2016-11-19 01:50:47Z bradbell $
|
||||
# ifndef CPPAD_UTILITY_ELAPSED_SECONDS_HPP
|
||||
# define CPPAD_UTILITY_ELAPSED_SECONDS_HPP
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-16 Bradley M. Bell
|
||||
|
||||
CppAD is distributed under multiple licenses. This distribution is under
|
||||
the terms of the
|
||||
Eclipse Public License Version 1.0.
|
||||
|
||||
A copy of this license is included in the COPYING file of this distribution.
|
||||
Please visit http://www.coin-or.org/CppAD/ for information on other licenses.
|
||||
-------------------------------------------------------------------------- */
|
||||
|
||||
/*
|
||||
$begin elapsed_seconds$$
|
||||
$spell
|
||||
cppad.hpp
|
||||
Microsoft
|
||||
gettimeofday
|
||||
std
|
||||
chrono
|
||||
$$
|
||||
|
||||
$section Returns Elapsed Number of Seconds$$
|
||||
$mindex elapsed_seconds time$$
|
||||
|
||||
|
||||
$head Syntax$$
|
||||
$codei%# include <cppad/utility/elapsed_seconds.hpp>
|
||||
%$$
|
||||
$icode%s% = elapsed_seconds()%$$
|
||||
|
||||
$head Purpose$$
|
||||
This routine is accurate to within .02 seconds
|
||||
(see $cref elapsed_seconds.cpp$$).
|
||||
It does not necessary work for time intervals that are greater than a day.
|
||||
$list number$$
|
||||
If the C++11 $code std::chrono::steady_clock$$ is available,
|
||||
it will be used for timing.
|
||||
$lnext
|
||||
Otherwise, if running under the Microsoft compiler,
|
||||
$code ::GetSystemTime$$ will be used for timing.
|
||||
$lnext
|
||||
Otherwise, if $code gettimeofday$$ is available, it is used for timing.
|
||||
$lnext
|
||||
Otherwise, $code std::clock()$$ will be used for timing.
|
||||
$lend
|
||||
|
||||
$head s$$
|
||||
is a $code double$$ equal to the
|
||||
number of seconds since the first call to $code elapsed_seconds$$.
|
||||
|
||||
$head Microsoft Systems$$
|
||||
It you are using $code ::GetSystemTime$$,
|
||||
you will need to link in the external routine
|
||||
called $cref microsoft_timer$$.
|
||||
|
||||
$children%
|
||||
speed/example/elapsed_seconds.cpp
|
||||
%$$
|
||||
$head Example$$
|
||||
The routine $cref elapsed_seconds.cpp$$ is
|
||||
an example and test of this routine.
|
||||
|
||||
|
||||
$end
|
||||
-----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
// For some unknown reason under Fedora (which needs to be understood),
|
||||
// if you move this include for cppad_assert.hpp below include for define.hpp,
|
||||
// cd work/speed/example
|
||||
// make test.sh
|
||||
// fails with the error message 'gettimeofday' not defined.
|
||||
# include <cppad/core/cppad_assert.hpp>
|
||||
|
||||
// define CPPAD_NULL
|
||||
# include <cppad/core/define.hpp>
|
||||
|
||||
// needed before one can use CPPAD_ASSERT_FIRST_CALL_NOT_PARALLEL
|
||||
# include <cppad/utility/thread_alloc.hpp>
|
||||
|
||||
# if CPPAD_USE_CPLUSPLUS_2011
|
||||
# include <chrono>
|
||||
# elif _MSC_VER
|
||||
extern double microsoft_timer(void);
|
||||
# elif CPPAD_HAS_GETTIMEOFDAY
|
||||
# include <sys/time.h>
|
||||
# else
|
||||
# include <ctime>
|
||||
# endif
|
||||
|
||||
namespace CppAD { // BEGIN_CPPAD_NAMESPACE
|
||||
/*!
|
||||
\file elapsed_seconds.hpp
|
||||
\brief Function that returns the elapsed seconds from first call.
|
||||
*/
|
||||
|
||||
/*!
|
||||
Returns the elapsed number since the first call to this function.
|
||||
|
||||
This routine tries is accurate to within .02 seconds.
|
||||
It does not necessary work for time intervals that are less than a day.
|
||||
\li
|
||||
If running under the Microsoft system, it uses \c ::%GetSystemTime for timing.
|
||||
\li
|
||||
Otherwise, if \c gettimeofday is available, it is used.
|
||||
\li
|
||||
Otherwise, \c std::clock() is used.
|
||||
|
||||
\return
|
||||
The number of seconds since the first call to \c elapsed_seconds.
|
||||
*/
|
||||
inline double elapsed_seconds(void)
|
||||
// --------------------------------------------------------------------------
|
||||
# if CPPAD_USE_CPLUSPLUS_2011
|
||||
{ CPPAD_ASSERT_FIRST_CALL_NOT_PARALLEL;
|
||||
static bool first_ = true;
|
||||
static std::chrono::time_point<std::chrono::steady_clock> start_;
|
||||
if( first_ )
|
||||
{ start_ = std::chrono::steady_clock::now();
|
||||
first_ = false;
|
||||
return 0.0;
|
||||
}
|
||||
std::chrono::time_point<std::chrono::steady_clock> now;
|
||||
now = std::chrono::steady_clock::now();
|
||||
std::chrono::duration<double> difference = now - start_;
|
||||
return difference.count();
|
||||
}
|
||||
// --------------------------------------------------------------------------
|
||||
# elif _MSC_VER
|
||||
{ return microsoft_timer(); }
|
||||
// --------------------------------------------------------------------------
|
||||
# elif CPPAD_HAS_GETTIMEOFDAY
|
||||
{ CPPAD_ASSERT_FIRST_CALL_NOT_PARALLEL;
|
||||
static bool first_ = true;
|
||||
static struct timeval tv_;
|
||||
struct timeval tv;
|
||||
if( first_ )
|
||||
{ gettimeofday(&tv_, CPPAD_NULL);
|
||||
first_ = false;
|
||||
return 0.;
|
||||
}
|
||||
gettimeofday(&tv, CPPAD_NULL);
|
||||
assert( tv.tv_sec >= tv_.tv_sec );
|
||||
|
||||
double sec = double(tv.tv_sec - tv_.tv_sec);
|
||||
double usec = double(tv.tv_usec) - double(tv_.tv_usec);
|
||||
double diff = sec + 1e-6*usec;
|
||||
|
||||
return diff;
|
||||
}
|
||||
// --------------------------------------------------------------------------
|
||||
# else // Not CPPAD_USE_CPLUSPLUS_2011 or CPPAD_HAS_GETTIMEOFDAY
|
||||
{ CPPAD_ASSERT_FIRST_CALL_NOT_PARALLEL;
|
||||
static bool first_ = true;
|
||||
static double tic_;
|
||||
double tic;
|
||||
if( first_ )
|
||||
{ tic_ = double(std::clock());
|
||||
first_ = false;
|
||||
return 0.;
|
||||
}
|
||||
tic = double( std::clock() );
|
||||
|
||||
double diff = (tic - tic_) / double(CLOCKS_PER_SEC);
|
||||
|
||||
return diff;
|
||||
}
|
||||
# endif
|
||||
// --------------------------------------------------------------------------
|
||||
} // END_CPPAD_NAMESPACE
|
||||
# endif
|
||||
@@ -0,0 +1,235 @@
|
||||
# ifndef CPPAD_UTILITY_ERROR_HANDLER_HPP
|
||||
# define CPPAD_UTILITY_ERROR_HANDLER_HPP
|
||||
/* --------------------------------------------------------------------------
|
||||
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-17 Bradley M. Bell
|
||||
|
||||
CppAD is distributed under multiple licenses. This distribution is under
|
||||
the terms of the
|
||||
Eclipse Public License Version 1.0.
|
||||
|
||||
A copy of this license is included in the COPYING file of this distribution.
|
||||
Please visit http://www.coin-or.org/CppAD/ for information on other licenses.
|
||||
-------------------------------------------------------------------------- */
|
||||
|
||||
/*
|
||||
$begin ErrorHandler$$
|
||||
$spell
|
||||
cppad.hpp
|
||||
CppAD
|
||||
exp
|
||||
bool
|
||||
const
|
||||
$$
|
||||
|
||||
$section Replacing the CppAD Error Handler$$
|
||||
$mindex replace assert exception ErrorHandler$$
|
||||
|
||||
$head Syntax$$
|
||||
$codei%# include <cppad/utility/error_handler.hpp>
|
||||
%$$
|
||||
$codei%ErrorHandler %info%(%handler%)
|
||||
%$$
|
||||
$codei%ErrorHandler::Call(%known%, %line%, %file%, %exp%, %msg%)
|
||||
%$$
|
||||
|
||||
$head Constructor$$
|
||||
When you construct a $code ErrorHandler$$ object,
|
||||
the current CppAD error handler is replaced by $icode handler$$.
|
||||
When the object is destructed, the previous CppAD error handler is restored.
|
||||
|
||||
$subhead Parallel Mode$$
|
||||
The $code ErrorHandler$$ constructor and destructor cannot be called in
|
||||
$cref/parallel/ta_in_parallel/$$ execution mode.
|
||||
Furthermore, this rule is not abided by, a raw C++ $code assert$$,
|
||||
instead of one that uses this error handler, will be generated.
|
||||
|
||||
$head Call$$
|
||||
When $code ErrorHandler::Call$$ is called,
|
||||
the current CppAD error handler is used to report an error.
|
||||
This starts out as a default error handler and can be replaced
|
||||
using the $code ErrorHandler$$ constructor.
|
||||
|
||||
$head info$$
|
||||
The object $icode info$$ is used to store information
|
||||
that is necessary to restore the previous CppAD error handler.
|
||||
This is done when the destructor for $icode info$$ is called.
|
||||
|
||||
|
||||
$head handler$$
|
||||
The argument $icode handler$$ has prototype
|
||||
$codei%
|
||||
void (*%handler%)
|
||||
(bool, int, const char *, const char *, const char *);
|
||||
%$$
|
||||
When an error is detected,
|
||||
it is called with the syntax
|
||||
$codei%
|
||||
%handler% (%known%, %line%, %file%, %exp%, %msg%)
|
||||
%$$
|
||||
This routine should not return; i.e., upon detection of the error,
|
||||
the routine calling $icode handler$$ does not know how to proceed.
|
||||
|
||||
$head known$$
|
||||
The $icode handler$$ argument $icode known$$ has prototype
|
||||
$codei%
|
||||
bool %known%
|
||||
%$$
|
||||
If it is true, the error being reported is from a know problem.
|
||||
|
||||
$head line$$
|
||||
The $icode handler$$ argument $icode line$$ has prototype
|
||||
$codei%
|
||||
int %line%
|
||||
%$$
|
||||
It reports the source code line number where the error is detected.
|
||||
|
||||
$head file$$
|
||||
The $icode handler$$ argument $icode file$$ has prototype
|
||||
$codei%
|
||||
const char *%file%
|
||||
%$$
|
||||
and is a $code '\0'$$ terminated character vector.
|
||||
It reports the source code file where the error is detected.
|
||||
|
||||
$head exp$$
|
||||
The $icode handler$$ argument $icode exp$$ has prototype
|
||||
$codei%
|
||||
const char *%exp%
|
||||
%$$
|
||||
and is a $code '\0'$$ terminated character vector.
|
||||
It is a source code boolean expression that should have been true,
|
||||
but is false,
|
||||
and thereby causes this call to $icode handler$$.
|
||||
|
||||
$head msg$$
|
||||
The $icode handler$$ argument $icode msg$$ has prototype
|
||||
$codei%
|
||||
const char *%msg%
|
||||
%$$
|
||||
and is a $code '\0'$$ terminated character vector.
|
||||
It reports the meaning of the error from the C++ programmers point of view.
|
||||
|
||||
$children%
|
||||
example/utility/error_handler.cpp%
|
||||
cppad/core/cppad_assert.hpp
|
||||
%$$
|
||||
$head Example$$
|
||||
The file
|
||||
$cref error_handler.cpp$$
|
||||
contains an example and test a test of using this routine.
|
||||
It returns true if it succeeds and false otherwise.
|
||||
|
||||
$end
|
||||
---------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
# include <iostream>
|
||||
|
||||
# include <cppad/configure.hpp>
|
||||
# include <cppad/local/set_get_in_parallel.hpp>
|
||||
# include <cassert>
|
||||
# include <cstdlib>
|
||||
|
||||
namespace CppAD { // BEGIN CppAD namespace
|
||||
|
||||
class ErrorHandler {
|
||||
template <class Base>
|
||||
friend void parallel_ad(void);
|
||||
public:
|
||||
typedef void (*Handler)
|
||||
(bool, int, const char *, const char *, const char *);
|
||||
|
||||
// construct a new handler
|
||||
ErrorHandler(Handler handler) : previous( Current() )
|
||||
{ if( local::set_get_in_parallel(0) )
|
||||
{ bool known = true;
|
||||
int line = __LINE__;
|
||||
const char* file = __FILE__;
|
||||
const char* exp = "! local::set_get_in_parallel(0)";
|
||||
const char* msg =
|
||||
"Using ErrorHandler constructor in parallel mode.";
|
||||
Call(known, line, file, exp, msg);
|
||||
}
|
||||
Current() = handler;
|
||||
}
|
||||
|
||||
// destructor for an error handler
|
||||
~ErrorHandler(void)
|
||||
{ if( local::set_get_in_parallel(0) )
|
||||
{ bool known = true;
|
||||
int line = __LINE__;
|
||||
const char* file = __FILE__;
|
||||
const char* exp = "! local::set_get_in_parallel(0)";
|
||||
const char* msg =
|
||||
"Using ErrorHandler destructor in parallel mode.";
|
||||
Call(known, line, file, exp, msg);
|
||||
}
|
||||
Current() = previous;
|
||||
}
|
||||
|
||||
// report an error
|
||||
static void Call(
|
||||
bool known,
|
||||
int line ,
|
||||
const char *file ,
|
||||
const char *exp ,
|
||||
const char *msg )
|
||||
{ Handler handler = Current();
|
||||
handler(known, line, file, exp, msg);
|
||||
}
|
||||
|
||||
private:
|
||||
const Handler previous;
|
||||
|
||||
// The default error handler
|
||||
static void Default(
|
||||
bool known,
|
||||
int line ,
|
||||
const char *file ,
|
||||
const char *exp ,
|
||||
const char *msg )
|
||||
{ using std::cerr;
|
||||
using std::endl;
|
||||
|
||||
cerr << CPPAD_PACKAGE_STRING;
|
||||
if( known )
|
||||
cerr << " error from a known source:" << endl;
|
||||
else cerr << " error from unknown source" << endl;
|
||||
if( msg[0] != '\0' )
|
||||
cerr << msg << endl;
|
||||
cerr << "Error detected by false result for" << endl;
|
||||
cerr << " " << exp << endl;
|
||||
cerr << "at line " << line << " in the file " << endl;
|
||||
cerr << " " << file << endl;
|
||||
|
||||
// terminate program execution
|
||||
assert(false);
|
||||
|
||||
// termination when NDEBUG is defined
|
||||
std::exit(1);
|
||||
}
|
||||
|
||||
// current error handler
|
||||
static Handler &Current(void)
|
||||
{ static bool first_call = true;
|
||||
static Handler current = Default;
|
||||
if( first_call )
|
||||
{ if( local::set_get_in_parallel(0) )
|
||||
{ bool known = false;
|
||||
int line = __LINE__;
|
||||
const char* file = __FILE__;
|
||||
const char* exp = "";
|
||||
const char* msg = "";
|
||||
Call(known, line, file, exp, msg);
|
||||
}
|
||||
first_call = false;
|
||||
}
|
||||
return current;
|
||||
}
|
||||
};
|
||||
|
||||
} // END CppAD namespace
|
||||
|
||||
|
||||
|
||||
# endif
|
||||
+178
@@ -0,0 +1,178 @@
|
||||
# ifndef CPPAD_UTILITY_INDEX_SORT_HPP
|
||||
# define CPPAD_UTILITY_INDEX_SORT_HPP
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-17 Bradley M. Bell
|
||||
|
||||
CppAD is distributed under multiple licenses. This distribution is under
|
||||
the terms of the
|
||||
Eclipse Public License Version 1.0.
|
||||
|
||||
A copy of this license is included in the COPYING file of this distribution.
|
||||
Please visit http://www.coin-or.org/CppAD/ for information on other licenses.
|
||||
-------------------------------------------------------------------------- */
|
||||
|
||||
/*
|
||||
$begin index_sort$$
|
||||
$spell
|
||||
cppad.hpp
|
||||
ind
|
||||
const
|
||||
$$
|
||||
|
||||
$section Returns Indices that Sort a Vector$$
|
||||
$mindex index_sort$$
|
||||
|
||||
|
||||
$head Syntax$$
|
||||
$codei%# include <cppad/utility/index_sort.hpp>
|
||||
%$$
|
||||
$codei%index_sort(%keys%, %ind%)%$$
|
||||
|
||||
$head keys$$
|
||||
The argument $icode keys$$ has prototype
|
||||
$codei%
|
||||
const %VectorKey%& %keys%
|
||||
%$$
|
||||
where $icode VectorKey$$ is
|
||||
a $cref SimpleVector$$ class with elements that support the $code <$$
|
||||
operation.
|
||||
|
||||
$head ind$$
|
||||
The argument $icode ind$$ has prototype
|
||||
$codei%
|
||||
%VectorSize%& %ind%
|
||||
%$$
|
||||
where $icode VectorSize$$ is
|
||||
a $cref SimpleVector$$ class with elements of type $code size_t$$.
|
||||
The routine $cref CheckSimpleVector$$ will generate an error message
|
||||
if this is not the case.
|
||||
|
||||
$subhead Input$$
|
||||
The size of $icode ind$$ must be the same as the size of $icode keys$$
|
||||
and the value of its input elements does not matter.
|
||||
|
||||
$subhead Return$$
|
||||
Upon return, $icode ind$$ is a permutation of the set of indices
|
||||
that yields increasing order for $icode keys$$.
|
||||
In other words, for all $icode%i% != %j%$$,
|
||||
$codei%
|
||||
%ind%[%i%] != %ind%[%j%]
|
||||
%$$
|
||||
and for $icode%i% = 0 , %...% , %size%-2%$$,
|
||||
$codei%
|
||||
( %keys%[ %ind%[%i%+1] ] < %keys%[ %ind%[%i%] ] ) == false
|
||||
%$$
|
||||
|
||||
|
||||
$head Example$$
|
||||
$children%
|
||||
example/utility/index_sort.cpp
|
||||
%$$
|
||||
The file $cref index_sort.cpp$$ contains an example
|
||||
and test of this routine.
|
||||
It return true if it succeeds and false otherwise.
|
||||
|
||||
$end
|
||||
*/
|
||||
# include <algorithm>
|
||||
# include <cppad/utility/thread_alloc.hpp>
|
||||
# include <cppad/utility/check_simple_vector.hpp>
|
||||
# include <cppad/core/define.hpp>
|
||||
|
||||
namespace CppAD { // BEGIN_CPPAD_NAMESPACE
|
||||
/*!
|
||||
\file index_sort.hpp
|
||||
File used to implement the CppAD index sort utility
|
||||
*/
|
||||
|
||||
/*!
|
||||
Helper class used by index_sort
|
||||
*/
|
||||
template <class Compare>
|
||||
class index_sort_element {
|
||||
private:
|
||||
/// key used to determine position of this element
|
||||
Compare key_;
|
||||
/// index vlaue corresponding to this key
|
||||
size_t index_;
|
||||
public:
|
||||
/// operator requried by std::sort
|
||||
bool operator<(const index_sort_element& other) const
|
||||
{ return key_ < other.key_; }
|
||||
/// set the key for this element
|
||||
void set_key(const Compare& value)
|
||||
{ key_ = value; }
|
||||
/// set the index for this element
|
||||
void set_index(const size_t& index)
|
||||
{ index_ = index; }
|
||||
/// get the key for this element
|
||||
Compare get_key(void) const
|
||||
{ return key_; }
|
||||
/// get the index for this element
|
||||
size_t get_index(void) const
|
||||
{ return index_; }
|
||||
};
|
||||
|
||||
/*!
|
||||
Compute the indices that sort a vector of keys
|
||||
|
||||
\tparam VectorKey
|
||||
Simple vector type that deterimene the sorting order by \c < operator
|
||||
on its elements.
|
||||
|
||||
\tparam VectorSize
|
||||
Simple vector type with elements of \c size_t
|
||||
that is used to return index values.
|
||||
|
||||
\param keys [in]
|
||||
values that determine the sorting order.
|
||||
|
||||
\param ind [out]
|
||||
must have the same size as \c keys.
|
||||
The input value of its elements does not matter.
|
||||
The output value of its elements satisfy
|
||||
\code
|
||||
( keys[ ind[i] ] < keys[ ind[i+1] ] ) == false
|
||||
\endcode
|
||||
*/
|
||||
template <class VectorKey, class VectorSize>
|
||||
void index_sort(const VectorKey& keys, VectorSize& ind)
|
||||
{ typedef typename VectorKey::value_type Compare;
|
||||
CheckSimpleVector<size_t, VectorSize>();
|
||||
|
||||
typedef index_sort_element<Compare> element;
|
||||
|
||||
CPPAD_ASSERT_KNOWN(
|
||||
size_t(keys.size()) == size_t(ind.size()),
|
||||
"index_sort: vector sizes do not match"
|
||||
);
|
||||
|
||||
size_t size_work = size_t(keys.size());
|
||||
size_t size_out;
|
||||
element* work =
|
||||
thread_alloc::create_array<element>(size_work, size_out);
|
||||
|
||||
// copy initial order into work
|
||||
size_t i;
|
||||
for(i = 0; i < size_work; i++)
|
||||
{ work[i].set_key( keys[i] );
|
||||
work[i].set_index( i );
|
||||
}
|
||||
|
||||
// sort the work array
|
||||
std::sort(work, work+size_work);
|
||||
|
||||
// copy the indices to the output vector
|
||||
for(i = 0; i < size_work; i++)
|
||||
ind[i] = work[i].get_index();
|
||||
|
||||
// we are done with this work array
|
||||
thread_alloc::delete_array(work);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
} // END_CPPAD_NAMESPACE
|
||||
|
||||
# endif
|
||||
+393
@@ -0,0 +1,393 @@
|
||||
# ifndef CPPAD_UTILITY_LU_FACTOR_HPP
|
||||
# define CPPAD_UTILITY_LU_FACTOR_HPP
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-17 Bradley M. Bell
|
||||
|
||||
CppAD is distributed under multiple licenses. This distribution is under
|
||||
the terms of the
|
||||
Eclipse Public License Version 1.0.
|
||||
|
||||
A copy of this license is included in the COPYING file of this distribution.
|
||||
Please visit http://www.coin-or.org/CppAD/ for information on other licenses.
|
||||
-------------------------------------------------------------------------- */
|
||||
|
||||
/*
|
||||
$begin LuFactor$$
|
||||
$escape #$$
|
||||
$spell
|
||||
cppad.hpp
|
||||
Cpp
|
||||
Geq
|
||||
Lu
|
||||
bool
|
||||
const
|
||||
ip
|
||||
jp
|
||||
namespace
|
||||
std
|
||||
typename
|
||||
$$
|
||||
|
||||
|
||||
$section LU Factorization of A Square Matrix$$
|
||||
$mindex LuFactor linear equation solve$$
|
||||
|
||||
$pre
|
||||
$$
|
||||
|
||||
$head Syntax$$ $codei%# include <cppad/utility/lu_factor.hpp>
|
||||
%$$
|
||||
$icode%sign% = LuFactor(%ip%, %jp%, %LU%)%$$
|
||||
|
||||
|
||||
$head Description$$
|
||||
Computes an LU factorization of the matrix $icode A$$
|
||||
where $icode A$$ is a square matrix.
|
||||
|
||||
$head Include$$
|
||||
The file $code cppad/lu_factor.hpp$$ is included by $code cppad/cppad.hpp$$
|
||||
but it can also be included separately with out the rest of
|
||||
the $code CppAD$$ routines.
|
||||
|
||||
$head Matrix Storage$$
|
||||
All matrices are stored in row major order.
|
||||
To be specific, if $latex Y$$ is a vector
|
||||
that contains a $latex p$$ by $latex q$$ matrix,
|
||||
the size of $latex Y$$ must be equal to $latex p * q $$ and for
|
||||
$latex i = 0 , \ldots , p-1$$,
|
||||
$latex j = 0 , \ldots , q-1$$,
|
||||
$latex \[
|
||||
Y_{i,j} = Y[ i * q + j ]
|
||||
\] $$
|
||||
|
||||
$head sign$$
|
||||
The return value $icode sign$$ has prototype
|
||||
$codei%
|
||||
int %sign%
|
||||
%$$
|
||||
If $icode A$$ is invertible, $icode sign$$ is plus or minus one
|
||||
and is the sign of the permutation corresponding to the row ordering
|
||||
$icode ip$$ and column ordering $icode jp$$.
|
||||
If $icode A$$ is not invertible, $icode sign$$ is zero.
|
||||
|
||||
$head ip$$
|
||||
The argument $icode ip$$ has prototype
|
||||
$codei%
|
||||
%SizeVector% &%ip%
|
||||
%$$
|
||||
(see description of $cref/SizeVector/LuFactor/SizeVector/$$ below).
|
||||
The size of $icode ip$$ is referred to as $icode n$$ in the
|
||||
specifications below.
|
||||
The input value of the elements of $icode ip$$ does not matter.
|
||||
The output value of the elements of $icode ip$$ determine
|
||||
the order of the rows in the permuted matrix.
|
||||
|
||||
$head jp$$
|
||||
The argument $icode jp$$ has prototype
|
||||
$codei%
|
||||
%SizeVector% &%jp%
|
||||
%$$
|
||||
(see description of $cref/SizeVector/LuFactor/SizeVector/$$ below).
|
||||
The size of $icode jp$$ must be equal to $icode n$$.
|
||||
The input value of the elements of $icode jp$$ does not matter.
|
||||
The output value of the elements of $icode jp$$ determine
|
||||
the order of the columns in the permuted matrix.
|
||||
|
||||
$head LU$$
|
||||
The argument $icode LU$$ has the prototype
|
||||
$codei%
|
||||
%FloatVector% &%LU%
|
||||
%$$
|
||||
and the size of $icode LU$$ must equal $latex n * n$$
|
||||
(see description of $cref/FloatVector/LuFactor/FloatVector/$$ below).
|
||||
|
||||
$subhead A$$
|
||||
We define $icode A$$ as the matrix corresponding to the input
|
||||
value of $icode LU$$.
|
||||
|
||||
$subhead P$$
|
||||
We define the permuted matrix $icode P$$ in terms of $icode A$$ by
|
||||
$codei%
|
||||
%P%(%i%, %j%) = %A%[ %ip%[%i%] * %n% + %jp%[%j%] ]
|
||||
%$$
|
||||
|
||||
$subhead L$$
|
||||
We define the lower triangular matrix $icode L$$ in terms of the
|
||||
output value of $icode LU$$.
|
||||
The matrix $icode L$$ is zero above the diagonal
|
||||
and the rest of the elements are defined by
|
||||
$codei%
|
||||
%L%(%i%, %j%) = %LU%[ %ip%[%i%] * %n% + %jp%[%j%] ]
|
||||
%$$
|
||||
for $latex i = 0 , \ldots , n-1$$ and $latex j = 0 , \ldots , i$$.
|
||||
|
||||
$subhead U$$
|
||||
We define the upper triangular matrix $icode U$$ in terms of the
|
||||
output value of $icode LU$$.
|
||||
The matrix $icode U$$ is zero below the diagonal,
|
||||
one on the diagonal,
|
||||
and the rest of the elements are defined by
|
||||
$codei%
|
||||
%U%(%i%, %j%) = %LU%[ %ip%[%i%] * %n% + %jp%[%j%] ]
|
||||
%$$
|
||||
for $latex i = 0 , \ldots , n-2$$ and $latex j = i+1 , \ldots , n-1$$.
|
||||
|
||||
$subhead Factor$$
|
||||
If the return value $icode sign$$ is non-zero,
|
||||
$codei%
|
||||
%L% * %U% = %P%
|
||||
%$$
|
||||
If the return value of $icode sign$$ is zero,
|
||||
the contents of $icode L$$ and $icode U$$ are not defined.
|
||||
|
||||
$subhead Determinant$$
|
||||
If the return value $icode sign$$ is zero,
|
||||
the determinant of $icode A$$ is zero.
|
||||
If $icode sign$$ is non-zero,
|
||||
using the output value of $icode LU$$
|
||||
the determinant of the matrix $icode A$$ is equal to
|
||||
$codei%
|
||||
%sign% * %LU%[%ip%[0], %jp%[0]] * %...% * %LU%[%ip%[%n%-1], %jp%[%n%-1]]
|
||||
%$$
|
||||
|
||||
$head SizeVector$$
|
||||
The type $icode SizeVector$$ must be a $cref SimpleVector$$ class with
|
||||
$cref/elements of type size_t/SimpleVector/Elements of Specified Type/$$.
|
||||
The routine $cref CheckSimpleVector$$ will generate an error message
|
||||
if this is not the case.
|
||||
|
||||
$head FloatVector$$
|
||||
The type $icode FloatVector$$ must be a
|
||||
$cref/simple vector class/SimpleVector/$$.
|
||||
The routine $cref CheckSimpleVector$$ will generate an error message
|
||||
if this is not the case.
|
||||
|
||||
$head Float$$
|
||||
This notation is used to denote the type corresponding
|
||||
to the elements of a $icode FloatVector$$.
|
||||
The type $icode Float$$ must satisfy the conditions
|
||||
for a $cref NumericType$$ type.
|
||||
The routine $cref CheckNumericType$$ will generate an error message
|
||||
if this is not the case.
|
||||
In addition, the following operations must be defined for any pair
|
||||
of $icode Float$$ objects $icode x$$ and $icode y$$:
|
||||
|
||||
$table
|
||||
$bold Operation$$ $cnext $bold Description$$ $rnext
|
||||
$codei%log(%x%)%$$ $cnext
|
||||
returns the logarithm of $icode x$$ as a $icode Float$$ object
|
||||
$tend
|
||||
|
||||
$head AbsGeq$$
|
||||
Including the file $code lu_factor.hpp$$ defines the template function
|
||||
$codei%
|
||||
template <typename %Float%>
|
||||
bool AbsGeq<%Float%>(const %Float% &%x%, const %Float% &%y%)
|
||||
%$$
|
||||
in the $code CppAD$$ namespace.
|
||||
This function returns true if the absolute value of
|
||||
$icode x$$ is greater than or equal the absolute value of $icode y$$.
|
||||
It is used by $code LuFactor$$ to choose the pivot elements.
|
||||
This template function definition uses the operator
|
||||
$code <=$$ to obtain the absolute value for $icode Float$$ objects.
|
||||
If this operator is not defined for your use of $icode Float$$,
|
||||
you will need to specialize this template so that it works for your
|
||||
use of $code LuFactor$$.
|
||||
$pre
|
||||
|
||||
$$
|
||||
Complex numbers do not have the operation $code <=$$ defined.
|
||||
The specializations
|
||||
$codei%
|
||||
bool AbsGeq< std::complex<float> >
|
||||
(const std::complex<float> &%x%, const std::complex<float> &%y%)
|
||||
bool AbsGeq< std::complex<double> >
|
||||
(const std::complex<double> &%x%, const std::complex<double> &%y%)
|
||||
%$$
|
||||
are define by including $code lu_factor.hpp$$
|
||||
These return true if the sum of the square of the real and imaginary parts
|
||||
of $icode x$$ is greater than or equal the
|
||||
sum of the square of the real and imaginary parts of $icode y$$.
|
||||
|
||||
$children%
|
||||
example/utility/lu_factor.cpp%
|
||||
omh/lu_factor_hpp.omh
|
||||
%$$
|
||||
$head Example$$
|
||||
The file
|
||||
$cref lu_factor.cpp$$
|
||||
contains an example and test of using $code LuFactor$$ by itself.
|
||||
It returns true if it succeeds and false otherwise.
|
||||
$pre
|
||||
|
||||
$$
|
||||
The file $cref lu_solve.hpp$$ provides a useful example usage of
|
||||
$code LuFactor$$ with $code LuInvert$$.
|
||||
|
||||
$head Source$$
|
||||
The file $cref lu_factor.hpp$$ contains the
|
||||
current source code that implements these specifications.
|
||||
|
||||
$end
|
||||
--------------------------------------------------------------------------
|
||||
*/
|
||||
// BEGIN C++
|
||||
|
||||
# include <complex>
|
||||
# include <vector>
|
||||
|
||||
# include <cppad/core/cppad_assert.hpp>
|
||||
# include <cppad/utility/check_simple_vector.hpp>
|
||||
# include <cppad/utility/check_numeric_type.hpp>
|
||||
|
||||
namespace CppAD { // BEGIN CppAD namespace
|
||||
|
||||
// AbsGeq
|
||||
template <typename Float>
|
||||
inline bool AbsGeq(const Float &x, const Float &y)
|
||||
{ Float xabs = x;
|
||||
if( xabs <= Float(0) )
|
||||
xabs = - xabs;
|
||||
Float yabs = y;
|
||||
if( yabs <= Float(0) )
|
||||
yabs = - yabs;
|
||||
return xabs >= yabs;
|
||||
}
|
||||
inline bool AbsGeq(
|
||||
const std::complex<double> &x,
|
||||
const std::complex<double> &y)
|
||||
{ double xsq = x.real() * x.real() + x.imag() * x.imag();
|
||||
double ysq = y.real() * y.real() + y.imag() * y.imag();
|
||||
|
||||
return xsq >= ysq;
|
||||
}
|
||||
inline bool AbsGeq(
|
||||
const std::complex<float> &x,
|
||||
const std::complex<float> &y)
|
||||
{ float xsq = x.real() * x.real() + x.imag() * x.imag();
|
||||
float ysq = y.real() * y.real() + y.imag() * y.imag();
|
||||
|
||||
return xsq >= ysq;
|
||||
}
|
||||
|
||||
// Lines that are different from code in cppad/core/lu_ratio.hpp end with //
|
||||
template <class SizeVector, class FloatVector> //
|
||||
int LuFactor(SizeVector &ip, SizeVector &jp, FloatVector &LU) //
|
||||
{
|
||||
// type of the elements of LU //
|
||||
typedef typename FloatVector::value_type Float; //
|
||||
|
||||
// check numeric type specifications
|
||||
CheckNumericType<Float>();
|
||||
|
||||
// check simple vector class specifications
|
||||
CheckSimpleVector<Float, FloatVector>();
|
||||
CheckSimpleVector<size_t, SizeVector>();
|
||||
|
||||
size_t i, j; // some temporary indices
|
||||
const Float zero( 0 ); // the value zero as a Float object
|
||||
size_t imax; // row index of maximum element
|
||||
size_t jmax; // column indx of maximum element
|
||||
Float emax; // maximum absolute value
|
||||
size_t p; // count pivots
|
||||
int sign; // sign of the permutation
|
||||
Float etmp; // temporary element
|
||||
Float pivot; // pivot element
|
||||
|
||||
// -------------------------------------------------------
|
||||
size_t n = ip.size();
|
||||
CPPAD_ASSERT_KNOWN(
|
||||
size_t(jp.size()) == n,
|
||||
"Error in LuFactor: jp must have size equal to n"
|
||||
);
|
||||
CPPAD_ASSERT_KNOWN(
|
||||
size_t(LU.size()) == n * n,
|
||||
"Error in LuFactor: LU must have size equal to n * m"
|
||||
);
|
||||
// -------------------------------------------------------
|
||||
|
||||
// initialize row and column order in matrix not yet pivoted
|
||||
for(i = 0; i < n; i++)
|
||||
{ ip[i] = i;
|
||||
jp[i] = i;
|
||||
}
|
||||
// initialize the sign of the permutation
|
||||
sign = 1;
|
||||
// ---------------------------------------------------------
|
||||
|
||||
// Reduce the matrix P to L * U using n pivots
|
||||
for(p = 0; p < n; p++)
|
||||
{ // determine row and column corresponding to element of
|
||||
// maximum absolute value in remaining part of P
|
||||
imax = jmax = n;
|
||||
emax = zero;
|
||||
for(i = p; i < n; i++)
|
||||
{ for(j = p; j < n; j++)
|
||||
{ CPPAD_ASSERT_UNKNOWN(
|
||||
(ip[i] < n) & (jp[j] < n)
|
||||
);
|
||||
etmp = LU[ ip[i] * n + jp[j] ];
|
||||
|
||||
// check if maximum absolute value so far
|
||||
if( AbsGeq (etmp, emax) )
|
||||
{ imax = i;
|
||||
jmax = j;
|
||||
emax = etmp;
|
||||
}
|
||||
}
|
||||
}
|
||||
CPPAD_ASSERT_KNOWN(
|
||||
(imax < n) & (jmax < n) ,
|
||||
"LuFactor can't determine an element with "
|
||||
"maximum absolute value.\n"
|
||||
"Perhaps original matrix contains not a number or infinity.\n"
|
||||
"Perhaps your specialization of AbsGeq is not correct."
|
||||
);
|
||||
if( imax != p )
|
||||
{ // switch rows so max absolute element is in row p
|
||||
i = ip[p];
|
||||
ip[p] = ip[imax];
|
||||
ip[imax] = i;
|
||||
sign = -sign;
|
||||
}
|
||||
if( jmax != p )
|
||||
{ // switch columns so max absolute element is in column p
|
||||
j = jp[p];
|
||||
jp[p] = jp[jmax];
|
||||
jp[jmax] = j;
|
||||
sign = -sign;
|
||||
}
|
||||
// pivot using the max absolute element
|
||||
pivot = LU[ ip[p] * n + jp[p] ];
|
||||
|
||||
// check for determinant equal to zero
|
||||
if( pivot == zero )
|
||||
{ // abort the mission
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Reduce U by the elementary transformations that maps
|
||||
// LU( ip[p], jp[p] ) to one. Only need transform elements
|
||||
// above the diagonal in U and LU( ip[p] , jp[p] ) is
|
||||
// corresponding value below diagonal in L.
|
||||
for(j = p+1; j < n; j++)
|
||||
LU[ ip[p] * n + jp[j] ] /= pivot;
|
||||
|
||||
// Reduce U by the elementary transformations that maps
|
||||
// LU( ip[i], jp[p] ) to zero. Only need transform elements
|
||||
// above the diagonal in U and LU( ip[i], jp[p] ) is
|
||||
// corresponding value below diagonal in L.
|
||||
for(i = p+1; i < n; i++ )
|
||||
{ etmp = LU[ ip[i] * n + jp[p] ];
|
||||
for(j = p+1; j < n; j++)
|
||||
{ LU[ ip[i] * n + jp[j] ] -=
|
||||
etmp * LU[ ip[p] * n + jp[j] ];
|
||||
}
|
||||
}
|
||||
}
|
||||
return sign;
|
||||
}
|
||||
} // END CppAD namespace
|
||||
// END C++
|
||||
# endif
|
||||
+239
@@ -0,0 +1,239 @@
|
||||
# ifndef CPPAD_UTILITY_LU_INVERT_HPP
|
||||
# define CPPAD_UTILITY_LU_INVERT_HPP
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-17 Bradley M. Bell
|
||||
|
||||
CppAD is distributed under multiple licenses. This distribution is under
|
||||
the terms of the
|
||||
Eclipse Public License Version 1.0.
|
||||
|
||||
A copy of this license is included in the COPYING file of this distribution.
|
||||
Please visit http://www.coin-or.org/CppAD/ for information on other licenses.
|
||||
-------------------------------------------------------------------------- */
|
||||
|
||||
/*
|
||||
$begin LuInvert$$
|
||||
$escape #$$
|
||||
$spell
|
||||
cppad.hpp
|
||||
Lu
|
||||
Cpp
|
||||
jp
|
||||
ip
|
||||
const
|
||||
namespace
|
||||
typename
|
||||
etmp
|
||||
$$
|
||||
|
||||
|
||||
$section Invert an LU Factored Equation$$
|
||||
$mindex LuInvert linear$$
|
||||
|
||||
$pre
|
||||
$$
|
||||
|
||||
$head Syntax$$ $codei%# include <cppad/utility/lu_invert.hpp>
|
||||
%$$
|
||||
$codei%LuInvert(%ip%, %jp%, %LU%, %X%)%$$
|
||||
|
||||
|
||||
$head Description$$
|
||||
Solves the matrix equation $icode%A% * %X% = %B%$$
|
||||
using an LU factorization computed by $cref LuFactor$$.
|
||||
|
||||
$head Include$$
|
||||
The file $code cppad/lu_invert.hpp$$ is included by $code cppad/cppad.hpp$$
|
||||
but it can also be included separately with out the rest of
|
||||
the $code CppAD$$ routines.
|
||||
|
||||
$head Matrix Storage$$
|
||||
All matrices are stored in row major order.
|
||||
To be specific, if $latex Y$$ is a vector
|
||||
that contains a $latex p$$ by $latex q$$ matrix,
|
||||
the size of $latex Y$$ must be equal to $latex p * q $$ and for
|
||||
$latex i = 0 , \ldots , p-1$$,
|
||||
$latex j = 0 , \ldots , q-1$$,
|
||||
$latex \[
|
||||
Y_{i,j} = Y[ i * q + j ]
|
||||
\] $$
|
||||
|
||||
$head ip$$
|
||||
The argument $icode ip$$ has prototype
|
||||
$codei%
|
||||
const %SizeVector% &%ip%
|
||||
%$$
|
||||
(see description for $icode SizeVector$$ in
|
||||
$cref/LuFactor/LuFactor/SizeVector/$$ specifications).
|
||||
The size of $icode ip$$ is referred to as $icode n$$ in the
|
||||
specifications below.
|
||||
The elements of $icode ip$$ determine
|
||||
the order of the rows in the permuted matrix.
|
||||
|
||||
$head jp$$
|
||||
The argument $icode jp$$ has prototype
|
||||
$codei%
|
||||
const %SizeVector% &%jp%
|
||||
%$$
|
||||
(see description for $icode SizeVector$$ in
|
||||
$cref/LuFactor/LuFactor/SizeVector/$$ specifications).
|
||||
The size of $icode jp$$ must be equal to $icode n$$.
|
||||
The elements of $icode jp$$ determine
|
||||
the order of the columns in the permuted matrix.
|
||||
|
||||
$head LU$$
|
||||
The argument $icode LU$$ has the prototype
|
||||
$codei%
|
||||
const %FloatVector% &%LU%
|
||||
%$$
|
||||
and the size of $icode LU$$ must equal $latex n * n$$
|
||||
(see description for $icode FloatVector$$ in
|
||||
$cref/LuFactor/LuFactor/FloatVector/$$ specifications).
|
||||
|
||||
$subhead L$$
|
||||
We define the lower triangular matrix $icode L$$ in terms of $icode LU$$.
|
||||
The matrix $icode L$$ is zero above the diagonal
|
||||
and the rest of the elements are defined by
|
||||
$codei%
|
||||
%L%(%i%, %j%) = %LU%[ %ip%[%i%] * %n% + %jp%[%j%] ]
|
||||
%$$
|
||||
for $latex i = 0 , \ldots , n-1$$ and $latex j = 0 , \ldots , i$$.
|
||||
|
||||
$subhead U$$
|
||||
We define the upper triangular matrix $icode U$$ in terms of $icode LU$$.
|
||||
The matrix $icode U$$ is zero below the diagonal,
|
||||
one on the diagonal,
|
||||
and the rest of the elements are defined by
|
||||
$codei%
|
||||
%U%(%i%, %j%) = %LU%[ %ip%[%i%] * %n% + %jp%[%j%] ]
|
||||
%$$
|
||||
for $latex i = 0 , \ldots , n-2$$ and $latex j = i+1 , \ldots , n-1$$.
|
||||
|
||||
$subhead P$$
|
||||
We define the permuted matrix $icode P$$ in terms of
|
||||
the matrix $icode L$$ and the matrix $icode U$$
|
||||
by $icode%P% = %L% * %U%$$.
|
||||
|
||||
$subhead A$$
|
||||
The matrix $icode A$$,
|
||||
which defines the linear equations that we are solving, is given by
|
||||
$codei%
|
||||
%P%(%i%, %j%) = %A%[ %ip%[%i%] * %n% + %jp%[%j%] ]
|
||||
%$$
|
||||
(Hence
|
||||
$icode LU$$ contains a permuted factorization of the matrix $icode A$$.)
|
||||
|
||||
|
||||
$head X$$
|
||||
The argument $icode X$$ has prototype
|
||||
$codei%
|
||||
%FloatVector% &%X%
|
||||
%$$
|
||||
(see description for $icode FloatVector$$ in
|
||||
$cref/LuFactor/LuFactor/FloatVector/$$ specifications).
|
||||
The matrix $icode X$$
|
||||
must have the same number of rows as the matrix $icode A$$.
|
||||
The input value of $icode X$$ is the matrix $icode B$$ and the
|
||||
output value solves the matrix equation $icode%A% * %X% = %B%$$.
|
||||
|
||||
|
||||
$children%
|
||||
example/utility/lu_invert.cpp%
|
||||
omh/lu_invert_hpp.omh
|
||||
%$$
|
||||
$head Example$$
|
||||
The file $cref lu_solve.hpp$$ is a good example usage of
|
||||
$code LuFactor$$ with $code LuInvert$$.
|
||||
The file
|
||||
$cref lu_invert.cpp$$
|
||||
contains an example and test of using $code LuInvert$$ by itself.
|
||||
It returns true if it succeeds and false otherwise.
|
||||
|
||||
$head Source$$
|
||||
The file $cref lu_invert.hpp$$ contains the
|
||||
current source code that implements these specifications.
|
||||
|
||||
$end
|
||||
--------------------------------------------------------------------------
|
||||
*/
|
||||
// BEGIN C++
|
||||
# include <cppad/core/cppad_assert.hpp>
|
||||
# include <cppad/utility/check_simple_vector.hpp>
|
||||
# include <cppad/utility/check_numeric_type.hpp>
|
||||
|
||||
namespace CppAD { // BEGIN CppAD namespace
|
||||
|
||||
// LuInvert
|
||||
template <typename SizeVector, typename FloatVector>
|
||||
void LuInvert(
|
||||
const SizeVector &ip,
|
||||
const SizeVector &jp,
|
||||
const FloatVector &LU,
|
||||
FloatVector &B )
|
||||
{ size_t k; // column index in X
|
||||
size_t p; // index along diagonal in LU
|
||||
size_t i; // row index in LU and X
|
||||
|
||||
typedef typename FloatVector::value_type Float;
|
||||
|
||||
// check numeric type specifications
|
||||
CheckNumericType<Float>();
|
||||
|
||||
// check simple vector class specifications
|
||||
CheckSimpleVector<Float, FloatVector>();
|
||||
CheckSimpleVector<size_t, SizeVector>();
|
||||
|
||||
Float etmp;
|
||||
|
||||
size_t n = ip.size();
|
||||
CPPAD_ASSERT_KNOWN(
|
||||
size_t(jp.size()) == n,
|
||||
"Error in LuInvert: jp must have size equal to n * n"
|
||||
);
|
||||
CPPAD_ASSERT_KNOWN(
|
||||
size_t(LU.size()) == n * n,
|
||||
"Error in LuInvert: Lu must have size equal to n * m"
|
||||
);
|
||||
size_t m = size_t(B.size()) / n;
|
||||
CPPAD_ASSERT_KNOWN(
|
||||
size_t(B.size()) == n * m,
|
||||
"Error in LuSolve: B must have size equal to a multiple of n"
|
||||
);
|
||||
|
||||
// temporary storage for reordered solution
|
||||
FloatVector x(n);
|
||||
|
||||
// loop over equations
|
||||
for(k = 0; k < m; k++)
|
||||
{ // invert the equation c = L * b
|
||||
for(p = 0; p < n; p++)
|
||||
{ // solve for c[p]
|
||||
etmp = B[ ip[p] * m + k ] / LU[ ip[p] * n + jp[p] ];
|
||||
B[ ip[p] * m + k ] = etmp;
|
||||
// subtract off effect on other variables
|
||||
for(i = p+1; i < n; i++)
|
||||
B[ ip[i] * m + k ] -=
|
||||
etmp * LU[ ip[i] * n + jp[p] ];
|
||||
}
|
||||
|
||||
// invert the equation x = U * c
|
||||
p = n;
|
||||
while( p > 0 )
|
||||
{ --p;
|
||||
etmp = B[ ip[p] * m + k ];
|
||||
x[ jp[p] ] = etmp;
|
||||
for(i = 0; i < p; i++ )
|
||||
B[ ip[i] * m + k ] -=
|
||||
etmp * LU[ ip[i] * n + jp[p] ];
|
||||
}
|
||||
|
||||
// copy reordered solution into B
|
||||
for(i = 0; i < n; i++)
|
||||
B[i * m + k] = x[i];
|
||||
}
|
||||
return;
|
||||
}
|
||||
} // END CppAD namespace
|
||||
// END C++
|
||||
# endif
|
||||
+345
@@ -0,0 +1,345 @@
|
||||
# ifndef CPPAD_UTILITY_LU_SOLVE_HPP
|
||||
# define CPPAD_UTILITY_LU_SOLVE_HPP
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-17 Bradley M. Bell
|
||||
|
||||
CppAD is distributed under multiple licenses. This distribution is under
|
||||
the terms of the
|
||||
Eclipse Public License Version 1.0.
|
||||
|
||||
A copy of this license is included in the COPYING file of this distribution.
|
||||
Please visit http://www.coin-or.org/CppAD/ for information on other licenses.
|
||||
-------------------------------------------------------------------------- */
|
||||
|
||||
/*
|
||||
$begin LuSolve$$
|
||||
$escape #$$
|
||||
$spell
|
||||
cppad.hpp
|
||||
det
|
||||
exp
|
||||
Leq
|
||||
typename
|
||||
bool
|
||||
const
|
||||
namespace
|
||||
std
|
||||
Geq
|
||||
Lu
|
||||
CppAD
|
||||
signdet
|
||||
logdet
|
||||
$$
|
||||
|
||||
|
||||
$section Compute Determinant and Solve Linear Equations$$
|
||||
$mindex LuSolve Lu$$
|
||||
|
||||
$pre
|
||||
$$
|
||||
|
||||
$head Syntax$$ $codei%# include <cppad/utility/lu_solve.hpp>
|
||||
%$$
|
||||
$icode%signdet% = LuSolve(%n%, %m%, %A%, %B%, %X%, %logdet%)%$$
|
||||
|
||||
|
||||
$head Description$$
|
||||
Use an LU factorization of the matrix $icode A$$ to
|
||||
compute its determinant
|
||||
and solve for $icode X$$ in the linear of equation
|
||||
$latex \[
|
||||
A * X = B
|
||||
\] $$
|
||||
where $icode A$$ is an
|
||||
$icode n$$ by $icode n$$ matrix,
|
||||
$icode X$$ is an
|
||||
$icode n$$ by $icode m$$ matrix, and
|
||||
$icode B$$ is an $latex n x m$$ matrix.
|
||||
|
||||
$head Include$$
|
||||
The file $code cppad/lu_solve.hpp$$ is included by $code cppad/cppad.hpp$$
|
||||
but it can also be included separately with out the rest of
|
||||
the $code CppAD$$ routines.
|
||||
|
||||
$head Factor and Invert$$
|
||||
This routine is an easy to user interface to
|
||||
$cref LuFactor$$ and $cref LuInvert$$ for computing determinants and
|
||||
solutions of linear equations.
|
||||
These separate routines should be used if
|
||||
one right hand side $icode B$$
|
||||
depends on the solution corresponding to another
|
||||
right hand side (with the same value of $icode A$$).
|
||||
In this case only one call to $code LuFactor$$ is required
|
||||
but there will be multiple calls to $code LuInvert$$.
|
||||
|
||||
|
||||
$head Matrix Storage$$
|
||||
All matrices are stored in row major order.
|
||||
To be specific, if $latex Y$$ is a vector
|
||||
that contains a $latex p$$ by $latex q$$ matrix,
|
||||
the size of $latex Y$$ must be equal to $latex p * q $$ and for
|
||||
$latex i = 0 , \ldots , p-1$$,
|
||||
$latex j = 0 , \ldots , q-1$$,
|
||||
$latex \[
|
||||
Y_{i,j} = Y[ i * q + j ]
|
||||
\] $$
|
||||
|
||||
$head signdet$$
|
||||
The return value $icode signdet$$ is a $code int$$ value
|
||||
that specifies the sign factor for the determinant of $icode A$$.
|
||||
This determinant of $icode A$$ is zero if and only if $icode signdet$$
|
||||
is zero.
|
||||
|
||||
$head n$$
|
||||
The argument $icode n$$ has type $code size_t$$
|
||||
and specifies the number of rows in the matrices
|
||||
$icode A$$,
|
||||
$icode X$$,
|
||||
and $icode B$$.
|
||||
The number of columns in $icode A$$ is also equal to $icode n$$.
|
||||
|
||||
$head m$$
|
||||
The argument $icode m$$ has type $code size_t$$
|
||||
and specifies the number of columns in the matrices
|
||||
$icode X$$
|
||||
and $icode B$$.
|
||||
If $icode m$$ is zero,
|
||||
only the determinant of $icode A$$ is computed and
|
||||
the matrices $icode X$$ and $icode B$$ are not used.
|
||||
|
||||
$head A$$
|
||||
The argument $icode A$$ has the prototype
|
||||
$codei%
|
||||
const %FloatVector% &%A%
|
||||
%$$
|
||||
and the size of $icode A$$ must equal $latex n * n$$
|
||||
(see description of $cref/FloatVector/LuSolve/FloatVector/$$ below).
|
||||
This is the $latex n$$ by $icode n$$ matrix that
|
||||
we are computing the determinant of
|
||||
and that defines the linear equation.
|
||||
|
||||
$head B$$
|
||||
The argument $icode B$$ has the prototype
|
||||
$codei%
|
||||
const %FloatVector% &%B%
|
||||
%$$
|
||||
and the size of $icode B$$ must equal $latex n * m$$
|
||||
(see description of $cref/FloatVector/LuSolve/FloatVector/$$ below).
|
||||
This is the $latex n$$ by $icode m$$ matrix that
|
||||
defines the right hand side of the linear equations.
|
||||
If $icode m$$ is zero, $icode B$$ is not used.
|
||||
|
||||
$head X$$
|
||||
The argument $icode X$$ has the prototype
|
||||
$codei%
|
||||
%FloatVector% &%X%
|
||||
%$$
|
||||
and the size of $icode X$$ must equal $latex n * m$$
|
||||
(see description of $cref/FloatVector/LuSolve/FloatVector/$$ below).
|
||||
The input value of $icode X$$ does not matter.
|
||||
On output, the elements of $icode X$$ contain the solution
|
||||
of the equation we wish to solve
|
||||
(unless $icode signdet$$ is equal to zero).
|
||||
If $icode m$$ is zero, $icode X$$ is not used.
|
||||
|
||||
$head logdet$$
|
||||
The argument $icode logdet$$ has prototype
|
||||
$codei%
|
||||
%Float% &%logdet%
|
||||
%$$
|
||||
On input, the value of $icode logdet$$ does not matter.
|
||||
On output, it has been set to the
|
||||
log of the determinant of $icode A$$
|
||||
(but not quite).
|
||||
To be more specific,
|
||||
the determinant of $icode A$$ is given by the formula
|
||||
$codei%
|
||||
%det% = %signdet% * exp( %logdet% )
|
||||
%$$
|
||||
This enables $code LuSolve$$ to use logs of absolute values
|
||||
in the case where $icode Float$$ corresponds to a real number.
|
||||
|
||||
$head Float$$
|
||||
The type $icode Float$$ must satisfy the conditions
|
||||
for a $cref NumericType$$ type.
|
||||
The routine $cref CheckNumericType$$ will generate an error message
|
||||
if this is not the case.
|
||||
In addition, the following operations must be defined for any pair
|
||||
of $icode Float$$ objects $icode x$$ and $icode y$$:
|
||||
|
||||
$table
|
||||
$bold Operation$$ $cnext $bold Description$$ $rnext
|
||||
$codei%log(%x%)%$$ $cnext
|
||||
returns the logarithm of $icode x$$ as a $icode Float$$ object
|
||||
$tend
|
||||
|
||||
$head FloatVector$$
|
||||
The type $icode FloatVector$$ must be a $cref SimpleVector$$ class with
|
||||
$cref/elements of type Float/SimpleVector/Elements of Specified Type/$$.
|
||||
The routine $cref CheckSimpleVector$$ will generate an error message
|
||||
if this is not the case.
|
||||
|
||||
$head LeqZero$$
|
||||
Including the file $code lu_solve.hpp$$ defines the template function
|
||||
$codei%
|
||||
template <typename %Float%>
|
||||
bool LeqZero<%Float%>(const %Float% &%x%)
|
||||
%$$
|
||||
in the $code CppAD$$ namespace.
|
||||
This function returns true if $icode x$$ is less than or equal to zero
|
||||
and false otherwise.
|
||||
It is used by $code LuSolve$$ to avoid taking the log of
|
||||
zero (or a negative number if $icode Float$$ corresponds to real numbers).
|
||||
This template function definition assumes that the operator
|
||||
$code <=$$ is defined for $icode Float$$ objects.
|
||||
If this operator is not defined for your use of $icode Float$$,
|
||||
you will need to specialize this template so that it works for your
|
||||
use of $code LuSolve$$.
|
||||
$pre
|
||||
|
||||
$$
|
||||
Complex numbers do not have the operation or $code <=$$ defined.
|
||||
In addition, in the complex case,
|
||||
one can take the log of a negative number.
|
||||
The specializations
|
||||
$codei%
|
||||
bool LeqZero< std::complex<float> > (const std::complex<float> &%x%)
|
||||
bool LeqZero< std::complex<double> >(const std::complex<double> &%x%)
|
||||
%$$
|
||||
are defined by including $code lu_solve.hpp$$.
|
||||
These return true if $icode x$$ is zero and false otherwise.
|
||||
|
||||
$head AbsGeq$$
|
||||
Including the file $code lu_solve.hpp$$ defines the template function
|
||||
$codei%
|
||||
template <typename %Float%>
|
||||
bool AbsGeq<%Float%>(const %Float% &%x%, const %Float% &%y%)
|
||||
%$$
|
||||
If the type $icode Float$$ does not support the $code <=$$ operation
|
||||
and it is not $code std::complex<float>$$ or $code std::complex<double>$$,
|
||||
see the documentation for $code AbsGeq$$ in $cref/LuFactor/LuFactor/AbsGeq/$$.
|
||||
|
||||
$children%
|
||||
example/utility/lu_solve.cpp%
|
||||
omh/lu_solve_hpp.omh
|
||||
%$$
|
||||
$head Example$$
|
||||
The file
|
||||
$cref lu_solve.cpp$$
|
||||
contains an example and test of using this routine.
|
||||
It returns true if it succeeds and false otherwise.
|
||||
|
||||
$head Source$$
|
||||
The file $cref lu_solve.hpp$$ contains the
|
||||
current source code that implements these specifications.
|
||||
|
||||
$end
|
||||
--------------------------------------------------------------------------
|
||||
*/
|
||||
// BEGIN C++
|
||||
# include <complex>
|
||||
# include <vector>
|
||||
|
||||
// link exp for float and double cases
|
||||
# include <cppad/base_require.hpp>
|
||||
|
||||
# include <cppad/core/cppad_assert.hpp>
|
||||
# include <cppad/utility/check_simple_vector.hpp>
|
||||
# include <cppad/utility/check_numeric_type.hpp>
|
||||
# include <cppad/utility/lu_factor.hpp>
|
||||
# include <cppad/utility/lu_invert.hpp>
|
||||
|
||||
namespace CppAD { // BEGIN CppAD namespace
|
||||
|
||||
// LeqZero
|
||||
template <typename Float>
|
||||
inline bool LeqZero(const Float &x)
|
||||
{ return x <= Float(0); }
|
||||
inline bool LeqZero( const std::complex<double> &x )
|
||||
{ return x == std::complex<double>(0); }
|
||||
inline bool LeqZero( const std::complex<float> &x )
|
||||
{ return x == std::complex<float>(0); }
|
||||
|
||||
// LuSolve
|
||||
template <typename Float, typename FloatVector>
|
||||
int LuSolve(
|
||||
size_t n ,
|
||||
size_t m ,
|
||||
const FloatVector &A ,
|
||||
const FloatVector &B ,
|
||||
FloatVector &X ,
|
||||
Float &logdet )
|
||||
{
|
||||
// check numeric type specifications
|
||||
CheckNumericType<Float>();
|
||||
|
||||
// check simple vector class specifications
|
||||
CheckSimpleVector<Float, FloatVector>();
|
||||
|
||||
size_t p; // index of pivot element (diagonal of L)
|
||||
int signdet; // sign of the determinant
|
||||
Float pivot; // pivot element
|
||||
|
||||
// the value zero
|
||||
const Float zero(0);
|
||||
|
||||
// pivot row and column order in the matrix
|
||||
std::vector<size_t> ip(n);
|
||||
std::vector<size_t> jp(n);
|
||||
|
||||
// -------------------------------------------------------
|
||||
CPPAD_ASSERT_KNOWN(
|
||||
size_t(A.size()) == n * n,
|
||||
"Error in LuSolve: A must have size equal to n * n"
|
||||
);
|
||||
CPPAD_ASSERT_KNOWN(
|
||||
size_t(B.size()) == n * m,
|
||||
"Error in LuSolve: B must have size equal to n * m"
|
||||
);
|
||||
CPPAD_ASSERT_KNOWN(
|
||||
size_t(X.size()) == n * m,
|
||||
"Error in LuSolve: X must have size equal to n * m"
|
||||
);
|
||||
// -------------------------------------------------------
|
||||
|
||||
// copy A so that it does not change
|
||||
FloatVector Lu(A);
|
||||
|
||||
// copy B so that it does not change
|
||||
X = B;
|
||||
|
||||
// Lu factor the matrix A
|
||||
signdet = LuFactor(ip, jp, Lu);
|
||||
|
||||
// compute the log of the determinant
|
||||
logdet = Float(0);
|
||||
for(p = 0; p < n; p++)
|
||||
{ // pivot using the max absolute element
|
||||
pivot = Lu[ ip[p] * n + jp[p] ];
|
||||
|
||||
// check for determinant equal to zero
|
||||
if( pivot == zero )
|
||||
{ // abort the mission
|
||||
logdet = Float(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// update the determinant
|
||||
if( LeqZero ( pivot ) )
|
||||
{ logdet += log( - pivot );
|
||||
signdet = - signdet;
|
||||
}
|
||||
else logdet += log( pivot );
|
||||
|
||||
}
|
||||
|
||||
// solve the linear equations
|
||||
LuInvert(ip, jp, Lu, X);
|
||||
|
||||
// return the sign factor for the determinant
|
||||
return signdet;
|
||||
}
|
||||
} // END CppAD namespace
|
||||
// END C++
|
||||
# endif
|
||||
@@ -0,0 +1,214 @@
|
||||
# ifndef CPPAD_UTILITY_MEMORY_LEAK_HPP
|
||||
# define CPPAD_UTILITY_MEMORY_LEAK_HPP
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-17 Bradley M. Bell
|
||||
|
||||
CppAD is distributed under multiple licenses. This distribution is under
|
||||
the terms of the
|
||||
Eclipse Public License Version 1.0.
|
||||
|
||||
A copy of this license is included in the COPYING file of this distribution.
|
||||
Please visit http://www.coin-or.org/CppAD/ for information on other licenses.
|
||||
-------------------------------------------------------------------------- */
|
||||
/*
|
||||
$begin memory_leak$$
|
||||
$spell
|
||||
cppad
|
||||
num
|
||||
alloc
|
||||
hpp
|
||||
bool
|
||||
inuse
|
||||
$$
|
||||
|
||||
$section Memory Leak Detection$$
|
||||
$mindex memory_leak check static$$
|
||||
|
||||
$head Deprecated 2012-04-06$$
|
||||
This routine has been deprecated.
|
||||
You should instead use the routine $cref ta_free_all$$.
|
||||
|
||||
$head Syntax$$
|
||||
$codei%# include <cppad/utility/memory_leak.hpp>
|
||||
%$$
|
||||
$icode%flag% = %memory_leak()
|
||||
%$$
|
||||
$icode%flag% = %memory_leak%(%add_static%)%$$
|
||||
|
||||
$head Purpose$$
|
||||
This routine checks that the are no memory leaks
|
||||
caused by improper use of $cref thread_alloc$$ memory allocator.
|
||||
The deprecated memory allocator $cref TrackNewDel$$ is also checked.
|
||||
Memory errors in the deprecated $cref omp_alloc$$ allocator are
|
||||
reported as being in $code thread_alloc$$.
|
||||
|
||||
$head thread$$
|
||||
It is assumed that $cref/in_parallel()/ta_in_parallel/$$ is false
|
||||
and $cref/thread_num/ta_thread_num/$$ is zero when
|
||||
$code memory_leak$$ is called.
|
||||
|
||||
$head add_static$$
|
||||
This argument has prototype
|
||||
$codei%
|
||||
size_t %add_static%
|
||||
%$$
|
||||
and its default value is zero.
|
||||
Static variables hold onto memory forever.
|
||||
If the argument $icode add_static$$ is present (and non-zero),
|
||||
$code memory_leak$$ adds this amount of memory to the
|
||||
$cref/inuse/ta_inuse/$$ sum that corresponds to
|
||||
static variables in the program.
|
||||
A call with $icode add_static$$ should be make after
|
||||
a routine that has static variables which
|
||||
use $cref/get_memory/ta_get_memory/$$ to allocate memory.
|
||||
The value of $icode add_static$$ should be the difference of
|
||||
$codei%
|
||||
thread_alloc::inuse(0)
|
||||
%$$
|
||||
before and after the call.
|
||||
Since multiple statics may be allocated in different places in the program,
|
||||
it is expected that there will be multiple calls
|
||||
that use this option.
|
||||
|
||||
$head flag$$
|
||||
The return value $icode flag$$ has prototype
|
||||
$codei%
|
||||
bool %flag%
|
||||
%$$
|
||||
If $icode add_static$$ is non-zero,
|
||||
the return value for $code memory_leak$$ is false.
|
||||
Otherwise, the return value for $code memory_leak$$ should be false
|
||||
(indicating that the only allocated memory corresponds to static variables).
|
||||
|
||||
$head inuse$$
|
||||
It is assumed that, when $code memory_leak$$ is called,
|
||||
there should not be any memory
|
||||
$cref/inuse/ta_inuse/$$ or $cref omp_inuse$$ for any thread
|
||||
(except for inuse memory corresponding to static variables).
|
||||
If there is, a message is printed and $code memory_leak$$ returns false.
|
||||
|
||||
$head available$$
|
||||
It is assumed that, when $code memory_leak$$ is called,
|
||||
there should not be any memory
|
||||
$cref/available/ta_available/$$ or $cref omp_available$$ for any thread;
|
||||
i.e., it all has been returned to the system.
|
||||
If there is memory still available for any thread,
|
||||
$code memory_leak$$ returns false.
|
||||
|
||||
$head TRACK_COUNT$$
|
||||
It is assumed that, when $code memory_leak$$ is called,
|
||||
$cref/TrackCount/TrackNewDel/TrackCount/$$ will return a zero value.
|
||||
If it returns a non-zero value,
|
||||
$code memory_leak$$ returns false.
|
||||
|
||||
$head Error Message$$
|
||||
If this is the first call to $code memory_leak$$, no message is printed.
|
||||
Otherwise, if it returns true, an error message is printed
|
||||
to standard output describing the memory leak that was detected.
|
||||
|
||||
$end
|
||||
*/
|
||||
# include <iostream>
|
||||
# include <cppad/core/define.hpp>
|
||||
# include <cppad/utility/omp_alloc.hpp>
|
||||
# include <cppad/utility/thread_alloc.hpp>
|
||||
# include <cppad/utility/track_new_del.hpp>
|
||||
|
||||
namespace CppAD { // BEGIN_CPPAD_NAMESPACE
|
||||
/*!
|
||||
\file memory_leak.hpp
|
||||
File that implements a memory check at end of a CppAD program
|
||||
*/
|
||||
|
||||
/*!
|
||||
Function that checks
|
||||
allocator \c thread_alloc for misuse that results in memory leaks.
|
||||
Deprecated routines in track_new_del.hpp and omp_alloc.hpp are also checked.
|
||||
|
||||
\param add_static [in]
|
||||
The amount specified by \c add_static is added to the amount
|
||||
of memory that is expected to be used by thread zero for static variables.
|
||||
|
||||
\return
|
||||
If \c add_static is non-zero, the return value is \c false.
|
||||
Otherwise, if one of the following errors is detected,
|
||||
the return value is \c true:
|
||||
|
||||
\li
|
||||
Thread zero does not have the expected amount of inuse memory
|
||||
(for static variables).
|
||||
\li
|
||||
A thread, other than thread zero, has any inuse memory.
|
||||
\li
|
||||
Any thread has available memory.
|
||||
|
||||
\par
|
||||
If an error is detected, diagnostic information is printed to standard
|
||||
output.
|
||||
*/
|
||||
inline bool memory_leak(size_t add_static = 0)
|
||||
{ // CPPAD_ASSERT_FIRST_CALL_NOT_PARALLEL not necessary given asserts below
|
||||
static size_t thread_zero_static_inuse = 0;
|
||||
using std::cout;
|
||||
using std::endl;
|
||||
using CppAD::thread_alloc;
|
||||
using CppAD::omp_alloc;
|
||||
// --------------------------------------------------------------------
|
||||
CPPAD_ASSERT_KNOWN(
|
||||
! thread_alloc::in_parallel(),
|
||||
"memory_leak: in_parallel() is true."
|
||||
);
|
||||
CPPAD_ASSERT_KNOWN(
|
||||
thread_alloc::thread_num() == 0,
|
||||
"memory_leak: thread_num() is not zero."
|
||||
);
|
||||
if( add_static != 0 )
|
||||
{ thread_zero_static_inuse += add_static;
|
||||
return false;
|
||||
}
|
||||
bool leak = false;
|
||||
size_t thread = 0;
|
||||
|
||||
// check that memory in use for thread zero corresponds to statics
|
||||
size_t num_bytes = thread_alloc::inuse(thread);
|
||||
if( num_bytes != thread_zero_static_inuse )
|
||||
{ leak = true;
|
||||
cout << "thread zero: static inuse = " << thread_zero_static_inuse;
|
||||
cout << ", current inuse(0)= " << num_bytes << endl;
|
||||
}
|
||||
// check that no memory is currently available for this thread
|
||||
num_bytes = thread_alloc::available(thread);
|
||||
if( num_bytes != 0 )
|
||||
{ leak = true;
|
||||
cout << "thread zero: available = ";
|
||||
cout << num_bytes << endl;
|
||||
}
|
||||
for(thread = 1; thread < CPPAD_MAX_NUM_THREADS; thread++)
|
||||
{
|
||||
// check that no memory is currently in use for this thread
|
||||
num_bytes = thread_alloc::inuse(thread);
|
||||
if( num_bytes != 0 )
|
||||
{ leak = true;
|
||||
cout << "thread " << thread << ": inuse(thread) = ";
|
||||
cout << num_bytes << endl;
|
||||
}
|
||||
// check that no memory is currently available for this thread
|
||||
num_bytes = thread_alloc::available(thread);
|
||||
if( num_bytes != 0 )
|
||||
{ leak = true;
|
||||
cout << "thread " << thread << ": available(thread) = ";
|
||||
cout << num_bytes << endl;
|
||||
}
|
||||
}
|
||||
// ----------------------------------------------------------------------
|
||||
// check track_new_del
|
||||
if( CPPAD_TRACK_COUNT() != 0 )
|
||||
{ leak = true;
|
||||
CppAD::TrackElement::Print();
|
||||
}
|
||||
return leak;
|
||||
}
|
||||
|
||||
} // END_CPPAD_NAMESPACE
|
||||
# endif
|
||||
+193
@@ -0,0 +1,193 @@
|
||||
# ifndef CPPAD_UTILITY_NAN_HPP
|
||||
# define CPPAD_UTILITY_NAN_HPP
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-17 Bradley M. Bell
|
||||
|
||||
CppAD is distributed under multiple licenses. This distribution is under
|
||||
the terms of the
|
||||
Eclipse Public License Version 1.0.
|
||||
|
||||
A copy of this license is included in the COPYING file of this distribution.
|
||||
Please visit http://www.coin-or.org/CppAD/ for information on other licenses.
|
||||
-------------------------------------------------------------------------- */
|
||||
/*
|
||||
$begin nan$$
|
||||
$spell
|
||||
hasnan
|
||||
cppad
|
||||
hpp
|
||||
CppAD
|
||||
isnan
|
||||
bool
|
||||
const
|
||||
$$
|
||||
|
||||
$section Obtain Nan or Determine if a Value is Nan$$
|
||||
|
||||
$head Syntax$$
|
||||
$codei%# include <cppad/utility/nan.hpp>
|
||||
%$$
|
||||
$icode%b% = isnan(%s%)
|
||||
%$$
|
||||
$icode%b% = hasnan(%v%)%$$
|
||||
|
||||
$head Purpose$$
|
||||
It obtain and check for the value not a number $code nan$$.
|
||||
The IEEE standard specifies that a floating point value $icode a$$
|
||||
is $code nan$$ if and only if the following returns true
|
||||
$codei%
|
||||
%a% != %a%
|
||||
%$$
|
||||
|
||||
$head Include$$
|
||||
The file $code cppad/nan.hpp$$ is included by $code cppad/cppad.hpp$$
|
||||
but it can also be included separately with out the rest of
|
||||
the $code CppAD$$ routines.
|
||||
|
||||
$subhead Macros$$
|
||||
Some C++ compilers use preprocessor symbols called $code nan$$
|
||||
and $code isnan$$.
|
||||
These preprocessor symbols will no longer be defined after
|
||||
this file is included.
|
||||
|
||||
$head isnan$$
|
||||
This routine determines if a scalar value is $code nan$$.
|
||||
|
||||
$subhead s$$
|
||||
The argument $icode s$$ has prototype
|
||||
$codei%
|
||||
const %Scalar% %s%
|
||||
%$$
|
||||
|
||||
$subhead b$$
|
||||
The return value $icode b$$ has prototype
|
||||
$codei%
|
||||
bool %b%
|
||||
%$$
|
||||
It is true if the value $icode s$$ is $code nan$$.
|
||||
|
||||
$head hasnan$$
|
||||
This routine determines if a
|
||||
$cref SimpleVector$$ has an element that is $code nan$$.
|
||||
|
||||
$subhead v$$
|
||||
The argument $icode v$$ has prototype
|
||||
$codei%
|
||||
const %Vector% &%v%
|
||||
%$$
|
||||
(see $cref/Vector/nan/Vector/$$ for the definition of $icode Vector$$).
|
||||
|
||||
$subhead b$$
|
||||
The return value $icode b$$ has prototype
|
||||
$codei%
|
||||
bool %b%
|
||||
%$$
|
||||
It is true if the vector $icode v$$ has a $code nan$$.
|
||||
|
||||
|
||||
$head nan(zero)$$
|
||||
|
||||
$subhead Deprecated 2015-10-04$$
|
||||
This routine has been deprecated, use CppAD numeric limits
|
||||
$cref/quiet_NaN/numeric_limits/quiet_NaN/$$ in its place.
|
||||
|
||||
$subhead Syntax$$
|
||||
$icode%s% = nan(%z%)
|
||||
%$$
|
||||
|
||||
$subhead z$$
|
||||
The argument $icode z$$ has prototype
|
||||
$codei%
|
||||
const %Scalar% &%z%
|
||||
%$$
|
||||
and its value is zero
|
||||
(see $cref/Scalar/nan/Scalar/$$ for the definition of $icode Scalar$$).
|
||||
|
||||
$subhead s$$
|
||||
The return value $icode s$$ has prototype
|
||||
$codei%
|
||||
%Scalar% %s%
|
||||
%$$
|
||||
It is the value $code nan$$ for this floating point type.
|
||||
|
||||
$head Scalar$$
|
||||
The type $icode Scalar$$ must support the following operations;
|
||||
$table
|
||||
$bold Operation$$ $cnext $bold Description$$ $rnext
|
||||
$icode%a% / %b%$$ $cnext
|
||||
division operator (returns a $icode Scalar$$ object)
|
||||
$rnext
|
||||
$icode%a% == %b%$$ $cnext
|
||||
equality operator (returns a $code bool$$ object)
|
||||
$rnext
|
||||
$icode%a% != %b%$$ $cnext
|
||||
not equality operator (returns a $code bool$$ object)
|
||||
$tend
|
||||
Note that the division operator will be used with $icode a$$ and $icode b$$
|
||||
equal to zero. For some types (e.g. $code int$$) this may generate
|
||||
an exception. No attempt is made to catch any such exception.
|
||||
|
||||
$head Vector$$
|
||||
The type $icode Vector$$ must be a $cref SimpleVector$$ class with
|
||||
elements of type $icode Scalar$$.
|
||||
|
||||
$children%
|
||||
example/utility/nan.cpp
|
||||
%$$
|
||||
$head Example$$
|
||||
The file $cref nan.cpp$$
|
||||
contains an example and test of this routine.
|
||||
It returns true if it succeeds and false otherwise.
|
||||
|
||||
$end
|
||||
*/
|
||||
|
||||
# include <cstddef>
|
||||
# include <cppad/core/cppad_assert.hpp>
|
||||
|
||||
// needed before one can use CPPAD_ASSERT_FIRST_CALL_NOT_PARALLEL
|
||||
# include <cppad/utility/thread_alloc.hpp>
|
||||
|
||||
/*
|
||||
# define nan There must be a define for every CppAD undef
|
||||
*/
|
||||
# ifdef nan
|
||||
# undef nan
|
||||
# endif
|
||||
|
||||
/*
|
||||
# define isnan There must be a define for every CppAD undef
|
||||
*/
|
||||
# ifdef isnan
|
||||
# undef isnan
|
||||
# endif
|
||||
|
||||
namespace CppAD { // BEGIN CppAD namespace
|
||||
|
||||
template <class Scalar>
|
||||
inline bool isnan(const Scalar &s)
|
||||
{ return (s != s);
|
||||
}
|
||||
|
||||
template <class Vector>
|
||||
bool hasnan(const Vector &v)
|
||||
{
|
||||
bool found_nan;
|
||||
size_t i;
|
||||
i = v.size();
|
||||
found_nan = false;
|
||||
// on MS Visual Studio 2012, CppAD required in front of isnan ?
|
||||
while(i--)
|
||||
found_nan |= CppAD::isnan(v[i]);
|
||||
return found_nan;
|
||||
}
|
||||
|
||||
template <class Scalar>
|
||||
inline Scalar nan(const Scalar &zero)
|
||||
{ return zero / zero;
|
||||
}
|
||||
|
||||
} // End CppAD namespace
|
||||
|
||||
# endif
|
||||
+270
@@ -0,0 +1,270 @@
|
||||
# ifndef CPPAD_UTILITY_NEAR_EQUAL_HPP
|
||||
# define CPPAD_UTILITY_NEAR_EQUAL_HPP
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-17 Bradley M. Bell
|
||||
|
||||
CppAD is distributed under multiple licenses. This distribution is under
|
||||
the terms of the
|
||||
Eclipse Public License Version 1.0.
|
||||
|
||||
A copy of this license is included in the COPYING file of this distribution.
|
||||
Please visit http://www.coin-or.org/CppAD/ for information on other licenses.
|
||||
-------------------------------------------------------------------------- */
|
||||
|
||||
/*
|
||||
$begin NearEqual$$
|
||||
$spell
|
||||
cppad.hpp
|
||||
sqrt
|
||||
cout
|
||||
endl
|
||||
Microsoft
|
||||
std
|
||||
Cpp
|
||||
namespace
|
||||
const
|
||||
bool
|
||||
$$
|
||||
|
||||
$section Determine if Two Values Are Nearly Equal$$
|
||||
$mindex NearEqual near absolute difference relative$$
|
||||
|
||||
|
||||
$head Syntax$$
|
||||
|
||||
$codei%# include <cppad/utility/near_equal.hpp>
|
||||
%$$
|
||||
$icode%b% = NearEqual(%x%, %y%, %r%, %a%)%$$
|
||||
|
||||
|
||||
$head Purpose$$
|
||||
Returns true,
|
||||
if $icode x$$ and $icode y$$ are nearly equal,
|
||||
and false otherwise.
|
||||
|
||||
$head x$$
|
||||
The argument $icode x$$
|
||||
has one of the following possible prototypes
|
||||
$codei%
|
||||
const %Type% &%x%,
|
||||
const std::complex<%Type%> &%x%,
|
||||
%$$
|
||||
|
||||
$head y$$
|
||||
The argument $icode y$$
|
||||
has one of the following possible prototypes
|
||||
$codei%
|
||||
const %Type% &%y%,
|
||||
const std::complex<%Type%> &%y%,
|
||||
%$$
|
||||
|
||||
$head r$$
|
||||
The relative error criteria $icode r$$ has prototype
|
||||
$codei%
|
||||
const %Type% &%r%
|
||||
%$$
|
||||
It must be greater than or equal to zero.
|
||||
The relative error condition is defined as:
|
||||
$latex \[
|
||||
| x - y | \leq r ( |x| + |y| )
|
||||
\] $$
|
||||
|
||||
$head a$$
|
||||
The absolute error criteria $icode a$$ has prototype
|
||||
$codei%
|
||||
const %Type% &%a%
|
||||
%$$
|
||||
It must be greater than or equal to zero.
|
||||
The absolute error condition is defined as:
|
||||
$latex \[
|
||||
| x - y | \leq a
|
||||
\] $$
|
||||
|
||||
$head b$$
|
||||
The return value $icode b$$ has prototype
|
||||
$codei%
|
||||
bool %b%
|
||||
%$$
|
||||
If either $icode x$$ or $icode y$$ is infinite or not a number,
|
||||
the return value is false.
|
||||
Otherwise, if either the relative or absolute error
|
||||
condition (defined above) is satisfied, the return value is true.
|
||||
Otherwise, the return value is false.
|
||||
|
||||
$head Type$$
|
||||
The type $icode Type$$ must be a
|
||||
$cref NumericType$$.
|
||||
The routine $cref CheckNumericType$$ will generate
|
||||
an error message if this is not the case.
|
||||
In addition, the following operations must be defined objects
|
||||
$icode a$$ and $icode b$$ of type $icode Type$$:
|
||||
$table
|
||||
$bold Operation$$ $cnext
|
||||
$bold Description$$ $rnext
|
||||
$icode%a% <= %b%$$ $cnext
|
||||
less that or equal operator (returns a $code bool$$ object)
|
||||
$tend
|
||||
|
||||
$head Include Files$$
|
||||
The file $code cppad/near_equal.hpp$$ is included by $code cppad/cppad.hpp$$
|
||||
but it can also be included separately with out the rest of
|
||||
the $code CppAD$$ routines.
|
||||
|
||||
$head Example$$
|
||||
$children%
|
||||
example/utility/near_equal.cpp
|
||||
%$$
|
||||
The file $cref near_equal.cpp$$ contains an example
|
||||
and test of $code NearEqual$$.
|
||||
It return true if it succeeds and false otherwise.
|
||||
|
||||
$head Exercise$$
|
||||
Create and run a program that contains the following code:
|
||||
$codep
|
||||
using std::complex;
|
||||
using std::cout;
|
||||
using std::endl;
|
||||
|
||||
complex<double> one(1., 0), i(0., 1);
|
||||
complex<double> x = one / i;
|
||||
complex<double> y = - i;
|
||||
double r = 1e-12;
|
||||
double a = 0;
|
||||
bool ok = CppAD::NearEqual(x, y, r, a);
|
||||
if( ok )
|
||||
cout << "Ok" << endl;
|
||||
else cout << "Error" << endl;
|
||||
$$
|
||||
|
||||
$end
|
||||
|
||||
*/
|
||||
|
||||
# include <limits>
|
||||
# include <complex>
|
||||
# include <cppad/core/cppad_assert.hpp>
|
||||
# include <cppad/utility/check_numeric_type.hpp>
|
||||
|
||||
namespace CppAD { // Begin CppAD namespace
|
||||
|
||||
// determine if both x and y are finite values
|
||||
template <class Type>
|
||||
bool near_equal_isfinite(const Type &x , const Type &y)
|
||||
{ Type infinity = Type( std::numeric_limits<double>::infinity() );
|
||||
|
||||
// handle bug where some compilers return true for nan == nan
|
||||
bool xNan = x != x;
|
||||
bool yNan = y != y;
|
||||
|
||||
// infinite cases
|
||||
bool xInf = (x == infinity || x == - infinity);
|
||||
bool yInf = (x == infinity || x == - infinity);
|
||||
|
||||
return ! (xNan | yNan | xInf | yInf);
|
||||
}
|
||||
|
||||
template <class Type>
|
||||
bool NearEqual(const Type &x, const Type &y, const Type &r, const Type &a)
|
||||
{
|
||||
CheckNumericType<Type>();
|
||||
Type zero(0);
|
||||
|
||||
CPPAD_ASSERT_KNOWN(
|
||||
zero <= r,
|
||||
"Error in NearEqual: relative error is less than zero"
|
||||
);
|
||||
CPPAD_ASSERT_KNOWN(
|
||||
zero <= a,
|
||||
"Error in NearEqual: absolute error is less than zero"
|
||||
);
|
||||
|
||||
// check for special cases
|
||||
if( ! CppAD::near_equal_isfinite(x, y) )
|
||||
return false;
|
||||
|
||||
Type ax = x;
|
||||
if( ax <= zero )
|
||||
ax = - ax;
|
||||
|
||||
Type ay = y;
|
||||
if( ay <= zero )
|
||||
ay = - ay;
|
||||
|
||||
Type ad = x - y;
|
||||
if( ad <= zero )
|
||||
ad = - ad;
|
||||
|
||||
if( ad <= a )
|
||||
return true;
|
||||
|
||||
if( ad <= r * (ax + ay) )
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
template <class Type>
|
||||
bool NearEqual(
|
||||
const std::complex<Type> &x ,
|
||||
const std::complex<Type> &y ,
|
||||
const Type &r ,
|
||||
const Type & a )
|
||||
{
|
||||
CheckNumericType<Type>();
|
||||
# ifndef NDEBUG
|
||||
Type zero(0);
|
||||
# endif
|
||||
|
||||
CPPAD_ASSERT_KNOWN(
|
||||
zero <= r,
|
||||
"Error in NearEqual: relative error is less than zero"
|
||||
);
|
||||
CPPAD_ASSERT_KNOWN(
|
||||
zero <= a,
|
||||
"Error in NearEqual: absolute error is less than zero"
|
||||
);
|
||||
|
||||
// check for special cases
|
||||
if( ! CppAD::near_equal_isfinite(x.real(), x.imag()) )
|
||||
return false;
|
||||
if( ! CppAD::near_equal_isfinite(y.real(), y.imag()) )
|
||||
return false;
|
||||
|
||||
std::complex<Type> d = x - y;
|
||||
|
||||
Type ad = std::abs(d);
|
||||
if( ad <= a )
|
||||
return true;
|
||||
|
||||
Type ax = std::abs(x);
|
||||
Type ay = std::abs(y);
|
||||
if( ad <= r * (ax + ay) )
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
template <class Type>
|
||||
bool NearEqual(
|
||||
const std::complex<Type> &x ,
|
||||
const Type &y ,
|
||||
const Type &r ,
|
||||
const Type & a )
|
||||
{
|
||||
return NearEqual(x, std::complex<Type>(y, Type(0)), r, a);
|
||||
}
|
||||
|
||||
template <class Type>
|
||||
bool NearEqual(
|
||||
const Type &x ,
|
||||
const std::complex<Type> &y ,
|
||||
const Type &r ,
|
||||
const Type & a )
|
||||
{
|
||||
return NearEqual(std::complex<Type>(x, Type(0)), y, r, a);
|
||||
}
|
||||
|
||||
} // END CppAD namespace
|
||||
|
||||
# endif
|
||||
@@ -0,0 +1,595 @@
|
||||
# ifndef CPPAD_UTILITY_ODE_ERR_CONTROL_HPP
|
||||
# define CPPAD_UTILITY_ODE_ERR_CONTROL_HPP
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-17 Bradley M. Bell
|
||||
|
||||
CppAD is distributed under multiple licenses. This distribution is under
|
||||
the terms of the
|
||||
Eclipse Public License Version 1.0.
|
||||
|
||||
A copy of this license is included in the COPYING file of this distribution.
|
||||
Please visit http://www.coin-or.org/CppAD/ for information on other licenses.
|
||||
-------------------------------------------------------------------------- */
|
||||
|
||||
/*
|
||||
$begin OdeErrControl$$
|
||||
$spell
|
||||
cppad.hpp
|
||||
nstep
|
||||
maxabs
|
||||
exp
|
||||
scur
|
||||
CppAD
|
||||
xf
|
||||
tf
|
||||
xi
|
||||
smin
|
||||
smax
|
||||
eabs
|
||||
erel
|
||||
ef
|
||||
ta
|
||||
tb
|
||||
xa
|
||||
xb
|
||||
const
|
||||
eb
|
||||
$$
|
||||
|
||||
|
||||
|
||||
$section An Error Controller for ODE Solvers$$
|
||||
$mindex OdeErrControl differential equation$$
|
||||
|
||||
$head Syntax$$
|
||||
$codei%# include <cppad/utility/ode_err_control.hpp>
|
||||
%$$
|
||||
$icode%xf% = OdeErrControl(%method%, %ti%, %tf%, %xi%,
|
||||
%smin%, %smax%, %scur%, %eabs%, %erel%, %ef% , %maxabs%, %nstep% )%$$
|
||||
|
||||
|
||||
$head Description$$
|
||||
Let $latex \B{R}$$ denote the real numbers
|
||||
and let $latex F : \B{R} \times \B{R}^n \rightarrow \B{R}^n$$ be a smooth function.
|
||||
We define $latex X : [ti , tf] \rightarrow \B{R}^n$$ by
|
||||
the following initial value problem:
|
||||
$latex \[
|
||||
\begin{array}{rcl}
|
||||
X(ti) & = & xi \\
|
||||
X'(t) & = & F[t , X(t)]
|
||||
\end{array}
|
||||
\] $$
|
||||
The routine $code OdeErrControl$$ can be used to adjust the step size
|
||||
used an arbitrary integration methods in order to be as fast as possible
|
||||
and still with in a requested error bound.
|
||||
|
||||
$head Include$$
|
||||
The file $code cppad/ode_err_control.hpp$$ is included by
|
||||
$code cppad/cppad.hpp$$
|
||||
but it can also be included separately with out the rest of
|
||||
the $code CppAD$$ routines.
|
||||
|
||||
$head Notation$$
|
||||
The template parameter types $cref/Scalar/OdeErrControl/Scalar/$$ and
|
||||
$cref/Vector/OdeErrControl/Vector/$$ are documented below.
|
||||
|
||||
$head xf$$
|
||||
The return value $icode xf$$ has the prototype
|
||||
$codei%
|
||||
%Vector% %xf%
|
||||
%$$
|
||||
(see description of $cref/Vector/OdeErrControl/Vector/$$ below).
|
||||
and the size of $icode xf$$ is equal to $icode n$$.
|
||||
If $icode xf$$ contains not a number $cref nan$$,
|
||||
see the discussion of $cref/step/OdeErrControl/Method/Nan/$$.
|
||||
|
||||
$head Method$$
|
||||
The class $icode Method$$
|
||||
and the object $icode method$$ satisfy the following syntax
|
||||
$codei%
|
||||
%Method% &%method%
|
||||
%$$
|
||||
The object $icode method$$ must support $code step$$ and
|
||||
$code order$$ member functions defined below:
|
||||
|
||||
$subhead step$$
|
||||
The syntax
|
||||
$codei%
|
||||
%method%.step(%ta%, %tb%, %xa%, %xb%, %eb%)
|
||||
%$$
|
||||
executes one step of the integration method.
|
||||
$codei%
|
||||
|
||||
%ta%
|
||||
%$$
|
||||
The argument $icode ta$$ has prototype
|
||||
$codei%
|
||||
const %Scalar% &%ta%
|
||||
%$$
|
||||
It specifies the initial time for this step in the
|
||||
ODE integration.
|
||||
(see description of $cref/Scalar/OdeErrControl/Scalar/$$ below).
|
||||
$codei%
|
||||
|
||||
%tb%
|
||||
%$$
|
||||
The argument $icode tb$$ has prototype
|
||||
$codei%
|
||||
const %Scalar% &%tb%
|
||||
%$$
|
||||
It specifies the final time for this step in the
|
||||
ODE integration.
|
||||
$codei%
|
||||
|
||||
%xa%
|
||||
%$$
|
||||
The argument $icode xa$$ has prototype
|
||||
$codei%
|
||||
const %Vector% &%xa%
|
||||
%$$
|
||||
and size $icode n$$.
|
||||
It specifies the value of $latex X(ta)$$.
|
||||
(see description of $cref/Vector/OdeErrControl/Vector/$$ below).
|
||||
$codei%
|
||||
|
||||
%xb%
|
||||
%$$
|
||||
The argument value $icode xb$$ has prototype
|
||||
$codei%
|
||||
%Vector% &%xb%
|
||||
%$$
|
||||
and size $icode n$$.
|
||||
The input value of its elements does not matter.
|
||||
On output,
|
||||
it contains the approximation for $latex X(tb)$$ that the method obtains.
|
||||
$codei%
|
||||
|
||||
%eb%
|
||||
%$$
|
||||
The argument value $icode eb$$ has prototype
|
||||
$codei%
|
||||
%Vector% &%eb%
|
||||
%$$
|
||||
and size $icode n$$.
|
||||
The input value of its elements does not matter.
|
||||
On output,
|
||||
it contains an estimate for the error in the approximation $icode xb$$.
|
||||
It is assumed (locally) that the error bound in this approximation
|
||||
nearly equal to $latex K (tb - ta)^m$$
|
||||
where $icode K$$ is a fixed constant and $icode m$$
|
||||
is the corresponding argument to $code CodeControl$$.
|
||||
|
||||
$subhead Nan$$
|
||||
If any element of the vector $icode eb$$ or $icode xb$$ are
|
||||
not a number $code nan$$,
|
||||
the current step is considered to large.
|
||||
If this happens with the current step size equal to $icode smin$$,
|
||||
$code OdeErrControl$$ returns with $icode xf$$ and $icode ef$$ as vectors
|
||||
of $code nan$$.
|
||||
|
||||
$subhead order$$
|
||||
If $icode m$$ is $code size_t$$,
|
||||
the object $icode method$$ must also support the following syntax
|
||||
$codei%
|
||||
%m% = %method%.order()
|
||||
%$$
|
||||
The return value $icode m$$ is the order of the error estimate;
|
||||
i.e., there is a constant K such that if $latex ti \leq ta \leq tb \leq tf$$,
|
||||
$latex \[
|
||||
| eb(tb) | \leq K | tb - ta |^m
|
||||
\] $$
|
||||
where $icode ta$$, $icode tb$$, and $icode eb$$ are as in
|
||||
$icode%method%.step(%ta%, %tb%, %xa%, %xb%, %eb%)%$$
|
||||
|
||||
|
||||
$head ti$$
|
||||
The argument $icode ti$$ has prototype
|
||||
$codei%
|
||||
const %Scalar% &%ti%
|
||||
%$$
|
||||
It specifies the initial time for the integration of
|
||||
the differential equation.
|
||||
|
||||
|
||||
$head tf$$
|
||||
The argument $icode tf$$ has prototype
|
||||
$codei%
|
||||
const %Scalar% &%tf%
|
||||
%$$
|
||||
It specifies the final time for the integration of
|
||||
the differential equation.
|
||||
|
||||
$head xi$$
|
||||
The argument $icode xi$$ has prototype
|
||||
$codei%
|
||||
const %Vector% &%xi%
|
||||
%$$
|
||||
and size $icode n$$.
|
||||
It specifies value of $latex X(ti)$$.
|
||||
|
||||
$head smin$$
|
||||
The argument $icode smin$$ has prototype
|
||||
$codei%
|
||||
const %Scalar% &%smin%
|
||||
%$$
|
||||
The step size during a call to $icode method$$ is defined as
|
||||
the corresponding value of $latex tb - ta$$.
|
||||
If $latex tf - ti \leq smin$$,
|
||||
the integration will be done in one step of size $icode tf - ti$$.
|
||||
Otherwise,
|
||||
the minimum value of $icode tb - ta$$ will be $latex smin$$
|
||||
except for the last two calls to $icode method$$ where it may be
|
||||
as small as $latex smin / 2$$.
|
||||
|
||||
$head smax$$
|
||||
The argument $icode smax$$ has prototype
|
||||
$codei%
|
||||
const %Scalar% &%smax%
|
||||
%$$
|
||||
It specifies the maximum step size to use during the integration;
|
||||
i.e., the maximum value for $latex tb - ta$$ in a call to $icode method$$.
|
||||
The value of $icode smax$$ must be greater than or equal $icode smin$$.
|
||||
|
||||
$head scur$$
|
||||
The argument $icode scur$$ has prototype
|
||||
$codei%
|
||||
%Scalar% &%scur%
|
||||
%$$
|
||||
The value of $icode scur$$ is the suggested next step size,
|
||||
based on error criteria, to try in the next call to $icode method$$.
|
||||
On input it corresponds to the first call to $icode method$$,
|
||||
in this call to $code OdeErrControl$$ (where $latex ta = ti$$).
|
||||
On output it corresponds to the next call to $icode method$$,
|
||||
in a subsequent call to $code OdeErrControl$$ (where $icode ta = tf$$).
|
||||
|
||||
$head eabs$$
|
||||
The argument $icode eabs$$ has prototype
|
||||
$codei%
|
||||
const %Vector% &%eabs%
|
||||
%$$
|
||||
and size $icode n$$.
|
||||
Each of the elements of $icode eabs$$ must be
|
||||
greater than or equal zero.
|
||||
It specifies a bound for the absolute
|
||||
error in the return value $icode xf$$ as an approximation for $latex X(tf)$$.
|
||||
(see the
|
||||
$cref/error criteria discussion/OdeErrControl/Error Criteria Discussion/$$
|
||||
below).
|
||||
|
||||
$head erel$$
|
||||
The argument $icode erel$$ has prototype
|
||||
$codei%
|
||||
const %Scalar% &%erel%
|
||||
%$$
|
||||
and is greater than or equal zero.
|
||||
It specifies a bound for the relative
|
||||
error in the return value $icode xf$$ as an approximation for $latex X(tf)$$
|
||||
(see the
|
||||
$cref/error criteria discussion/OdeErrControl/Error Criteria Discussion/$$
|
||||
below).
|
||||
|
||||
$head ef$$
|
||||
The argument value $icode ef$$ has prototype
|
||||
$codei%
|
||||
%Vector% &%ef%
|
||||
%$$
|
||||
and size $icode n$$.
|
||||
The input value of its elements does not matter.
|
||||
On output,
|
||||
it contains an estimated bound for the
|
||||
absolute error in the approximation $icode xf$$; i.e.,
|
||||
$latex \[
|
||||
ef_i > | X( tf )_i - xf_i |
|
||||
\] $$
|
||||
If on output $icode ef$$ contains not a number $code nan$$,
|
||||
see the discussion of $cref/step/OdeErrControl/Method/Nan/$$.
|
||||
|
||||
$head maxabs$$
|
||||
The argument $icode maxabs$$ is optional in the call to $code OdeErrControl$$.
|
||||
If it is present, it has the prototype
|
||||
$codei%
|
||||
%Vector% &%maxabs%
|
||||
%$$
|
||||
and size $icode n$$.
|
||||
The input value of its elements does not matter.
|
||||
On output,
|
||||
it contains an estimate for the
|
||||
maximum absolute value of $latex X(t)$$; i.e.,
|
||||
$latex \[
|
||||
maxabs[i] \approx \max \left\{
|
||||
| X( t )_i | \; : \; t \in [ti, tf]
|
||||
\right\}
|
||||
\] $$
|
||||
|
||||
$head nstep$$
|
||||
The argument $icode nstep$$ is optional in the call to $code OdeErrControl$$.
|
||||
If it is present, it has the prototype
|
||||
$codei%
|
||||
%size_t% &%nstep%
|
||||
%$$
|
||||
Its input value does not matter and its output value
|
||||
is the number of calls to $icode%method%.step%$$
|
||||
used by $code OdeErrControl$$.
|
||||
|
||||
$head Error Criteria Discussion$$
|
||||
The relative error criteria $icode erel$$ and
|
||||
absolute error criteria $icode eabs$$ are enforced during each step of the
|
||||
integration of the ordinary differential equations.
|
||||
In addition, they are inversely scaled by the step size so that
|
||||
the total error bound is less than the sum of the error bounds.
|
||||
To be specific, if $latex \tilde{X} (t)$$ is the approximate solution
|
||||
at time $latex t$$,
|
||||
$icode ta$$ is the initial step time,
|
||||
and $icode tb$$ is the final step time,
|
||||
$latex \[
|
||||
\left| \tilde{X} (tb)_j - X (tb)_j \right|
|
||||
\leq
|
||||
\frac{tf - ti}{tb - ta}
|
||||
\left[ eabs[j] + erel \; | \tilde{X} (tb)_j | \right]
|
||||
\] $$
|
||||
If $latex X(tb)_j$$ is near zero for some $latex tb \in [ti , tf]$$,
|
||||
and one uses an absolute error criteria $latex eabs[j]$$ of zero,
|
||||
the error criteria above will force $code OdeErrControl$$
|
||||
to use step sizes equal to
|
||||
$cref/smin/OdeErrControl/smin/$$
|
||||
for steps ending near $latex tb$$.
|
||||
In this case, the error relative to $icode maxabs$$ can be judged after
|
||||
$code OdeErrControl$$ returns.
|
||||
If $icode ef$$ is to large relative to $icode maxabs$$,
|
||||
$code OdeErrControl$$ can be called again
|
||||
with a smaller value of $icode smin$$.
|
||||
|
||||
$head Scalar$$
|
||||
The type $icode Scalar$$ must satisfy the conditions
|
||||
for a $cref NumericType$$ type.
|
||||
The routine $cref CheckNumericType$$ will generate an error message
|
||||
if this is not the case.
|
||||
In addition, the following operations must be defined for
|
||||
$icode Scalar$$ objects $icode a$$ and $icode b$$:
|
||||
|
||||
$table
|
||||
$bold Operation$$ $cnext $bold Description$$ $rnext
|
||||
$icode%a% <= %b%$$ $cnext
|
||||
returns true (false) if $icode a$$ is less than or equal
|
||||
(greater than) $icode b$$.
|
||||
$rnext
|
||||
$icode%a% == %b%$$ $cnext
|
||||
returns true (false) if $icode a$$ is equal to $icode b$$.
|
||||
$rnext
|
||||
$codei%log(%a%)%$$ $cnext
|
||||
returns a $icode Scalar$$ equal to the logarithm of $icode a$$
|
||||
$rnext
|
||||
$codei%exp(%a%)%$$ $cnext
|
||||
returns a $icode Scalar$$ equal to the exponential of $icode a$$
|
||||
$tend
|
||||
|
||||
|
||||
$head Vector$$
|
||||
The type $icode Vector$$ must be a $cref SimpleVector$$ class with
|
||||
$cref/elements of type Scalar/SimpleVector/Elements of Specified Type/$$.
|
||||
The routine $cref CheckSimpleVector$$ will generate an error message
|
||||
if this is not the case.
|
||||
|
||||
$head Example$$
|
||||
$children%
|
||||
example/utility/ode_err_control.cpp%
|
||||
example/utility/ode_err_maxabs.cpp
|
||||
%$$
|
||||
The files
|
||||
$cref ode_err_control.cpp$$
|
||||
and
|
||||
$cref ode_err_maxabs.cpp$$
|
||||
contain examples and tests of using this routine.
|
||||
They return true if they succeed and false otherwise.
|
||||
|
||||
$head Theory$$
|
||||
Let $latex e(s)$$ be the error as a function of the
|
||||
step size $latex s$$ and suppose that there is a constant
|
||||
$latex K$$ such that $latex e(s) = K s^m$$.
|
||||
Let $latex a$$ be our error bound.
|
||||
Given the value of $latex e(s)$$, a step of size $latex \lambda s$$
|
||||
would be ok provided that
|
||||
$latex \[
|
||||
\begin{array}{rcl}
|
||||
a & \geq & e( \lambda s ) (tf - ti) / ( \lambda s ) \\
|
||||
a & \geq & K \lambda^m s^m (tf - ti) / ( \lambda s ) \\
|
||||
a & \geq & \lambda^{m-1} s^{m-1} (tf - ti) e(s) / s^m \\
|
||||
a & \geq & \lambda^{m-1} (tf - ti) e(s) / s \\
|
||||
\lambda^{m-1} & \leq & \frac{a}{e(s)} \frac{s}{tf - ti}
|
||||
\end{array}
|
||||
\] $$
|
||||
Thus if the right hand side of the last inequality is greater
|
||||
than or equal to one, the step of size $latex s$$ is ok.
|
||||
|
||||
$head Source Code$$
|
||||
The source code for this routine is in the file
|
||||
$code cppad/ode_err_control.hpp$$.
|
||||
|
||||
$end
|
||||
--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
// link exp and log for float and double
|
||||
# include <cppad/base_require.hpp>
|
||||
|
||||
# include <cppad/core/cppad_assert.hpp>
|
||||
# include <cppad/utility/check_simple_vector.hpp>
|
||||
# include <cppad/utility/nan.hpp>
|
||||
|
||||
namespace CppAD { // Begin CppAD namespace
|
||||
|
||||
template <typename Scalar, typename Vector, typename Method>
|
||||
Vector OdeErrControl(
|
||||
Method &method,
|
||||
const Scalar &ti ,
|
||||
const Scalar &tf ,
|
||||
const Vector &xi ,
|
||||
const Scalar &smin ,
|
||||
const Scalar &smax ,
|
||||
Scalar &scur ,
|
||||
const Vector &eabs ,
|
||||
const Scalar &erel ,
|
||||
Vector &ef ,
|
||||
Vector &maxabs,
|
||||
size_t &nstep )
|
||||
{
|
||||
// check simple vector class specifications
|
||||
CheckSimpleVector<Scalar, Vector>();
|
||||
|
||||
size_t n = size_t(xi.size());
|
||||
|
||||
CPPAD_ASSERT_KNOWN(
|
||||
smin <= smax,
|
||||
"Error in OdeErrControl: smin > smax"
|
||||
);
|
||||
CPPAD_ASSERT_KNOWN(
|
||||
size_t(eabs.size()) == n,
|
||||
"Error in OdeErrControl: size of eabs is not equal to n"
|
||||
);
|
||||
CPPAD_ASSERT_KNOWN(
|
||||
size_t(maxabs.size()) == n,
|
||||
"Error in OdeErrControl: size of maxabs is not equal to n"
|
||||
);
|
||||
size_t m = method.order();
|
||||
CPPAD_ASSERT_KNOWN(
|
||||
m > 1,
|
||||
"Error in OdeErrControl: m is less than or equal one"
|
||||
);
|
||||
|
||||
bool ok;
|
||||
bool minimum_step;
|
||||
size_t i;
|
||||
Vector xa(n), xb(n), eb(n), nan_vec(n);
|
||||
|
||||
// initialization
|
||||
Scalar zero(0.0);
|
||||
Scalar one(1.0);
|
||||
Scalar two(2.0);
|
||||
Scalar three(3.0);
|
||||
Scalar m1(double(m-1));
|
||||
Scalar ta = ti;
|
||||
for(i = 0; i < n; i++)
|
||||
{ nan_vec[i] = nan(zero);
|
||||
ef[i] = zero;
|
||||
xa[i] = xi[i];
|
||||
if( zero <= xi[i] )
|
||||
maxabs[i] = xi[i];
|
||||
else maxabs[i] = - xi[i];
|
||||
|
||||
}
|
||||
nstep = 0;
|
||||
|
||||
Scalar tb, step, lambda, axbi, a, r, root;
|
||||
while( ! (ta == tf) )
|
||||
{ // start with value suggested by error criteria
|
||||
step = scur;
|
||||
|
||||
// check maximum
|
||||
if( smax <= step )
|
||||
step = smax;
|
||||
|
||||
// check minimum
|
||||
minimum_step = step <= smin;
|
||||
if( minimum_step )
|
||||
step = smin;
|
||||
|
||||
// check if near the end
|
||||
if( tf <= ta + step * three / two )
|
||||
tb = tf;
|
||||
else tb = ta + step;
|
||||
|
||||
// try using this step size
|
||||
nstep++;
|
||||
method.step(ta, tb, xa, xb, eb);
|
||||
step = tb - ta;
|
||||
|
||||
// check if this steps error estimate is ok
|
||||
ok = ! (hasnan(xb) || hasnan(eb));
|
||||
if( (! ok) && minimum_step )
|
||||
{ ef = nan_vec;
|
||||
return nan_vec;
|
||||
}
|
||||
|
||||
// compute value of lambda for this step
|
||||
lambda = Scalar(10) * scur / step;
|
||||
for(i = 0; i < n; i++)
|
||||
{ if( zero <= xb[i] )
|
||||
axbi = xb[i];
|
||||
else axbi = - xb[i];
|
||||
a = eabs[i] + erel * axbi;
|
||||
if( ! (eb[i] == zero) )
|
||||
{ r = ( a / eb[i] ) * step / (tf - ti);
|
||||
root = exp( log(r) / m1 );
|
||||
if( root <= lambda )
|
||||
lambda = root;
|
||||
}
|
||||
}
|
||||
if( ok && ( one <= lambda || step <= smin * three / two) )
|
||||
{ // this step is within error limits or
|
||||
// close to the minimum size
|
||||
ta = tb;
|
||||
for(i = 0; i < n; i++)
|
||||
{ xa[i] = xb[i];
|
||||
ef[i] = ef[i] + eb[i];
|
||||
if( zero <= xb[i] )
|
||||
axbi = xb[i];
|
||||
else axbi = - xb[i];
|
||||
if( axbi > maxabs[i] )
|
||||
maxabs[i] = axbi;
|
||||
}
|
||||
}
|
||||
if( ! ok )
|
||||
{ // decrease step an see if method will work this time
|
||||
scur = step / two;
|
||||
}
|
||||
else if( ! (ta == tf) )
|
||||
{ // step suggested by the error criteria is not used
|
||||
// on the last step because it may be very small.
|
||||
scur = lambda * step / two;
|
||||
}
|
||||
}
|
||||
return xa;
|
||||
}
|
||||
|
||||
template <typename Scalar, typename Vector, typename Method>
|
||||
Vector OdeErrControl(
|
||||
Method &method,
|
||||
const Scalar &ti ,
|
||||
const Scalar &tf ,
|
||||
const Vector &xi ,
|
||||
const Scalar &smin ,
|
||||
const Scalar &smax ,
|
||||
Scalar &scur ,
|
||||
const Vector &eabs ,
|
||||
const Scalar &erel ,
|
||||
Vector &ef )
|
||||
{ Vector maxabs(xi.size());
|
||||
size_t nstep;
|
||||
return OdeErrControl(
|
||||
method, ti, tf, xi, smin, smax, scur, eabs, erel, ef, maxabs, nstep
|
||||
);
|
||||
}
|
||||
|
||||
template <typename Scalar, typename Vector, typename Method>
|
||||
Vector OdeErrControl(
|
||||
Method &method,
|
||||
const Scalar &ti ,
|
||||
const Scalar &tf ,
|
||||
const Vector &xi ,
|
||||
const Scalar &smin ,
|
||||
const Scalar &smax ,
|
||||
Scalar &scur ,
|
||||
const Vector &eabs ,
|
||||
const Scalar &erel ,
|
||||
Vector &ef ,
|
||||
Vector &maxabs)
|
||||
{ size_t nstep;
|
||||
return OdeErrControl(
|
||||
method, ti, tf, xi, smin, smax, scur, eabs, erel, ef, maxabs, nstep
|
||||
);
|
||||
}
|
||||
|
||||
} // End CppAD namespace
|
||||
|
||||
# endif
|
||||
+522
@@ -0,0 +1,522 @@
|
||||
# ifndef CPPAD_UTILITY_ODE_GEAR_HPP
|
||||
# define CPPAD_UTILITY_ODE_GEAR_HPP
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-17 Bradley M. Bell
|
||||
|
||||
CppAD is distributed under multiple licenses. This distribution is under
|
||||
the terms of the
|
||||
Eclipse Public License Version 1.0.
|
||||
|
||||
A copy of this license is included in the COPYING file of this distribution.
|
||||
Please visit http://www.coin-or.org/CppAD/ for information on other licenses.
|
||||
-------------------------------------------------------------------------- */
|
||||
|
||||
/*
|
||||
$begin OdeGear$$
|
||||
$spell
|
||||
cppad.hpp
|
||||
Jan
|
||||
bool
|
||||
const
|
||||
CppAD
|
||||
dep
|
||||
$$
|
||||
|
||||
|
||||
$section An Arbitrary Order Gear Method$$
|
||||
$mindex OdeGear Ode stiff differential equation$$
|
||||
|
||||
$head Syntax$$
|
||||
$codei%# include <cppad/utility/ode_gear.hpp>
|
||||
%$$
|
||||
$codei%OdeGear(%F%, %m%, %n%, %T%, %X%, %e%)%$$
|
||||
|
||||
|
||||
$head Purpose$$
|
||||
This routine applies
|
||||
$cref/Gear's Method/OdeGear/Gear's Method/$$
|
||||
to solve an explicit set of ordinary differential equations.
|
||||
We are given
|
||||
$latex f : \B{R} \times \B{R}^n \rightarrow \B{R}^n$$ be a smooth function.
|
||||
This routine solves the following initial value problem
|
||||
$latex \[
|
||||
\begin{array}{rcl}
|
||||
x( t_{m-1} ) & = & x^0 \\
|
||||
x^\prime (t) & = & f[t , x(t)]
|
||||
\end{array}
|
||||
\] $$
|
||||
for the value of $latex x( t_m )$$.
|
||||
If your set of ordinary differential equations are not stiff
|
||||
an explicit method may be better (perhaps $cref Runge45$$.)
|
||||
|
||||
$head Include$$
|
||||
The file $code cppad/ode_gear.hpp$$ is included by $code cppad/cppad.hpp$$
|
||||
but it can also be included separately with out the rest of
|
||||
the $code CppAD$$ routines.
|
||||
|
||||
$head Fun$$
|
||||
The class $icode Fun$$
|
||||
and the object $icode F$$ satisfy the prototype
|
||||
$codei%
|
||||
%Fun% &%F%
|
||||
%$$
|
||||
This must support the following set of calls
|
||||
$codei%
|
||||
%F%.Ode(%t%, %x%, %f%)
|
||||
%F%.Ode_dep(%t%, %x%, %f_x%)
|
||||
%$$
|
||||
|
||||
$subhead t$$
|
||||
The argument $icode t$$ has prototype
|
||||
$codei%
|
||||
const %Scalar% &%t%
|
||||
%$$
|
||||
(see description of $cref/Scalar/OdeGear/Scalar/$$ below).
|
||||
|
||||
$subhead x$$
|
||||
The argument $icode x$$ has prototype
|
||||
$codei%
|
||||
const %Vector% &%x%
|
||||
%$$
|
||||
and has size $icode n$$
|
||||
(see description of $cref/Vector/OdeGear/Vector/$$ below).
|
||||
|
||||
$subhead f$$
|
||||
The argument $icode f$$ to $icode%F%.Ode%$$ has prototype
|
||||
$codei%
|
||||
%Vector% &%f%
|
||||
%$$
|
||||
On input and output, $icode f$$ is a vector of size $icode n$$
|
||||
and the input values of the elements of $icode f$$ do not matter.
|
||||
On output,
|
||||
$icode f$$ is set equal to $latex f(t, x)$$
|
||||
(see $icode f(t, x)$$ in $cref/Purpose/OdeGear/Purpose/$$).
|
||||
|
||||
$subhead f_x$$
|
||||
The argument $icode f_x$$ has prototype
|
||||
$codei%
|
||||
%Vector% &%f_x%
|
||||
%$$
|
||||
On input and output, $icode f_x$$ is a vector of size $latex n * n$$
|
||||
and the input values of the elements of $icode f_x$$ do not matter.
|
||||
On output,
|
||||
$latex \[
|
||||
f\_x [i * n + j] = \partial_{x(j)} f_i ( t , x )
|
||||
\] $$
|
||||
|
||||
$subhead Warning$$
|
||||
The arguments $icode f$$, and $icode f_x$$
|
||||
must have a call by reference in their prototypes; i.e.,
|
||||
do not forget the $code &$$ in the prototype for
|
||||
$icode f$$ and $icode f_x$$.
|
||||
|
||||
$head m$$
|
||||
The argument $icode m$$ has prototype
|
||||
$codei%
|
||||
size_t %m%
|
||||
%$$
|
||||
It specifies the order (highest power of $latex t$$)
|
||||
used to represent the function $latex x(t)$$ in the multi-step method.
|
||||
Upon return from $code OdeGear$$,
|
||||
the $th i$$ component of the polynomial is defined by
|
||||
$latex \[
|
||||
p_i ( t_j ) = X[ j * n + i ]
|
||||
\] $$
|
||||
for $latex j = 0 , \ldots , m$$ (where $latex 0 \leq i < n$$).
|
||||
The value of $latex m$$ must be greater than or equal one.
|
||||
|
||||
$head n$$
|
||||
The argument $icode n$$ has prototype
|
||||
$codei%
|
||||
size_t %n%
|
||||
%$$
|
||||
It specifies the range space dimension of the
|
||||
vector valued function $latex x(t)$$.
|
||||
|
||||
$head T$$
|
||||
The argument $icode T$$ has prototype
|
||||
$codei%
|
||||
const %Vector% &%T%
|
||||
%$$
|
||||
and size greater than or equal to $latex m+1$$.
|
||||
For $latex j = 0 , \ldots m$$, $latex T[j]$$ is the time
|
||||
corresponding to time corresponding
|
||||
to a previous point in the multi-step method.
|
||||
The value $latex T[m]$$ is the time
|
||||
of the next point in the multi-step method.
|
||||
The array $latex T$$ must be monotone increasing; i.e.,
|
||||
$latex T[j] < T[j+1]$$.
|
||||
Above and below we often use the shorthand $latex t_j$$ for $latex T[j]$$.
|
||||
|
||||
|
||||
$head X$$
|
||||
The argument $icode X$$ has the prototype
|
||||
$codei%
|
||||
%Vector% &%X%
|
||||
%$$
|
||||
and size greater than or equal to $latex (m+1) * n$$.
|
||||
On input to $code OdeGear$$,
|
||||
for $latex j = 0 , \ldots , m-1$$, and
|
||||
$latex i = 0 , \ldots , n-1$$
|
||||
$latex \[
|
||||
X[ j * n + i ] = x_i ( t_j )
|
||||
\] $$
|
||||
Upon return from $code OdeGear$$,
|
||||
for $latex i = 0 , \ldots , n-1$$
|
||||
$latex \[
|
||||
X[ m * n + i ] \approx x_i ( t_m )
|
||||
\] $$
|
||||
|
||||
$head e$$
|
||||
The vector $icode e$$ is an approximate error bound for the result; i.e.,
|
||||
$latex \[
|
||||
e[i] \geq | X[ m * n + i ] - x_i ( t_m ) |
|
||||
\] $$
|
||||
The order of this approximation is one less than the order of
|
||||
the solution; i.e.,
|
||||
$latex \[
|
||||
e = O ( h^m )
|
||||
\] $$
|
||||
where $latex h$$ is the maximum of $latex t_{j+1} - t_j$$.
|
||||
|
||||
$head Scalar$$
|
||||
The type $icode Scalar$$ must satisfy the conditions
|
||||
for a $cref NumericType$$ type.
|
||||
The routine $cref CheckNumericType$$ will generate an error message
|
||||
if this is not the case.
|
||||
In addition, the following operations must be defined for
|
||||
$icode Scalar$$ objects $icode a$$ and $icode b$$:
|
||||
|
||||
$table
|
||||
$bold Operation$$ $cnext $bold Description$$ $rnext
|
||||
$icode%a% < %b%$$ $cnext
|
||||
less than operator (returns a $code bool$$ object)
|
||||
$tend
|
||||
|
||||
$head Vector$$
|
||||
The type $icode Vector$$ must be a $cref SimpleVector$$ class with
|
||||
$cref/elements of type Scalar/SimpleVector/Elements of Specified Type/$$.
|
||||
The routine $cref CheckSimpleVector$$ will generate an error message
|
||||
if this is not the case.
|
||||
|
||||
$head Example$$
|
||||
$children%
|
||||
example/utility/ode_gear.cpp
|
||||
%$$
|
||||
The file
|
||||
$cref ode_gear.cpp$$
|
||||
contains an example and test a test of using this routine.
|
||||
It returns true if it succeeds and false otherwise.
|
||||
|
||||
$head Source Code$$
|
||||
The source code for this routine is in the file
|
||||
$code cppad/ode_gear.hpp$$.
|
||||
|
||||
$head Theory$$
|
||||
For this discussion we use the shorthand $latex x_j$$
|
||||
for the value $latex x ( t_j ) \in \B{R}^n$$ which is not to be confused
|
||||
with $latex x_i (t) \in \B{R}$$ in the notation above.
|
||||
The interpolating polynomial $latex p(t)$$ is given by
|
||||
$latex \[
|
||||
p(t) =
|
||||
\sum_{j=0}^m
|
||||
x_j
|
||||
\frac{
|
||||
\prod_{i \neq j} ( t - t_i )
|
||||
}{
|
||||
\prod_{i \neq j} ( t_j - t_i )
|
||||
}
|
||||
\] $$
|
||||
The derivative $latex p^\prime (t)$$ is given by
|
||||
$latex \[
|
||||
p^\prime (t) =
|
||||
\sum_{j=0}^m
|
||||
x_j
|
||||
\frac{
|
||||
\sum_{i \neq j} \prod_{k \neq i,j} ( t - t_k )
|
||||
}{
|
||||
\prod_{k \neq j} ( t_j - t_k )
|
||||
}
|
||||
\] $$
|
||||
Evaluating the derivative at the point $latex t_\ell$$ we have
|
||||
$latex \[
|
||||
\begin{array}{rcl}
|
||||
p^\prime ( t_\ell ) & = &
|
||||
x_\ell
|
||||
\frac{
|
||||
\sum_{i \neq \ell} \prod_{k \neq i,\ell} ( t_\ell - t_k )
|
||||
}{
|
||||
\prod_{k \neq \ell} ( t_\ell - t_k )
|
||||
}
|
||||
+
|
||||
\sum_{j \neq \ell}
|
||||
x_j
|
||||
\frac{
|
||||
\sum_{i \neq j} \prod_{k \neq i,j} ( t_\ell - t_k )
|
||||
}{
|
||||
\prod_{k \neq j} ( t_j - t_k )
|
||||
}
|
||||
\\
|
||||
& = &
|
||||
x_\ell
|
||||
\sum_{i \neq \ell}
|
||||
\frac{ 1 }{ t_\ell - t_i }
|
||||
+
|
||||
\sum_{j \neq \ell}
|
||||
x_j
|
||||
\frac{
|
||||
\prod_{k \neq \ell,j} ( t_\ell - t_k )
|
||||
}{
|
||||
\prod_{k \neq j} ( t_j - t_k )
|
||||
}
|
||||
\\
|
||||
& = &
|
||||
x_\ell
|
||||
\sum_{k \neq \ell} ( t_\ell - t_k )^{-1}
|
||||
+
|
||||
\sum_{j \neq \ell}
|
||||
x_j
|
||||
( t_j - t_\ell )^{-1}
|
||||
\prod_{k \neq \ell ,j} ( t_\ell - t_k ) / ( t_j - t_k )
|
||||
\end{array}
|
||||
\] $$
|
||||
We define the vector $latex \alpha \in \B{R}^{m+1}$$ by
|
||||
$latex \[
|
||||
\alpha_j = \left\{ \begin{array}{ll}
|
||||
\sum_{k \neq m} ( t_m - t_k )^{-1}
|
||||
& {\rm if} \; j = m
|
||||
\\
|
||||
( t_j - t_m )^{-1}
|
||||
\prod_{k \neq m,j} ( t_m - t_k ) / ( t_j - t_k )
|
||||
& {\rm otherwise}
|
||||
\end{array} \right.
|
||||
\] $$
|
||||
It follows that
|
||||
$latex \[
|
||||
p^\prime ( t_m ) = \alpha_0 x_0 + \cdots + \alpha_m x_m
|
||||
\] $$
|
||||
Gear's method determines $latex x_m$$ by solving the following
|
||||
nonlinear equation
|
||||
$latex \[
|
||||
f( t_m , x_m ) = \alpha_0 x_0 + \cdots + \alpha_m x_m
|
||||
\] $$
|
||||
Newton's method for solving this equation determines iterates,
|
||||
which we denote by $latex x_m^k$$, by solving the following affine
|
||||
approximation of the equation above
|
||||
$latex \[
|
||||
\begin{array}{rcl}
|
||||
f( t_m , x_m^{k-1} ) + \partial_x f( t_m , x_m^{k-1} ) ( x_m^k - x_m^{k-1} )
|
||||
& = &
|
||||
\alpha_0 x_0^k + \alpha_1 x_1 + \cdots + \alpha_m x_m
|
||||
\\
|
||||
\left[ \alpha_m I - \partial_x f( t_m , x_m^{k-1} ) \right] x_m
|
||||
& = &
|
||||
\left[
|
||||
f( t_m , x_m^{k-1} ) - \partial_x f( t_m , x_m^{k-1} ) x_m^{k-1}
|
||||
- \alpha_0 x_0 - \cdots - \alpha_{m-1} x_{m-1}
|
||||
\right]
|
||||
\end{array}
|
||||
\] $$
|
||||
In order to initialize Newton's method; i.e. choose $latex x_m^0$$
|
||||
we define the vector $latex \beta \in \B{R}^{m+1}$$ by
|
||||
$latex \[
|
||||
\beta_j = \left\{ \begin{array}{ll}
|
||||
\sum_{k \neq m-1} ( t_{m-1} - t_k )^{-1}
|
||||
& {\rm if} \; j = m-1
|
||||
\\
|
||||
( t_j - t_{m-1} )^{-1}
|
||||
\prod_{k \neq m-1,j} ( t_{m-1} - t_k ) / ( t_j - t_k )
|
||||
& {\rm otherwise}
|
||||
\end{array} \right.
|
||||
\] $$
|
||||
It follows that
|
||||
$latex \[
|
||||
p^\prime ( t_{m-1} ) = \beta_0 x_0 + \cdots + \beta_m x_m
|
||||
\] $$
|
||||
We solve the following approximation of the equation above to determine
|
||||
$latex x_m^0$$:
|
||||
$latex \[
|
||||
f( t_{m-1} , x_{m-1} ) =
|
||||
\beta_0 x_0 + \cdots + \beta_{m-1} x_{m-1} + \beta_m x_m^0
|
||||
\] $$
|
||||
|
||||
|
||||
$head Gear's Method$$
|
||||
C. W. Gear,
|
||||
``Simultaneous Numerical Solution of Differential-Algebraic Equations,''
|
||||
IEEE Transactions on Circuit Theory,
|
||||
vol. 18, no. 1, pp. 89-95, Jan. 1971.
|
||||
|
||||
|
||||
$end
|
||||
--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
# include <cstddef>
|
||||
# include <cppad/core/cppad_assert.hpp>
|
||||
# include <cppad/utility/check_simple_vector.hpp>
|
||||
# include <cppad/utility/check_numeric_type.hpp>
|
||||
# include <cppad/utility/vector.hpp>
|
||||
# include <cppad/utility/lu_factor.hpp>
|
||||
# include <cppad/utility/lu_invert.hpp>
|
||||
|
||||
namespace CppAD { // BEGIN CppAD namespace
|
||||
|
||||
template <typename Vector, typename Fun>
|
||||
void OdeGear(
|
||||
Fun &F ,
|
||||
size_t m ,
|
||||
size_t n ,
|
||||
const Vector &T ,
|
||||
Vector &X ,
|
||||
Vector &e )
|
||||
{
|
||||
// temporary indices
|
||||
size_t i, j, k;
|
||||
|
||||
typedef typename Vector::value_type Scalar;
|
||||
|
||||
// check numeric type specifications
|
||||
CheckNumericType<Scalar>();
|
||||
|
||||
// check simple vector class specifications
|
||||
CheckSimpleVector<Scalar, Vector>();
|
||||
|
||||
CPPAD_ASSERT_KNOWN(
|
||||
m >= 1,
|
||||
"OdeGear: m is less than one"
|
||||
);
|
||||
CPPAD_ASSERT_KNOWN(
|
||||
n > 0,
|
||||
"OdeGear: n is equal to zero"
|
||||
);
|
||||
CPPAD_ASSERT_KNOWN(
|
||||
size_t(T.size()) >= (m+1),
|
||||
"OdeGear: size of T is not greater than or equal (m+1)"
|
||||
);
|
||||
CPPAD_ASSERT_KNOWN(
|
||||
size_t(X.size()) >= (m+1) * n,
|
||||
"OdeGear: size of X is not greater than or equal (m+1) * n"
|
||||
);
|
||||
for(j = 0; j < m; j++) CPPAD_ASSERT_KNOWN(
|
||||
T[j] < T[j+1],
|
||||
"OdeGear: the array T is not monotone increasing"
|
||||
);
|
||||
|
||||
// some constants
|
||||
Scalar zero(0);
|
||||
Scalar one(1);
|
||||
|
||||
// vectors required by method
|
||||
Vector alpha(m + 1);
|
||||
Vector beta(m + 1);
|
||||
Vector f(n);
|
||||
Vector f_x(n * n);
|
||||
Vector x_m0(n);
|
||||
Vector x_m(n);
|
||||
Vector b(n);
|
||||
Vector A(n * n);
|
||||
|
||||
// compute alpha[m]
|
||||
alpha[m] = zero;
|
||||
for(k = 0; k < m; k++)
|
||||
alpha[m] += one / (T[m] - T[k]);
|
||||
|
||||
// compute beta[m-1]
|
||||
beta[m-1] = one / (T[m-1] - T[m]);
|
||||
for(k = 0; k < m-1; k++)
|
||||
beta[m-1] += one / (T[m-1] - T[k]);
|
||||
|
||||
|
||||
// compute other components of alpha
|
||||
for(j = 0; j < m; j++)
|
||||
{ // compute alpha[j]
|
||||
alpha[j] = one / (T[j] - T[m]);
|
||||
for(k = 0; k < m; k++)
|
||||
{ if( k != j )
|
||||
{ alpha[j] *= (T[m] - T[k]);
|
||||
alpha[j] /= (T[j] - T[k]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// compute other components of beta
|
||||
for(j = 0; j <= m; j++)
|
||||
{ if( j != m-1 )
|
||||
{ // compute beta[j]
|
||||
beta[j] = one / (T[j] - T[m-1]);
|
||||
for(k = 0; k <= m; k++)
|
||||
{ if( k != j && k != m-1 )
|
||||
{ beta[j] *= (T[m-1] - T[k]);
|
||||
beta[j] /= (T[j] - T[k]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// evaluate f(T[m-1], x_{m-1} )
|
||||
for(i = 0; i < n; i++)
|
||||
x_m[i] = X[(m-1) * n + i];
|
||||
F.Ode(T[m-1], x_m, f);
|
||||
|
||||
// solve for x_m^0
|
||||
for(i = 0; i < n; i++)
|
||||
{ x_m[i] = f[i];
|
||||
for(j = 0; j < m; j++)
|
||||
x_m[i] -= beta[j] * X[j * n + i];
|
||||
x_m[i] /= beta[m];
|
||||
}
|
||||
x_m0 = x_m;
|
||||
|
||||
// evaluate partial w.r.t x of f(T[m], x_m^0)
|
||||
F.Ode_dep(T[m], x_m, f_x);
|
||||
|
||||
// compute the matrix A = ( alpha[m] * I - f_x )
|
||||
for(i = 0; i < n; i++)
|
||||
{ for(j = 0; j < n; j++)
|
||||
A[i * n + j] = - f_x[i * n + j];
|
||||
A[i * n + i] += alpha[m];
|
||||
}
|
||||
|
||||
// LU factor (and overwrite) the matrix A
|
||||
CppAD::vector<size_t> ip(n) , jp(n);
|
||||
# ifndef NDEBUG
|
||||
int sign =
|
||||
# endif
|
||||
LuFactor(ip, jp, A);
|
||||
CPPAD_ASSERT_KNOWN(
|
||||
sign != 0,
|
||||
"OdeGear: step size is to large"
|
||||
);
|
||||
|
||||
// Iterations of Newton's method
|
||||
for(k = 0; k < 3; k++)
|
||||
{
|
||||
// only evaluate f( T[m] , x_m ) keep f_x during iteration
|
||||
F.Ode(T[m], x_m, f);
|
||||
|
||||
// b = f + f_x x_m - alpha[0] x_0 - ... - alpha[m-1] x_{m-1}
|
||||
for(i = 0; i < n; i++)
|
||||
{ b[i] = f[i];
|
||||
for(j = 0; j < n; j++)
|
||||
b[i] -= f_x[i * n + j] * x_m[j];
|
||||
for(j = 0; j < m; j++)
|
||||
b[i] -= alpha[j] * X[ j * n + i ];
|
||||
}
|
||||
LuInvert(ip, jp, A, b);
|
||||
x_m = b;
|
||||
}
|
||||
|
||||
// return estimate for x( t[k] ) and the estimated error bound
|
||||
for(i = 0; i < n; i++)
|
||||
{ X[m * n + i] = x_m[i];
|
||||
e[i] = x_m[i] - x_m0[i];
|
||||
if( e[i] < zero )
|
||||
e[i] = - e[i];
|
||||
}
|
||||
}
|
||||
|
||||
} // End CppAD namespace
|
||||
|
||||
# endif
|
||||
@@ -0,0 +1,542 @@
|
||||
# ifndef CPPAD_UTILITY_ODE_GEAR_CONTROL_HPP
|
||||
# define CPPAD_UTILITY_ODE_GEAR_CONTROL_HPP
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-17 Bradley M. Bell
|
||||
|
||||
CppAD is distributed under multiple licenses. This distribution is under
|
||||
the terms of the
|
||||
Eclipse Public License Version 1.0.
|
||||
|
||||
A copy of this license is included in the COPYING file of this distribution.
|
||||
Please visit http://www.coin-or.org/CppAD/ for information on other licenses.
|
||||
-------------------------------------------------------------------------- */
|
||||
|
||||
/*
|
||||
$begin OdeGearControl$$
|
||||
$spell
|
||||
cppad.hpp
|
||||
CppAD
|
||||
xf
|
||||
xi
|
||||
smin
|
||||
smax
|
||||
eabs
|
||||
ef
|
||||
maxabs
|
||||
nstep
|
||||
tf
|
||||
sini
|
||||
erel
|
||||
dep
|
||||
const
|
||||
tb
|
||||
ta
|
||||
exp
|
||||
$$
|
||||
|
||||
|
||||
|
||||
$section An Error Controller for Gear's Ode Solvers$$
|
||||
$mindex OdeGearControl Gear differential equation$$
|
||||
|
||||
$head Syntax$$
|
||||
$codei%# include <cppad/utility/ode_gear_control.hpp>
|
||||
%$$
|
||||
$icode%xf% = OdeGearControl(%F%, %M%, %ti%, %tf%, %xi%,
|
||||
%smin%, %smax%, %sini%, %eabs%, %erel%, %ef% , %maxabs%, %nstep% )%$$
|
||||
|
||||
|
||||
$head Purpose$$
|
||||
Let $latex \B{R}$$ denote the real numbers
|
||||
and let $latex f : \B{R} \times \B{R}^n \rightarrow \B{R}^n$$ be a smooth function.
|
||||
We define $latex X : [ti , tf] \rightarrow \B{R}^n$$ by
|
||||
the following initial value problem:
|
||||
$latex \[
|
||||
\begin{array}{rcl}
|
||||
X(ti) & = & xi \\
|
||||
X'(t) & = & f[t , X(t)]
|
||||
\end{array}
|
||||
\] $$
|
||||
The routine $cref OdeGear$$ is a stiff multi-step method that
|
||||
can be used to approximate the solution to this equation.
|
||||
The routine $code OdeGearControl$$ sets up this multi-step method
|
||||
and controls the error during such an approximation.
|
||||
|
||||
$head Include$$
|
||||
The file $code cppad/ode_gear_control.hpp$$
|
||||
is included by $code cppad/cppad.hpp$$
|
||||
but it can also be included separately with out the rest of
|
||||
the $code CppAD$$ routines.
|
||||
|
||||
$head Notation$$
|
||||
The template parameter types $cref/Scalar/OdeGearControl/Scalar/$$ and
|
||||
$cref/Vector/OdeGearControl/Vector/$$ are documented below.
|
||||
|
||||
$head xf$$
|
||||
The return value $icode xf$$ has the prototype
|
||||
$codei%
|
||||
%Vector% %xf%
|
||||
%$$
|
||||
and the size of $icode xf$$ is equal to $icode n$$
|
||||
(see description of $cref/Vector/OdeGear/Vector/$$ below).
|
||||
It is the approximation for $latex X(tf)$$.
|
||||
|
||||
$head Fun$$
|
||||
The class $icode Fun$$
|
||||
and the object $icode F$$ satisfy the prototype
|
||||
$codei%
|
||||
%Fun% &%F%
|
||||
%$$
|
||||
This must support the following set of calls
|
||||
$codei%
|
||||
%F%.Ode(%t%, %x%, %f%)
|
||||
%F%.Ode_dep(%t%, %x%, %f_x%)
|
||||
%$$
|
||||
|
||||
$subhead t$$
|
||||
The argument $icode t$$ has prototype
|
||||
$codei%
|
||||
const %Scalar% &%t%
|
||||
%$$
|
||||
(see description of $cref/Scalar/OdeGear/Scalar/$$ below).
|
||||
|
||||
$subhead x$$
|
||||
The argument $icode x$$ has prototype
|
||||
$codei%
|
||||
const %Vector% &%x%
|
||||
%$$
|
||||
and has size $icode N$$
|
||||
(see description of $cref/Vector/OdeGear/Vector/$$ below).
|
||||
|
||||
$subhead f$$
|
||||
The argument $icode f$$ to $icode%F%.Ode%$$ has prototype
|
||||
$codei%
|
||||
%Vector% &%f%
|
||||
%$$
|
||||
On input and output, $icode f$$ is a vector of size $icode N$$
|
||||
and the input values of the elements of $icode f$$ do not matter.
|
||||
On output,
|
||||
$icode f$$ is set equal to $latex f(t, x)$$
|
||||
(see $icode f(t, x)$$ in $cref/Purpose/OdeGear/Purpose/$$).
|
||||
|
||||
$subhead f_x$$
|
||||
The argument $icode f_x$$ has prototype
|
||||
$codei%
|
||||
%Vector% &%f_x%
|
||||
%$$
|
||||
On input and output, $icode f_x$$ is a vector of size $latex N * N$$
|
||||
and the input values of the elements of $icode f_x$$ do not matter.
|
||||
On output,
|
||||
$latex \[
|
||||
f\_x [i * n + j] = \partial_{x(j)} f_i ( t , x )
|
||||
\] $$
|
||||
|
||||
$subhead Warning$$
|
||||
The arguments $icode f$$, and $icode f_x$$
|
||||
must have a call by reference in their prototypes; i.e.,
|
||||
do not forget the $code &$$ in the prototype for
|
||||
$icode f$$ and $icode f_x$$.
|
||||
|
||||
$head M$$
|
||||
The argument $icode M$$ has prototype
|
||||
$codei%
|
||||
size_t %M%
|
||||
%$$
|
||||
It specifies the order of the multi-step method; i.e.,
|
||||
the order of the approximating polynomial
|
||||
(after the initialization process).
|
||||
The argument $icode M$$ must greater than or equal one.
|
||||
|
||||
$head ti$$
|
||||
The argument $icode ti$$ has prototype
|
||||
$codei%
|
||||
const %Scalar% &%ti%
|
||||
%$$
|
||||
It specifies the initial time for the integration of
|
||||
the differential equation.
|
||||
|
||||
$head tf$$
|
||||
The argument $icode tf$$ has prototype
|
||||
$codei%
|
||||
const %Scalar% &%tf%
|
||||
%$$
|
||||
It specifies the final time for the integration of
|
||||
the differential equation.
|
||||
|
||||
$head xi$$
|
||||
The argument $icode xi$$ has prototype
|
||||
$codei%
|
||||
const %Vector% &%xi%
|
||||
%$$
|
||||
and size $icode n$$.
|
||||
It specifies value of $latex X(ti)$$.
|
||||
|
||||
$head smin$$
|
||||
The argument $icode smin$$ has prototype
|
||||
$codei%
|
||||
const %Scalar% &%smin%
|
||||
%$$
|
||||
The minimum value of $latex T[M] - T[M-1]$$ in a call to $code OdeGear$$
|
||||
will be $latex smin$$ except for the last two calls where it may be
|
||||
as small as $latex smin / 2$$.
|
||||
The value of $icode smin$$ must be less than or equal $icode smax$$.
|
||||
|
||||
$head smax$$
|
||||
The argument $icode smax$$ has prototype
|
||||
$codei%
|
||||
const %Scalar% &%smax%
|
||||
%$$
|
||||
It specifies the maximum step size to use during the integration;
|
||||
i.e., the maximum value for $latex T[M] - T[M-1]$$
|
||||
in a call to $code OdeGear$$.
|
||||
|
||||
$head sini$$
|
||||
The argument $icode sini$$ has prototype
|
||||
$codei%
|
||||
%Scalar% &%sini%
|
||||
%$$
|
||||
The value of $icode sini$$ is the minimum
|
||||
step size to use during initialization of the multi-step method; i.e.,
|
||||
for calls to $code OdeGear$$ where $latex m < M$$.
|
||||
The value of $icode sini$$ must be less than or equal $icode smax$$
|
||||
(and can also be less than $icode smin$$).
|
||||
|
||||
$head eabs$$
|
||||
The argument $icode eabs$$ has prototype
|
||||
$codei%
|
||||
const %Vector% &%eabs%
|
||||
%$$
|
||||
and size $icode n$$.
|
||||
Each of the elements of $icode eabs$$ must be
|
||||
greater than or equal zero.
|
||||
It specifies a bound for the absolute
|
||||
error in the return value $icode xf$$ as an approximation for $latex X(tf)$$.
|
||||
(see the
|
||||
$cref/error criteria discussion/OdeGearControl/Error Criteria Discussion/$$
|
||||
below).
|
||||
|
||||
$head erel$$
|
||||
The argument $icode erel$$ has prototype
|
||||
$codei%
|
||||
const %Scalar% &%erel%
|
||||
%$$
|
||||
and is greater than or equal zero.
|
||||
It specifies a bound for the relative
|
||||
error in the return value $icode xf$$ as an approximation for $latex X(tf)$$
|
||||
(see the
|
||||
$cref/error criteria discussion/OdeGearControl/Error Criteria Discussion/$$
|
||||
below).
|
||||
|
||||
$head ef$$
|
||||
The argument value $icode ef$$ has prototype
|
||||
$codei%
|
||||
%Vector% &%ef%
|
||||
%$$
|
||||
and size $icode n$$.
|
||||
The input value of its elements does not matter.
|
||||
On output,
|
||||
it contains an estimated bound for the
|
||||
absolute error in the approximation $icode xf$$; i.e.,
|
||||
$latex \[
|
||||
ef_i > | X( tf )_i - xf_i |
|
||||
\] $$
|
||||
|
||||
$head maxabs$$
|
||||
The argument $icode maxabs$$ is optional in the call to $code OdeGearControl$$.
|
||||
If it is present, it has the prototype
|
||||
$codei%
|
||||
%Vector% &%maxabs%
|
||||
%$$
|
||||
and size $icode n$$.
|
||||
The input value of its elements does not matter.
|
||||
On output,
|
||||
it contains an estimate for the
|
||||
maximum absolute value of $latex X(t)$$; i.e.,
|
||||
$latex \[
|
||||
maxabs[i] \approx \max \left\{
|
||||
| X( t )_i | \; : \; t \in [ti, tf]
|
||||
\right\}
|
||||
\] $$
|
||||
|
||||
$head nstep$$
|
||||
The argument $icode nstep$$ has the prototype
|
||||
$codei%
|
||||
%size_t% &%nstep%
|
||||
%$$
|
||||
Its input value does not matter and its output value
|
||||
is the number of calls to $cref OdeGear$$
|
||||
used by $code OdeGearControl$$.
|
||||
|
||||
$head Error Criteria Discussion$$
|
||||
The relative error criteria $icode erel$$ and
|
||||
absolute error criteria $icode eabs$$ are enforced during each step of the
|
||||
integration of the ordinary differential equations.
|
||||
In addition, they are inversely scaled by the step size so that
|
||||
the total error bound is less than the sum of the error bounds.
|
||||
To be specific, if $latex \tilde{X} (t)$$ is the approximate solution
|
||||
at time $latex t$$,
|
||||
$icode ta$$ is the initial step time,
|
||||
and $icode tb$$ is the final step time,
|
||||
$latex \[
|
||||
\left| \tilde{X} (tb)_j - X (tb)_j \right|
|
||||
\leq
|
||||
\frac{tf - ti}{tb - ta}
|
||||
\left[ eabs[j] + erel \; | \tilde{X} (tb)_j | \right]
|
||||
\] $$
|
||||
If $latex X(tb)_j$$ is near zero for some $latex tb \in [ti , tf]$$,
|
||||
and one uses an absolute error criteria $latex eabs[j]$$ of zero,
|
||||
the error criteria above will force $code OdeGearControl$$
|
||||
to use step sizes equal to
|
||||
$cref/smin/OdeGearControl/smin/$$
|
||||
for steps ending near $latex tb$$.
|
||||
In this case, the error relative to $icode maxabs$$ can be judged after
|
||||
$code OdeGearControl$$ returns.
|
||||
If $icode ef$$ is to large relative to $icode maxabs$$,
|
||||
$code OdeGearControl$$ can be called again
|
||||
with a smaller value of $icode smin$$.
|
||||
|
||||
$head Scalar$$
|
||||
The type $icode Scalar$$ must satisfy the conditions
|
||||
for a $cref NumericType$$ type.
|
||||
The routine $cref CheckNumericType$$ will generate an error message
|
||||
if this is not the case.
|
||||
In addition, the following operations must be defined for
|
||||
$icode Scalar$$ objects $icode a$$ and $icode b$$:
|
||||
|
||||
$table
|
||||
$bold Operation$$ $cnext $bold Description$$ $rnext
|
||||
$icode%a% <= %b%$$ $cnext
|
||||
returns true (false) if $icode a$$ is less than or equal
|
||||
(greater than) $icode b$$.
|
||||
$rnext
|
||||
$icode%a% == %b%$$ $cnext
|
||||
returns true (false) if $icode a$$ is equal to $icode b$$.
|
||||
$rnext
|
||||
$codei%log(%a%)%$$ $cnext
|
||||
returns a $icode Scalar$$ equal to the logarithm of $icode a$$
|
||||
$rnext
|
||||
$codei%exp(%a%)%$$ $cnext
|
||||
returns a $icode Scalar$$ equal to the exponential of $icode a$$
|
||||
$tend
|
||||
|
||||
|
||||
$head Vector$$
|
||||
The type $icode Vector$$ must be a $cref SimpleVector$$ class with
|
||||
$cref/elements of type Scalar/SimpleVector/Elements of Specified Type/$$.
|
||||
The routine $cref CheckSimpleVector$$ will generate an error message
|
||||
if this is not the case.
|
||||
|
||||
$head Example$$
|
||||
$children%
|
||||
example/utility/ode_gear_control.cpp
|
||||
%$$
|
||||
The file
|
||||
$cref ode_gear_control.cpp$$
|
||||
contains an example and test a test of using this routine.
|
||||
It returns true if it succeeds and false otherwise.
|
||||
|
||||
$head Theory$$
|
||||
Let $latex e(s)$$ be the error as a function of the
|
||||
step size $latex s$$ and suppose that there is a constant
|
||||
$latex K$$ such that $latex e(s) = K s^m$$.
|
||||
Let $latex a$$ be our error bound.
|
||||
Given the value of $latex e(s)$$, a step of size $latex \lambda s$$
|
||||
would be ok provided that
|
||||
$latex \[
|
||||
\begin{array}{rcl}
|
||||
a & \geq & e( \lambda s ) (tf - ti) / ( \lambda s ) \\
|
||||
a & \geq & K \lambda^m s^m (tf - ti) / ( \lambda s ) \\
|
||||
a & \geq & \lambda^{m-1} s^{m-1} (tf - ti) e(s) / s^m \\
|
||||
a & \geq & \lambda^{m-1} (tf - ti) e(s) / s \\
|
||||
\lambda^{m-1} & \leq & \frac{a}{e(s)} \frac{s}{tf - ti}
|
||||
\end{array}
|
||||
\] $$
|
||||
Thus if the right hand side of the last inequality is greater
|
||||
than or equal to one, the step of size $latex s$$ is ok.
|
||||
|
||||
$head Source Code$$
|
||||
The source code for this routine is in the file
|
||||
$code cppad/ode_gear_control.hpp$$.
|
||||
|
||||
$end
|
||||
--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
// link exp and log for float and double
|
||||
# include <cppad/base_require.hpp>
|
||||
|
||||
# include <cppad/utility/ode_gear.hpp>
|
||||
|
||||
namespace CppAD { // Begin CppAD namespace
|
||||
|
||||
template <class Scalar, class Vector, class Fun>
|
||||
Vector OdeGearControl(
|
||||
Fun &F ,
|
||||
size_t M ,
|
||||
const Scalar &ti ,
|
||||
const Scalar &tf ,
|
||||
const Vector &xi ,
|
||||
const Scalar &smin ,
|
||||
const Scalar &smax ,
|
||||
Scalar &sini ,
|
||||
const Vector &eabs ,
|
||||
const Scalar &erel ,
|
||||
Vector &ef ,
|
||||
Vector &maxabs,
|
||||
size_t &nstep )
|
||||
{
|
||||
// check simple vector class specifications
|
||||
CheckSimpleVector<Scalar, Vector>();
|
||||
|
||||
// dimension of the state space
|
||||
size_t n = size_t(xi.size());
|
||||
|
||||
CPPAD_ASSERT_KNOWN(
|
||||
M >= 1,
|
||||
"Error in OdeGearControl: M is less than one"
|
||||
);
|
||||
CPPAD_ASSERT_KNOWN(
|
||||
smin <= smax,
|
||||
"Error in OdeGearControl: smin is greater than smax"
|
||||
);
|
||||
CPPAD_ASSERT_KNOWN(
|
||||
sini <= smax,
|
||||
"Error in OdeGearControl: sini is greater than smax"
|
||||
);
|
||||
CPPAD_ASSERT_KNOWN(
|
||||
size_t(eabs.size()) == n,
|
||||
"Error in OdeGearControl: size of eabs is not equal to n"
|
||||
);
|
||||
CPPAD_ASSERT_KNOWN(
|
||||
size_t(maxabs.size()) == n,
|
||||
"Error in OdeGearControl: size of maxabs is not equal to n"
|
||||
);
|
||||
|
||||
// some constants
|
||||
const Scalar zero(0);
|
||||
const Scalar one(1);
|
||||
const Scalar one_plus( Scalar(3) / Scalar(2) );
|
||||
const Scalar two(2);
|
||||
const Scalar ten(10);
|
||||
|
||||
// temporary indices
|
||||
size_t i, k;
|
||||
|
||||
// temporary Scalars
|
||||
Scalar step, sprevious, lambda, axi, a, root, r;
|
||||
|
||||
// vectors of Scalars
|
||||
Vector T (M + 1);
|
||||
Vector X( (M + 1) * n );
|
||||
Vector e(n);
|
||||
Vector xf(n);
|
||||
|
||||
// initial integer values
|
||||
size_t m = 1;
|
||||
nstep = 0;
|
||||
|
||||
// initialize T
|
||||
T[0] = ti;
|
||||
|
||||
// initialize X, ef, maxabs
|
||||
for(i = 0; i < n; i++)
|
||||
for(i = 0; i < n; i++)
|
||||
{ X[i] = xi[i];
|
||||
ef[i] = zero;
|
||||
X[i] = xi[i];
|
||||
if( zero <= xi[i] )
|
||||
maxabs[i] = xi[i];
|
||||
else maxabs[i] = - xi[i];
|
||||
|
||||
}
|
||||
|
||||
// initial step size
|
||||
step = smin;
|
||||
|
||||
while( T[m-1] < tf )
|
||||
{ sprevious = step;
|
||||
|
||||
// check maximum
|
||||
if( smax <= step )
|
||||
step = smax;
|
||||
|
||||
// check minimum
|
||||
if( m < M )
|
||||
{ if( step <= sini )
|
||||
step = sini;
|
||||
}
|
||||
else if( step <= smin )
|
||||
step = smin;
|
||||
|
||||
// check if near the end
|
||||
if( tf <= T[m-1] + one_plus * step )
|
||||
T[m] = tf;
|
||||
else T[m] = T[m-1] + step;
|
||||
|
||||
// try using this step size
|
||||
nstep++;
|
||||
OdeGear(F, m, n, T, X, e);
|
||||
step = T[m] - T[m-1];
|
||||
|
||||
// compute value of lambda for this step
|
||||
lambda = Scalar(10) * sprevious / step;
|
||||
for(i = 0; i < n; i++)
|
||||
{ axi = X[m * n + i];
|
||||
if( axi <= zero )
|
||||
axi = - axi;
|
||||
a = eabs[i] + erel * axi;
|
||||
if( e[i] > zero )
|
||||
{ if( m == 1 )
|
||||
root = (a / e[i]) / ten;
|
||||
else
|
||||
{ r = ( a / e[i] ) * step / (tf - ti);
|
||||
root = exp( log(r) / Scalar(m-1) );
|
||||
}
|
||||
if( root <= lambda )
|
||||
lambda = root;
|
||||
}
|
||||
}
|
||||
|
||||
bool advance;
|
||||
if( m == M )
|
||||
advance = one <= lambda || step <= one_plus * smin;
|
||||
else advance = one <= lambda || step <= one_plus * sini;
|
||||
|
||||
|
||||
if( advance )
|
||||
{ // accept the results of this time step
|
||||
CPPAD_ASSERT_UNKNOWN( m <= M );
|
||||
if( m == M )
|
||||
{ // shift for next step
|
||||
for(k = 0; k < m; k++)
|
||||
{ T[k] = T[k+1];
|
||||
for(i = 0; i < n; i++)
|
||||
X[k*n + i] = X[(k+1)*n + i];
|
||||
}
|
||||
}
|
||||
// update ef and maxabs
|
||||
for(i = 0; i < n; i++)
|
||||
{ ef[i] = ef[i] + e[i];
|
||||
axi = X[m * n + i];
|
||||
if( axi <= zero )
|
||||
axi = - axi;
|
||||
if( axi > maxabs[i] )
|
||||
maxabs[i] = axi;
|
||||
}
|
||||
if( m != M )
|
||||
m++; // all we need do in this case
|
||||
}
|
||||
|
||||
// new step suggested by error criteria
|
||||
step = std::min(lambda , ten) * step / two;
|
||||
}
|
||||
for(i = 0; i < n; i++)
|
||||
xf[i] = X[(m-1) * n + i];
|
||||
|
||||
return xf;
|
||||
}
|
||||
|
||||
} // End CppAD namespace
|
||||
|
||||
# endif
|
||||
+783
@@ -0,0 +1,783 @@
|
||||
// $Id: omp_alloc.hpp 3804 2016-03-20 15:08:46Z bradbell $
|
||||
# ifndef CPPAD_UTILITY_OMP_ALLOC_HPP
|
||||
# define CPPAD_UTILITY_OMP_ALLOC_HPP
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-16 Bradley M. Bell
|
||||
|
||||
CppAD is distributed under multiple licenses. This distribution is under
|
||||
the terms of the
|
||||
Eclipse Public License Version 1.0.
|
||||
|
||||
A copy of this license is included in the COPYING file of this distribution.
|
||||
Please visit http://www.coin-or.org/CppAD/ for information on other licenses.
|
||||
-------------------------------------------------------------------------- */
|
||||
# include <cppad/utility/thread_alloc.hpp>
|
||||
# ifdef _OPENMP
|
||||
# include <omp.h>
|
||||
# endif
|
||||
|
||||
namespace CppAD { // BEGIN_CPPAD_NAMESPACE
|
||||
class omp_alloc{
|
||||
// ============================================================================
|
||||
public:
|
||||
/*
|
||||
$begin omp_max_num_threads$$
|
||||
$spell
|
||||
cppad.hpp
|
||||
inv
|
||||
CppAD
|
||||
num
|
||||
omp_alloc
|
||||
$$
|
||||
$section Set and Get Maximum Number of Threads for omp_alloc Allocator$$
|
||||
|
||||
$head Deprecated 2011-08-31$$
|
||||
Use the functions $cref/thread_alloc::parallel_setup/ta_parallel_setup/$$
|
||||
and $cref/thread_alloc:num_threads/ta_num_threads/$$ instead.
|
||||
|
||||
$head Syntax$$
|
||||
$codei%# include <cppad/utility/omp_alloc.hpp>
|
||||
%$$
|
||||
$codei%omp_alloc::set_max_num_threads(%number%)
|
||||
%$$
|
||||
$icode%number% = omp_alloc::get_max_num_threads()
|
||||
%$$
|
||||
|
||||
$head Purpose$$
|
||||
By default there is only one thread and all execution is in sequential mode
|
||||
(not $cref/parallel/omp_in_parallel/$$).
|
||||
|
||||
$head number$$
|
||||
The argument and return value $icode number$$ has prototype
|
||||
$codei%
|
||||
size_t %number%
|
||||
%$$
|
||||
and must be greater than zero.
|
||||
|
||||
$head set_max_num_threads$$
|
||||
Informs $cref omp_alloc$$ of the maximum number of OpenMP threads.
|
||||
|
||||
$head get_max_num_threads$$
|
||||
Returns the valued used in the previous call to $code set_max_num_threads$$.
|
||||
If there was no such previous call, the value one is returned
|
||||
(and only thread number zero can use $cref omp_alloc$$).
|
||||
|
||||
$head Restrictions$$
|
||||
The function $code set_max_num_threads$$ must be called before
|
||||
the program enters $cref/parallel/omp_in_parallel/$$ execution mode.
|
||||
In addition, this function cannot be called while in parallel mode.
|
||||
|
||||
$end
|
||||
*/
|
||||
/*!
|
||||
Inform omp_alloc of the maximum number of OpenMP threads and enable
|
||||
parallel execution mode by initializing all statics in this file.
|
||||
|
||||
\param number [in]
|
||||
maximum number of OpenMP threads.
|
||||
*/
|
||||
static void set_max_num_threads(size_t number)
|
||||
{ thread_alloc::parallel_setup(
|
||||
number, omp_alloc::in_parallel, omp_alloc::get_thread_num
|
||||
);
|
||||
thread_alloc::hold_memory(number > 1);
|
||||
}
|
||||
/*!
|
||||
Get the current maximum number of OpenMP threads that omp_alloc can use.
|
||||
|
||||
\return
|
||||
maximum number of OpenMP threads.
|
||||
*/
|
||||
static size_t get_max_num_threads(void)
|
||||
{ return thread_alloc::num_threads(); }
|
||||
|
||||
/* -----------------------------------------------------------------------
|
||||
$begin omp_in_parallel$$
|
||||
|
||||
$section Is The Current Execution in OpenMP Parallel Mode$$
|
||||
$mindex in_parallel$$
|
||||
$spell
|
||||
cppad.hpp
|
||||
omp_alloc
|
||||
bool
|
||||
$$
|
||||
|
||||
$head Deprecated 2011-08-31$$
|
||||
Use the function $cref/thread_alloc::in_parallel/ta_in_parallel/$$ instead.
|
||||
|
||||
$head Syntax$$
|
||||
$codei%# include <cppad/utility/omp_alloc.hpp>
|
||||
%$$
|
||||
$icode%flag% = omp_alloc::in_parallel()%$$
|
||||
|
||||
$head Purpose$$
|
||||
Some of the $cref omp_alloc$$ allocation routines have different
|
||||
specifications for parallel (not sequential) execution mode.
|
||||
This routine enables you to determine if the current execution mode
|
||||
is sequential or parallel.
|
||||
|
||||
$head flag$$
|
||||
The return value has prototype
|
||||
$codei%
|
||||
bool %flag%
|
||||
%$$
|
||||
It is true if the current execution is in parallel mode
|
||||
(possibly multi-threaded) and false otherwise (sequential mode).
|
||||
|
||||
$head Example$$
|
||||
$cref omp_alloc.cpp$$
|
||||
|
||||
$end
|
||||
*/
|
||||
/// Are we in a parallel execution state; i.e., is it possible that
|
||||
/// other threads are currently executing.
|
||||
static bool in_parallel(void)
|
||||
{
|
||||
# ifdef _OPENMP
|
||||
return omp_in_parallel() != 0;
|
||||
# else
|
||||
return false;
|
||||
# endif
|
||||
}
|
||||
|
||||
/* -----------------------------------------------------------------------
|
||||
$begin omp_get_thread_num$$
|
||||
$spell
|
||||
cppad.hpp
|
||||
CppAD
|
||||
num
|
||||
omp_alloc
|
||||
cppad.hpp
|
||||
$$
|
||||
|
||||
$section Get the Current OpenMP Thread Number$$
|
||||
$mindex get_thread_num$$
|
||||
|
||||
$head Deprecated 2011-08-31$$
|
||||
Use the function $cref/thread_alloc::thread_num/ta_thread_num/$$ instead.
|
||||
|
||||
$head Syntax$$
|
||||
$codei%# include <cppad/utility/omp_alloc.hpp>
|
||||
%$$
|
||||
$icode%thread% = omp_alloc::get_thread_num()%$$
|
||||
|
||||
$head Purpose$$
|
||||
Some of the $cref omp_alloc$$ allocation routines have a thread number.
|
||||
This routine enables you to determine the current thread.
|
||||
|
||||
$head thread$$
|
||||
The return value $icode thread$$ has prototype
|
||||
$codei%
|
||||
size_t %thread%
|
||||
%$$
|
||||
and is the currently executing thread number.
|
||||
If $code _OPENMP$$ is not defined, $icode thread$$ is zero.
|
||||
|
||||
$head Example$$
|
||||
$cref omp_alloc.cpp$$
|
||||
|
||||
$end
|
||||
*/
|
||||
/// Get current OpenMP thread number (zero if _OpenMP not defined).
|
||||
static size_t get_thread_num(void)
|
||||
{
|
||||
# ifdef _OPENMP
|
||||
size_t thread = static_cast<size_t>( omp_get_thread_num() );
|
||||
return thread;
|
||||
# else
|
||||
return 0;
|
||||
# endif
|
||||
}
|
||||
/* -----------------------------------------------------------------------
|
||||
$begin omp_get_memory$$
|
||||
$spell
|
||||
cppad.hpp
|
||||
num
|
||||
ptr
|
||||
omp_alloc
|
||||
$$
|
||||
|
||||
$section Get At Least A Specified Amount of Memory$$
|
||||
|
||||
$head Deprecated 2011-08-31$$
|
||||
Use the function $cref/thread_alloc::get_memory/ta_get_memory/$$ instead.
|
||||
|
||||
$head Syntax$$
|
||||
$codei%# include <cppad/utility/omp_alloc.hpp>
|
||||
%$$
|
||||
$icode%v_ptr% = omp_alloc::get_memory(%min_bytes%, %cap_bytes%)%$$
|
||||
|
||||
$head Purpose$$
|
||||
Use $cref omp_alloc$$ to obtain a minimum number of bytes of memory
|
||||
(for use by the $cref/current thread/omp_get_thread_num/$$).
|
||||
|
||||
$head min_bytes$$
|
||||
This argument has prototype
|
||||
$codei%
|
||||
size_t %min_bytes%
|
||||
%$$
|
||||
It specifies the minimum number of bytes to allocate.
|
||||
|
||||
$head cap_bytes$$
|
||||
This argument has prototype
|
||||
$codei%
|
||||
size_t& %cap_bytes%
|
||||
%$$
|
||||
It's input value does not matter.
|
||||
Upon return, it is the actual number of bytes (capacity)
|
||||
that have been allocated for use,
|
||||
$codei%
|
||||
%min_bytes% <= %cap_bytes%
|
||||
%$$
|
||||
|
||||
$head v_ptr$$
|
||||
The return value $icode v_ptr$$ has prototype
|
||||
$codei%
|
||||
void* %v_ptr%
|
||||
%$$
|
||||
It is the location where the $icode cap_bytes$$ of memory
|
||||
that have been allocated for use begins.
|
||||
|
||||
$head Allocation Speed$$
|
||||
This allocation should be faster if the following conditions hold:
|
||||
$list number$$
|
||||
The memory allocated by a previous call to $code get_memory$$
|
||||
is currently available for use.
|
||||
$lnext
|
||||
The current $icode min_bytes$$ is between
|
||||
the previous $icode min_bytes$$ and previous $icode cap_bytes$$.
|
||||
$lend
|
||||
|
||||
$head Example$$
|
||||
$cref omp_alloc.cpp$$
|
||||
|
||||
$end
|
||||
*/
|
||||
/*!
|
||||
Use omp_alloc to get a specified amount of memory.
|
||||
|
||||
If the memory allocated by a previous call to \c get_memory is now
|
||||
avaialable, and \c min_bytes is between its previous value
|
||||
and the previous \c cap_bytes, this memory allocation will have
|
||||
optimal speed. Otherwise, the memory allocation is more complicated and
|
||||
may have to wait for other threads to complete an allocation.
|
||||
|
||||
\param min_bytes [in]
|
||||
The minimum number of bytes of memory to be obtained for use.
|
||||
|
||||
\param cap_bytes [out]
|
||||
The actual number of bytes of memory obtained for use.
|
||||
|
||||
\return
|
||||
pointer to the beginning of the memory allocted for use.
|
||||
*/
|
||||
static void* get_memory(size_t min_bytes, size_t& cap_bytes)
|
||||
{ return thread_alloc::get_memory(min_bytes, cap_bytes); }
|
||||
|
||||
/* -----------------------------------------------------------------------
|
||||
$begin omp_return_memory$$
|
||||
$spell
|
||||
cppad.hpp
|
||||
ptr
|
||||
omp_alloc
|
||||
$$
|
||||
|
||||
$section Return Memory to omp_alloc$$
|
||||
$mindex return_memory$$
|
||||
|
||||
$head Deprecated 2011-08-31$$
|
||||
Use the function $cref/thread_alloc::return_memory/ta_return_memory/$$ instead.
|
||||
|
||||
$head Syntax$$
|
||||
$codei%# include <cppad/utility/omp_alloc.hpp>
|
||||
%$$
|
||||
$codei%omp_alloc::return_memory(%v_ptr%)%$$
|
||||
|
||||
$head Purpose$$
|
||||
If $cref omp_max_num_threads$$ is one,
|
||||
the memory is returned to the system.
|
||||
Otherwise, the memory is retained by $cref omp_alloc$$ for quick future use
|
||||
by the thread that allocated to memory.
|
||||
|
||||
$head v_ptr$$
|
||||
This argument has prototype
|
||||
$codei%
|
||||
void* %v_ptr%
|
||||
%$$.
|
||||
It must be a pointer to memory that is currently in use; i.e.
|
||||
obtained by a previous call to $cref omp_get_memory$$ and not yet returned.
|
||||
|
||||
$head Thread$$
|
||||
Either the $cref/current thread/omp_get_thread_num/$$ must be the same as during
|
||||
the corresponding call to $cref omp_get_memory$$,
|
||||
or the current execution mode must be sequential
|
||||
(not $cref/parallel/omp_in_parallel/$$).
|
||||
|
||||
$head NDEBUG$$
|
||||
If $code NDEBUG$$ is defined, $icode v_ptr$$ is not checked (this is faster).
|
||||
Otherwise, a list of in use pointers is searched to make sure
|
||||
that $icode v_ptr$$ is in the list.
|
||||
|
||||
$head Example$$
|
||||
$cref omp_alloc.cpp$$
|
||||
|
||||
$end
|
||||
*/
|
||||
/*!
|
||||
Return memory that was obtained by \c get_memory.
|
||||
If <code>max_num_threads(0) == 1</code>,
|
||||
the memory is returned to the system.
|
||||
Otherwise, it is retained by \c omp_alloc and available for use by
|
||||
\c get_memory for this thread.
|
||||
|
||||
\param v_ptr [in]
|
||||
Value of the pointer returned by \c get_memory and still in use.
|
||||
After this call, this pointer will available (and not in use).
|
||||
|
||||
\par
|
||||
We must either be in sequential (not parallel) execution mode,
|
||||
or the current thread must be the same as for the corresponding call
|
||||
to \c get_memory.
|
||||
*/
|
||||
static void return_memory(void* v_ptr)
|
||||
{ thread_alloc::return_memory(v_ptr); }
|
||||
/* -----------------------------------------------------------------------
|
||||
$begin omp_free_available$$
|
||||
$spell
|
||||
cppad.hpp
|
||||
omp_alloc
|
||||
$$
|
||||
|
||||
$section Free Memory Currently Available for Quick Use by a Thread$$
|
||||
$mindex free_available$$
|
||||
|
||||
$head Deprecated 2011-08-31$$
|
||||
Use the function $cref/thread_alloc::free_available/ta_free_available/$$
|
||||
instead.
|
||||
|
||||
$head Syntax$$
|
||||
$codei%# include <cppad/utility/omp_alloc.hpp>
|
||||
%$$
|
||||
$codei%omp_alloc::free_available(%thread%)%$$
|
||||
|
||||
$head Purpose$$
|
||||
Free memory, currently available for quick use by a specific thread,
|
||||
for general future use.
|
||||
|
||||
$head thread$$
|
||||
This argument has prototype
|
||||
$codei%
|
||||
size_t %thread%
|
||||
%$$
|
||||
Either $cref omp_get_thread_num$$ must be the same as $icode thread$$,
|
||||
or the current execution mode must be sequential
|
||||
(not $cref/parallel/omp_in_parallel/$$).
|
||||
|
||||
$head Example$$
|
||||
$cref omp_alloc.cpp$$
|
||||
|
||||
$end
|
||||
*/
|
||||
/*!
|
||||
Return all the memory being held as available for a thread to the system.
|
||||
|
||||
\param thread [in]
|
||||
this thread that will no longer have any available memory after this call.
|
||||
This must either be the thread currently executing, or we must be
|
||||
in sequential (not parallel) execution mode.
|
||||
*/
|
||||
static void free_available(size_t thread)
|
||||
{ thread_alloc::free_available(thread); }
|
||||
/* -----------------------------------------------------------------------
|
||||
$begin omp_inuse$$
|
||||
$spell
|
||||
cppad.hpp
|
||||
num
|
||||
inuse
|
||||
omp_alloc
|
||||
$$
|
||||
|
||||
$section Amount of Memory a Thread is Currently Using$$
|
||||
$mindex inuse$$
|
||||
|
||||
$head Deprecated 2011-08-31$$
|
||||
|
||||
$head Syntax$$
|
||||
$codei%# include <cppad/utility/omp_alloc.hpp>
|
||||
%$$
|
||||
$icode%num_bytes% = omp_alloc::inuse(%thread%)%$$
|
||||
Use the function $cref/thread_alloc::inuse/ta_inuse/$$ instead.
|
||||
|
||||
$head Purpose$$
|
||||
Memory being managed by $cref omp_alloc$$ has two states,
|
||||
currently in use by the specified thread,
|
||||
and quickly available for future use by the specified thread.
|
||||
This function informs the program how much memory is in use.
|
||||
|
||||
$head thread$$
|
||||
This argument has prototype
|
||||
$codei%
|
||||
size_t %thread%
|
||||
%$$
|
||||
Either $cref omp_get_thread_num$$ must be the same as $icode thread$$,
|
||||
or the current execution mode must be sequential
|
||||
(not $cref/parallel/omp_in_parallel/$$).
|
||||
|
||||
$head num_bytes$$
|
||||
The return value has prototype
|
||||
$codei%
|
||||
size_t %num_bytes%
|
||||
%$$
|
||||
It is the number of bytes currently in use by the specified thread.
|
||||
|
||||
$head Example$$
|
||||
$cref omp_alloc.cpp$$
|
||||
|
||||
$end
|
||||
*/
|
||||
/*!
|
||||
Determine the amount of memory that is currently inuse.
|
||||
|
||||
\param thread [in]
|
||||
Thread for which we are determining the amount of memory
|
||||
(must be < CPPAD_MAX_NUM_THREADS).
|
||||
Durring parallel execution, this must be the thread
|
||||
that is currently executing.
|
||||
|
||||
\return
|
||||
The amount of memory in bytes.
|
||||
*/
|
||||
static size_t inuse(size_t thread)
|
||||
{ return thread_alloc::inuse(thread); }
|
||||
/* -----------------------------------------------------------------------
|
||||
$begin omp_available$$
|
||||
$spell
|
||||
cppad.hpp
|
||||
num
|
||||
omp_alloc
|
||||
$$
|
||||
|
||||
$section Amount of Memory Available for Quick Use by a Thread$$
|
||||
|
||||
$head Deprecated 2011-08-31$$
|
||||
Use the function $cref/thread_alloc::available/ta_available/$$ instead.
|
||||
|
||||
$head Syntax$$
|
||||
$codei%# include <cppad/utility/omp_alloc.hpp>
|
||||
%$$
|
||||
$icode%num_bytes% = omp_alloc::available(%thread%)%$$
|
||||
|
||||
$head Purpose$$
|
||||
Memory being managed by $cref omp_alloc$$ has two states,
|
||||
currently in use by the specified thread,
|
||||
and quickly available for future use by the specified thread.
|
||||
This function informs the program how much memory is available.
|
||||
|
||||
$head thread$$
|
||||
This argument has prototype
|
||||
$codei%
|
||||
size_t %thread%
|
||||
%$$
|
||||
Either $cref omp_get_thread_num$$ must be the same as $icode thread$$,
|
||||
or the current execution mode must be sequential
|
||||
(not $cref/parallel/omp_in_parallel/$$).
|
||||
|
||||
$head num_bytes$$
|
||||
The return value has prototype
|
||||
$codei%
|
||||
size_t %num_bytes%
|
||||
%$$
|
||||
It is the number of bytes currently available for use by the specified thread.
|
||||
|
||||
$head Example$$
|
||||
$cref omp_alloc.cpp$$
|
||||
|
||||
$end
|
||||
*/
|
||||
/*!
|
||||
Determine the amount of memory that is currently available for use.
|
||||
|
||||
\copydetails inuse
|
||||
*/
|
||||
static size_t available(size_t thread)
|
||||
{ return thread_alloc::available(thread); }
|
||||
/* -----------------------------------------------------------------------
|
||||
$begin omp_create_array$$
|
||||
$spell
|
||||
cppad.hpp
|
||||
omp_alloc
|
||||
sizeof
|
||||
$$
|
||||
|
||||
$section Allocate Memory and Create A Raw Array$$
|
||||
$mindex create_array$$
|
||||
|
||||
$head Deprecated 2011-08-31$$
|
||||
Use the function $cref/thread_alloc::create_array/ta_create_array/$$ instead.
|
||||
|
||||
$head Syntax$$
|
||||
$codei%# include <cppad/utility/omp_alloc.hpp>
|
||||
%$$
|
||||
$icode%array% = omp_alloc::create_array<%Type%>(%size_min%, %size_out%)%$$.
|
||||
|
||||
$head Purpose$$
|
||||
Create a new raw array using $cref omp_alloc$$ a fast memory allocator
|
||||
that works well in a multi-threading OpenMP environment.
|
||||
|
||||
$head Type$$
|
||||
The type of the elements of the array.
|
||||
|
||||
$head size_min$$
|
||||
This argument has prototype
|
||||
$codei%
|
||||
size_t %size_min%
|
||||
%$$
|
||||
This is the minimum number of elements that there can be
|
||||
in the resulting $icode array$$.
|
||||
|
||||
$head size_out$$
|
||||
This argument has prototype
|
||||
$codei%
|
||||
size_t& %size_out%
|
||||
%$$
|
||||
The input value of this argument does not matter.
|
||||
Upon return, it is the actual number of elements
|
||||
in $icode array$$
|
||||
($icode% size_min %<=% size_out%$$).
|
||||
|
||||
$head array$$
|
||||
The return value $icode array$$ has prototype
|
||||
$codei%
|
||||
%Type%* %array%
|
||||
%$$
|
||||
It is array with $icode size_out$$ elements.
|
||||
The default constructor for $icode Type$$ is used to initialize the
|
||||
elements of $icode array$$.
|
||||
Note that $cref omp_delete_array$$
|
||||
should be used to destroy the array when it is no longer needed.
|
||||
|
||||
$head Delta$$
|
||||
The amount of memory $cref omp_inuse$$ by the current thread,
|
||||
will increase $icode delta$$ where
|
||||
$codei%
|
||||
sizeof(%Type%) * (%size_out% + 1) > %delta% >= sizeof(%Type%) * %size_out%
|
||||
%$$
|
||||
The $cref omp_available$$ memory will decrease by $icode delta$$,
|
||||
(and the allocation will be faster)
|
||||
if a previous allocation with $icode size_min$$ between its current value
|
||||
and $icode size_out$$ is available.
|
||||
|
||||
$head Example$$
|
||||
$cref omp_alloc.cpp$$
|
||||
|
||||
$end
|
||||
*/
|
||||
/*!
|
||||
Use omp_alloc to Create a Raw Array.
|
||||
|
||||
\tparam Type
|
||||
The type of the elements of the array.
|
||||
|
||||
\param size_min [in]
|
||||
The minimum number of elements in the array.
|
||||
|
||||
\param size_out [out]
|
||||
The actual number of elements in the array.
|
||||
|
||||
\return
|
||||
pointer to the first element of the array.
|
||||
The default constructor is used to initialize
|
||||
all the elements of the array.
|
||||
|
||||
\par
|
||||
The \c extra_ field, in the \c omp_alloc node before the return value,
|
||||
is set to size_out.
|
||||
*/
|
||||
template <class Type>
|
||||
static Type* create_array(size_t size_min, size_t& size_out)
|
||||
{ return thread_alloc::create_array<Type>(size_min, size_out); }
|
||||
/* -----------------------------------------------------------------------
|
||||
$begin omp_delete_array$$
|
||||
$spell
|
||||
cppad.hpp
|
||||
omp_alloc
|
||||
sizeof
|
||||
$$
|
||||
|
||||
$section Return A Raw Array to The Available Memory for a Thread$$
|
||||
$mindex delete_array$$
|
||||
|
||||
$head Deprecated 2011-08-31$$
|
||||
Use the function $cref/thread_alloc::delete_array/ta_delete_array/$$ instead.
|
||||
|
||||
$head Syntax$$
|
||||
$codei%# include <cppad/utility/omp_alloc.hpp>
|
||||
%$$
|
||||
$codei%omp_alloc::delete_array(%array%)%$$.
|
||||
|
||||
$head Purpose$$
|
||||
Returns memory corresponding to a raw array
|
||||
(create by $cref omp_create_array$$) to the
|
||||
$cref omp_available$$ memory pool for the current thread.
|
||||
|
||||
$head Type$$
|
||||
The type of the elements of the array.
|
||||
|
||||
$head array$$
|
||||
The argument $icode array$$ has prototype
|
||||
$codei%
|
||||
%Type%* %array%
|
||||
%$$
|
||||
It is a value returned by $cref omp_create_array$$ and not yet deleted.
|
||||
The $icode Type$$ destructor is called for each element in the array.
|
||||
|
||||
$head Thread$$
|
||||
The $cref/current thread/omp_get_thread_num/$$ must be the
|
||||
same as when $cref omp_create_array$$ returned the value $icode array$$.
|
||||
There is an exception to this rule:
|
||||
when the current execution mode is sequential
|
||||
(not $cref/parallel/omp_in_parallel/$$) the current thread number does not matter.
|
||||
|
||||
$head Delta$$
|
||||
The amount of memory $cref omp_inuse$$ will decrease by $icode delta$$,
|
||||
and the $cref omp_available$$ memory will increase by $icode delta$$,
|
||||
where $cref/delta/omp_create_array/Delta/$$
|
||||
is the same as for the corresponding call to $code create_array$$.
|
||||
|
||||
$head Example$$
|
||||
$cref omp_alloc.cpp$$
|
||||
|
||||
$end
|
||||
*/
|
||||
/*!
|
||||
Return Memory Used for a Raw Array to the Available Pool.
|
||||
|
||||
\tparam Type
|
||||
The type of the elements of the array.
|
||||
|
||||
\param array [in]
|
||||
A value returned by \c create_array that has not yet been deleted.
|
||||
The \c Type destructor is used to destroy each of the elements
|
||||
of the array.
|
||||
|
||||
\par
|
||||
Durring parallel execution, the current thread must be the same
|
||||
as during the corresponding call to \c create_array.
|
||||
*/
|
||||
template <class Type>
|
||||
static void delete_array(Type* array)
|
||||
{ thread_alloc::delete_array(array); }
|
||||
};
|
||||
/* --------------------------------------------------------------------------
|
||||
$begin omp_efficient$$
|
||||
$spell
|
||||
cppad.hpp
|
||||
omp_alloc
|
||||
ptr
|
||||
num
|
||||
bool
|
||||
const
|
||||
$$
|
||||
|
||||
$section Check If A Memory Allocation is Efficient for Another Use$$
|
||||
|
||||
$head Removed$$
|
||||
This function has been removed because speed tests seem to indicate
|
||||
it is just as fast, or faster, to free and then reallocate the memory.
|
||||
|
||||
$head Syntax$$
|
||||
$codei%# include <cppad/utility/omp_alloc.hpp>
|
||||
%$$
|
||||
$icode%flag% = omp_alloc::efficient(%v_ptr%, %num_bytes%)%$$
|
||||
|
||||
$head Purpose$$
|
||||
Check if memory that is currently in use is an efficient
|
||||
allocation for a specified number of bytes.
|
||||
|
||||
$head v_ptr$$
|
||||
This argument has prototype
|
||||
$codei%
|
||||
const void* %v_ptr%
|
||||
%$$.
|
||||
It must be a pointer to memory that is currently in use; i.e.
|
||||
obtained by a previous call to $cref omp_get_memory$$ and not yet returned.
|
||||
|
||||
$head num_bytes$$
|
||||
This argument has prototype
|
||||
$codei%
|
||||
size_t %num_bytes%
|
||||
%$$
|
||||
It specifies the number of bytes of the memory allocated by $icode v_ptr$$
|
||||
that we want to use.
|
||||
|
||||
$head flag$$
|
||||
The return value has prototype
|
||||
$codei%
|
||||
bool %flag%
|
||||
%$$
|
||||
It is true,
|
||||
a call to $code get_memory$$ with
|
||||
$cref/min_bytes/omp_get_memory/min_bytes/$$
|
||||
equal to $icode num_bytes$$ would result in a value for
|
||||
$cref/cap_bytes/omp_get_memory/cap_bytes/$$ that is the same as when $code v_ptr$$
|
||||
was returned by $code get_memory$$; i.e.,
|
||||
$icode v_ptr$$ is an efficient memory block for $icode num_bytes$$
|
||||
bytes of information.
|
||||
|
||||
$head Thread$$
|
||||
Either the $cref/current thread/omp_get_thread_num/$$ must be the same as during
|
||||
the corresponding call to $cref omp_get_memory$$,
|
||||
or the current execution mode must be sequential
|
||||
(not $cref/parallel/omp_in_parallel/$$).
|
||||
|
||||
$head NDEBUG$$
|
||||
If $code NDEBUG$$ is defined, $icode v_ptr$$ is not checked (this is faster).
|
||||
Otherwise, a list of in use pointers is searched to make sure
|
||||
that $icode v_ptr$$ is in the list.
|
||||
|
||||
$end
|
||||
---------------------------------------------------------------------------
|
||||
$begin old_max_num_threads$$
|
||||
$spell
|
||||
cppad.hpp
|
||||
inv
|
||||
CppAD
|
||||
num
|
||||
omp_alloc
|
||||
$$
|
||||
$section Set Maximum Number of Threads for omp_alloc Allocator$$
|
||||
$mindex max_num_threads$$
|
||||
|
||||
$head Removed$$
|
||||
This function has been removed from the CppAD API.
|
||||
Use the function $cref/thread_alloc::parallel_setup/ta_parallel_setup/$$
|
||||
in its place.
|
||||
|
||||
$head Syntax$$
|
||||
$codei%# include <cppad/utility/omp_alloc.hpp>
|
||||
%$$
|
||||
$codei%omp_alloc::max_num_threads(%number%)%$$
|
||||
|
||||
$head Purpose$$
|
||||
By default there is only one thread and all execution is in sequential mode
|
||||
(not $cref/parallel/omp_in_parallel/$$).
|
||||
|
||||
$head number$$
|
||||
The argument $icode number$$ has prototype
|
||||
$codei%
|
||||
size_t %number%
|
||||
%$$
|
||||
It must be greater than zero and specifies the maximum number of
|
||||
OpenMP threads that will be active at one time.
|
||||
|
||||
$head Restrictions$$
|
||||
This function must be called before the program enters
|
||||
$cref/parallel/omp_in_parallel/$$ execution mode.
|
||||
|
||||
$end
|
||||
-------------------------------------------------------------------------------
|
||||
*/
|
||||
} // END_CPPAD_NAMESPACE
|
||||
|
||||
# endif
|
||||
+193
@@ -0,0 +1,193 @@
|
||||
# ifndef CPPAD_UTILITY_POLY_HPP
|
||||
# define CPPAD_UTILITY_POLY_HPP
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-17 Bradley M. Bell
|
||||
|
||||
CppAD is distributed under multiple licenses. This distribution is under
|
||||
the terms of the
|
||||
Eclipse Public License Version 1.0.
|
||||
|
||||
A copy of this license is included in the COPYING file of this distribution.
|
||||
Please visit http://www.coin-or.org/CppAD/ for information on other licenses.
|
||||
-------------------------------------------------------------------------- */
|
||||
/*
|
||||
$begin Poly$$
|
||||
$spell
|
||||
cppad.hpp
|
||||
CppAD
|
||||
namespace
|
||||
cstddef
|
||||
ifndef
|
||||
endif
|
||||
deg
|
||||
const
|
||||
std
|
||||
da
|
||||
$$
|
||||
|
||||
|
||||
$section Evaluate a Polynomial or its Derivative$$
|
||||
$mindex Poly template$$
|
||||
|
||||
$head Syntax$$
|
||||
$codei%# include <cppad/utility/poly.hpp>
|
||||
%$$
|
||||
$icode%p% = Poly(%k%, %a%, %z%)%$$
|
||||
|
||||
|
||||
$head Description$$
|
||||
Computes the $th k$$ derivative of the polynomial
|
||||
$latex \[
|
||||
P(z) = a_0 + a_1 z^1 + \cdots + a_d z^d
|
||||
\] $$
|
||||
If $icode k$$ is equal to zero, the return value is $latex P(z)$$.
|
||||
|
||||
$head Include$$
|
||||
The file $code cppad/poly.hpp$$ is included by $code cppad/cppad.hpp$$
|
||||
but it can also be included separately with out the rest of
|
||||
the $code CppAD$$ routines.
|
||||
Including this file defines
|
||||
$code Poly$$ within the $code CppAD$$ namespace.
|
||||
|
||||
$head k$$
|
||||
The argument $icode k$$ has prototype
|
||||
$codei%
|
||||
size_t %k%
|
||||
%$$
|
||||
It specifies the order of the derivative to calculate.
|
||||
|
||||
$head a$$
|
||||
The argument $icode a$$ has prototype
|
||||
$codei%
|
||||
const %Vector% &%a%
|
||||
%$$
|
||||
(see $cref/Vector/Poly/Vector/$$ below).
|
||||
It specifies the vector corresponding to the polynomial $latex P(z)$$.
|
||||
|
||||
$head z$$
|
||||
The argument $icode z$$ has prototype
|
||||
$codei%
|
||||
const %Type% &%z%
|
||||
%$$
|
||||
(see $icode Type$$ below).
|
||||
It specifies the point at which to evaluate the polynomial
|
||||
|
||||
$head p$$
|
||||
The result $icode p$$ has prototype
|
||||
$codei%
|
||||
%Type% %p%
|
||||
%$$
|
||||
(see $cref/Type/Poly/Type/$$ below)
|
||||
and it is equal to the $th k$$ derivative of $latex P(z)$$; i.e.,
|
||||
$latex \[
|
||||
p = \frac{k !}{0 !} a_k
|
||||
+ \frac{(k+1) !}{1 !} a_{k+1} z^1
|
||||
+ \ldots
|
||||
+ \frac{d !}{(d - k) !} a_d z^{d - k}
|
||||
\]
|
||||
$$
|
||||
If $latex k > d$$, $icode%p% = %Type%(0)%$$.
|
||||
|
||||
$head Type$$
|
||||
The type $icode Type$$ is determined by the argument $icode z$$.
|
||||
It is assumed that
|
||||
multiplication and addition of $icode Type$$ objects
|
||||
are commutative.
|
||||
|
||||
$subhead Operations$$
|
||||
The following operations must be supported where
|
||||
$icode x$$ and $icode y$$ are objects of type $icode Type$$
|
||||
and $icode i$$ is an $code int$$:
|
||||
$table
|
||||
$icode%x% = %i%$$ $cnext assignment $rnext
|
||||
$icode%x% = %y%$$ $cnext assignment $rnext
|
||||
$icode%x% *= %y%$$ $cnext multiplication compound assignment $rnext
|
||||
$icode%x% += %y%$$ $cnext addition compound assignment
|
||||
|
||||
$tend
|
||||
|
||||
|
||||
$head Vector$$
|
||||
The type $icode Vector$$ must be a $cref SimpleVector$$ class with
|
||||
$cref/elements of type/SimpleVector/Elements of Specified Type/$$
|
||||
$icode Type$$.
|
||||
The routine $cref CheckSimpleVector$$ will generate an error message
|
||||
if this is not the case.
|
||||
|
||||
$head Operation Sequence$$
|
||||
The $icode Type$$ operation sequence used to calculate $icode p$$ is
|
||||
$cref/independent/glossary/Operation/Independent/$$
|
||||
of $icode z$$ and the elements of $icode a$$
|
||||
(it does depend on the size of the vector $icode a$$).
|
||||
|
||||
|
||||
$children%
|
||||
example/general/poly.cpp%
|
||||
omh/poly_hpp.omh
|
||||
%$$
|
||||
|
||||
$head Example$$
|
||||
The file
|
||||
$cref poly.cpp$$
|
||||
contains an example and test of this routine.
|
||||
It returns true if it succeeds and false otherwise.
|
||||
|
||||
$head Source$$
|
||||
The file $cref poly.hpp$$ contains the
|
||||
current source code that implements these specifications.
|
||||
|
||||
$end
|
||||
------------------------------------------------------------------------------
|
||||
*/
|
||||
// BEGIN C++
|
||||
# include <cstddef> // used to defined size_t
|
||||
# include <cppad/utility/check_simple_vector.hpp>
|
||||
|
||||
namespace CppAD { // BEGIN CppAD namespace
|
||||
|
||||
template <class Type, class Vector>
|
||||
Type Poly(size_t k, const Vector &a, const Type &z)
|
||||
{ size_t i;
|
||||
size_t d = a.size() - 1;
|
||||
|
||||
Type tmp;
|
||||
|
||||
// check Vector is Simple Vector class with Type elements
|
||||
CheckSimpleVector<Type, Vector>();
|
||||
|
||||
// case where derivative order greater than degree of polynomial
|
||||
if( k > d )
|
||||
{ tmp = 0;
|
||||
return tmp;
|
||||
}
|
||||
// case where we are evaluating a derivative
|
||||
if( k > 0 )
|
||||
{ // initialize factor as (k-1) !
|
||||
size_t factor = 1;
|
||||
for(i = 2; i < k; i++)
|
||||
factor *= i;
|
||||
|
||||
// set b to coefficient vector corresponding to derivative
|
||||
Vector b(d - k + 1);
|
||||
for(i = k; i <= d; i++)
|
||||
{ factor *= i;
|
||||
tmp = double( factor );
|
||||
b[i - k] = a[i] * tmp;
|
||||
factor /= (i - k + 1);
|
||||
}
|
||||
// value of derivative polynomial
|
||||
return Poly(0, b, z);
|
||||
}
|
||||
// case where we are evaluating the original polynomial
|
||||
Type sum = a[d];
|
||||
i = d;
|
||||
while(i > 0)
|
||||
{ sum *= z;
|
||||
sum += a[--i];
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
} // END CppAD namespace
|
||||
// END C++
|
||||
# endif
|
||||
+141
@@ -0,0 +1,141 @@
|
||||
# ifndef CPPAD_UTILITY_POW_INT_HPP
|
||||
# define CPPAD_UTILITY_POW_INT_HPP
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-17 Bradley M. Bell
|
||||
|
||||
CppAD is distributed under multiple licenses. This distribution is under
|
||||
the terms of the
|
||||
Eclipse Public License Version 1.0.
|
||||
|
||||
A copy of this license is included in the COPYING file of this distribution.
|
||||
Please visit http://www.coin-or.org/CppAD/ for information on other licenses.
|
||||
-------------------------------------------------------------------------- */
|
||||
|
||||
/*
|
||||
-------------------------------------------------------------------------------
|
||||
$begin pow_int$$
|
||||
$spell
|
||||
cppad.hpp
|
||||
CppAD
|
||||
namespace
|
||||
const
|
||||
$$
|
||||
|
||||
|
||||
$section The Integer Power Function$$
|
||||
$mindex pow exponent$$
|
||||
|
||||
$head Syntax$$
|
||||
$codei%# include <cppad/utility/pow_int.hpp>
|
||||
%$$
|
||||
$icode%z% = pow(%x%, %y%)%$$
|
||||
|
||||
$head See Also$$
|
||||
$cref pow$$
|
||||
|
||||
$head Purpose$$
|
||||
Determines the value of the power function
|
||||
$latex \[
|
||||
{\rm pow} (x, y) = x^y
|
||||
\] $$
|
||||
for integer exponents $icode n$$
|
||||
using multiplication and possibly division to compute the value.
|
||||
The other CppAD $cref pow$$ function may use logarithms and exponentiation
|
||||
to compute derivatives of the same value
|
||||
(which will not work if $icode x$$ is less than or equal zero).
|
||||
|
||||
$head Include$$
|
||||
The file $code cppad/pow_int.h$$ is included by $code cppad/cppad.hpp$$
|
||||
but it can also be included separately with out the rest of
|
||||
the $code CppAD$$ routines.
|
||||
Including this file defines
|
||||
this version of the $code pow$$ within the $code CppAD$$ namespace.
|
||||
|
||||
$head x$$
|
||||
The argument $icode x$$ has prototype
|
||||
$codei%
|
||||
const %Type%& %x%
|
||||
%$$
|
||||
|
||||
$head y$$
|
||||
The argument $icode y$$ has prototype
|
||||
$codei%
|
||||
const int& %y%
|
||||
%$$
|
||||
|
||||
$head z$$
|
||||
The result $icode z$$ has prototype
|
||||
$codei%
|
||||
%Type% %z%
|
||||
%$$
|
||||
|
||||
$head Type$$
|
||||
The type $icode Type$$ must support the following operations
|
||||
where $icode a$$ and $icode b$$ are $icode Type$$ objects
|
||||
and $icode i$$ is an $code int$$:
|
||||
$table
|
||||
$bold Operation$$ $pre $$
|
||||
$cnext $bold Description$$
|
||||
$cnext $bold Result Type$$
|
||||
$rnext
|
||||
$icode%Type% %a%(%i%)%$$
|
||||
$cnext construction of a $icode Type$$ object from an $code int$$
|
||||
$cnext $icode Type$$
|
||||
$rnext
|
||||
$icode%a% * %b%$$
|
||||
$cnext binary multiplication of $icode Type$$ objects
|
||||
$cnext $icode Type$$
|
||||
$rnext
|
||||
$icode%a% / %b%$$
|
||||
$cnext binary division of $icode Type$$ objects
|
||||
$cnext $icode Type$$
|
||||
$tend
|
||||
|
||||
$head Operation Sequence$$
|
||||
The $icode Type$$ operation sequence used to calculate $icode z$$ is
|
||||
$cref/independent/glossary/Operation/Independent/$$
|
||||
of $icode x$$.
|
||||
|
||||
$head Example$$
|
||||
$children%
|
||||
example/general/pow_int.cpp
|
||||
%$$
|
||||
The file $cref pow_int.cpp$$
|
||||
is an example and test of this function.
|
||||
It returns true if it succeeds and false otherwise.
|
||||
|
||||
|
||||
$end
|
||||
-------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
namespace CppAD {
|
||||
|
||||
template <class Type>
|
||||
inline Type pow (const Type& x, const int& n)
|
||||
{
|
||||
Type p(1);
|
||||
int n2 = n / 2;
|
||||
|
||||
if( n == 0 )
|
||||
return p;
|
||||
if( n < 0 )
|
||||
return p / pow(x, -n);
|
||||
if( n == 1 )
|
||||
return x;
|
||||
|
||||
// p = (x^2)^(n/2)
|
||||
p = pow( x * x , n2 );
|
||||
|
||||
// n is even case
|
||||
if( n % 2 == 0 )
|
||||
return p;
|
||||
|
||||
// n is odd case
|
||||
return p * x;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
# endif
|
||||
@@ -0,0 +1,326 @@
|
||||
# ifndef CPPAD_UTILITY_ROMBERG_MUL_HPP
|
||||
# define CPPAD_UTILITY_ROMBERG_MUL_HPP
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-17 Bradley M. Bell
|
||||
|
||||
CppAD is distributed under multiple licenses. This distribution is under
|
||||
the terms of the
|
||||
Eclipse Public License Version 1.0.
|
||||
|
||||
A copy of this license is included in the COPYING file of this distribution.
|
||||
Please visit http://www.coin-or.org/CppAD/ for information on other licenses.
|
||||
-------------------------------------------------------------------------- */
|
||||
/*
|
||||
$begin RombergMul$$
|
||||
$spell
|
||||
cppad.hpp
|
||||
bool
|
||||
const
|
||||
Cpp
|
||||
RombergMulMul
|
||||
$$
|
||||
|
||||
$section Multi-dimensional Romberg Integration$$
|
||||
$mindex integrate multi dimensional dimension$$
|
||||
|
||||
|
||||
$head Syntax$$
|
||||
$codei%# include <cppad/utility/romberg_mul.hpp>
|
||||
%$$
|
||||
$codei%RombergMul<%Fun%, %SizeVector%, %FloatVector%, %m%> %R%$$
|
||||
$pre
|
||||
$$
|
||||
$icode%r% = %R%(%F%, %a%, %b%, %n%, %p%, %e%)%$$
|
||||
|
||||
|
||||
$head Description$$
|
||||
Returns the Romberg integration estimate
|
||||
$latex r$$ for the multi-dimensional integral
|
||||
$latex \[
|
||||
r =
|
||||
\int_{a[0]}^{b[0]} \cdots \int_{a[m-1]}^{b[m-1]}
|
||||
\; F(x) \;
|
||||
{\bf d} x_0 \cdots {\bf d} x_{m-1}
|
||||
\; + \;
|
||||
\sum_{i=0}^{m-1}
|
||||
O \left[ ( b[i] - a[i] ) / 2^{n[i]-1} \right]^{2(p[i]+1)}
|
||||
\] $$
|
||||
|
||||
$head Include$$
|
||||
The file $code cppad/romberg_mul.hpp$$ is included by $code cppad/cppad.hpp$$
|
||||
but it can also be included separately with out the rest of
|
||||
the $code CppAD$$ routines.
|
||||
|
||||
$head m$$
|
||||
The template parameter $icode m$$ must be convertible to a $code size_t$$
|
||||
object with a value that can be determined at compile time; for example
|
||||
$code 2$$.
|
||||
It determines the dimension of the domain space for the integration.
|
||||
|
||||
$head r$$
|
||||
The return value $icode r$$ has prototype
|
||||
$codei%
|
||||
%Float% %r%
|
||||
%$$
|
||||
It is the estimate computed by $code RombergMul$$ for the integral above
|
||||
(see description of $cref/Float/RombergMul/Float/$$ below).
|
||||
|
||||
$head F$$
|
||||
The object $icode F$$ has the prototype
|
||||
$codei%
|
||||
%Fun% &%F%
|
||||
%$$
|
||||
It must support the operation
|
||||
$codei%
|
||||
%F%(%x%)
|
||||
%$$
|
||||
The argument $icode x$$ to $icode F$$ has prototype
|
||||
$codei%
|
||||
const %Float% &%x%
|
||||
%$$
|
||||
The return value of $icode F$$ is a $icode Float$$ object
|
||||
|
||||
$head a$$
|
||||
The argument $icode a$$ has prototype
|
||||
$codei%
|
||||
const %FloatVector% &%a%
|
||||
%$$
|
||||
It specifies the lower limit for the integration
|
||||
(see description of $cref/FloatVector/RombergMul/FloatVector/$$ below).
|
||||
|
||||
$head b$$
|
||||
The argument $icode b$$ has prototype
|
||||
$codei%
|
||||
const %FloatVector% &%b%
|
||||
%$$
|
||||
It specifies the upper limit for the integration.
|
||||
|
||||
$head n$$
|
||||
The argument $icode n$$ has prototype
|
||||
$codei%
|
||||
const %SizeVector% &%n%
|
||||
%$$
|
||||
A total number of $latex 2^{n[i]-1} + 1$$
|
||||
evaluations of $icode%F%(%x%)%$$ are used to estimate the integral
|
||||
with respect to $latex {\bf d} x_i$$.
|
||||
|
||||
$head p$$
|
||||
The argument $icode p$$ has prototype
|
||||
$codei%
|
||||
const %SizeVector% &%p%
|
||||
%$$
|
||||
For $latex i = 0 , \ldots , m-1$$,
|
||||
$latex n[i]$$ determines the accuracy order in the
|
||||
approximation for the integral
|
||||
that is returned by $code RombergMul$$.
|
||||
The values in $icode p$$ must be less than or equal $icode n$$; i.e.,
|
||||
$icode%p%[%i%] <= %n%[%i%]%$$.
|
||||
|
||||
$head e$$
|
||||
The argument $icode e$$ has prototype
|
||||
$codei%
|
||||
%Float% &%e%
|
||||
%$$
|
||||
The input value of $icode e$$ does not matter
|
||||
and its output value is an approximation for the absolute error in
|
||||
the integral estimate.
|
||||
|
||||
$head Float$$
|
||||
The type $icode Float$$ is defined as the type of the elements of
|
||||
$cref/FloatVector/RombergMul/FloatVector/$$.
|
||||
The type $icode Float$$ must satisfy the conditions
|
||||
for a $cref NumericType$$ type.
|
||||
The routine $cref CheckNumericType$$ will generate an error message
|
||||
if this is not the case.
|
||||
In addition, if $icode x$$ and $icode y$$ are $icode Float$$ objects,
|
||||
$codei%
|
||||
%x% < %y%
|
||||
%$$
|
||||
returns the $code bool$$ value true if $icode x$$ is less than
|
||||
$icode y$$ and false otherwise.
|
||||
|
||||
$head FloatVector$$
|
||||
The type $icode FloatVector$$ must be a $cref SimpleVector$$ class.
|
||||
The routine $cref CheckSimpleVector$$ will generate an error message
|
||||
if this is not the case.
|
||||
|
||||
|
||||
$children%
|
||||
example/utility/romberg_mul.cpp
|
||||
%$$
|
||||
$head Example$$
|
||||
$comment%
|
||||
example/utility/romberg_mul.cpp
|
||||
%$$
|
||||
The file
|
||||
$cref Rombergmul.cpp$$
|
||||
contains an example and test a test of using this routine.
|
||||
It returns true if it succeeds and false otherwise.
|
||||
|
||||
$head Source Code$$
|
||||
The source code for this routine is in the file
|
||||
$code cppad/romberg_mul.hpp$$.
|
||||
|
||||
$end
|
||||
*/
|
||||
|
||||
# include <cppad/utility/romberg_one.hpp>
|
||||
# include <cppad/utility/check_numeric_type.hpp>
|
||||
# include <cppad/utility/check_simple_vector.hpp>
|
||||
|
||||
namespace CppAD { // BEGIN CppAD namespace
|
||||
|
||||
template <class Fun, class FloatVector>
|
||||
class SliceLast {
|
||||
typedef typename FloatVector::value_type Float;
|
||||
private:
|
||||
Fun *F;
|
||||
size_t last;
|
||||
FloatVector x;
|
||||
public:
|
||||
SliceLast( Fun *F_, size_t last_, const FloatVector &x_ )
|
||||
: F(F_) , last(last_), x(last + 1)
|
||||
{ size_t i;
|
||||
for(i = 0; i < last; i++)
|
||||
x[i] = x_[i];
|
||||
}
|
||||
double operator()(const Float &xlast)
|
||||
{ x[last] = xlast;
|
||||
return (*F)(x);
|
||||
}
|
||||
};
|
||||
|
||||
template <class Fun, class SizeVector, class FloatVector, class Float>
|
||||
class IntegrateLast {
|
||||
private:
|
||||
Fun *F;
|
||||
const size_t last;
|
||||
const FloatVector a;
|
||||
const FloatVector b;
|
||||
const SizeVector n;
|
||||
const SizeVector p;
|
||||
Float esum;
|
||||
size_t ecount;
|
||||
|
||||
public:
|
||||
IntegrateLast(
|
||||
Fun *F_ ,
|
||||
size_t last_ ,
|
||||
const FloatVector &a_ ,
|
||||
const FloatVector &b_ ,
|
||||
const SizeVector &n_ ,
|
||||
const SizeVector &p_ )
|
||||
: F(F_) , last(last_), a(a_) , b(b_) , n(n_) , p(p_)
|
||||
{ }
|
||||
Float operator()(const FloatVector &x)
|
||||
{ Float r, e;
|
||||
SliceLast<Fun, FloatVector > S(F, last, x);
|
||||
r = CppAD::RombergOne(
|
||||
S, a[last], b[last], n[last], p[last], e
|
||||
);
|
||||
esum = esum + e;
|
||||
ecount++;
|
||||
return r;
|
||||
}
|
||||
void ClearEsum(void)
|
||||
{ esum = 0.; }
|
||||
Float GetEsum(void)
|
||||
{ return esum; }
|
||||
|
||||
void ClearEcount(void)
|
||||
{ ecount = 0; }
|
||||
size_t GetEcount(void)
|
||||
{ return ecount; }
|
||||
};
|
||||
|
||||
template <class Fun, class SizeVector, class FloatVector, size_t m>
|
||||
class RombergMul {
|
||||
typedef typename FloatVector::value_type Float;
|
||||
public:
|
||||
RombergMul(void)
|
||||
{ }
|
||||
Float operator() (
|
||||
Fun &F ,
|
||||
const FloatVector &a ,
|
||||
const FloatVector &b ,
|
||||
const SizeVector &n ,
|
||||
const SizeVector &p ,
|
||||
Float &e )
|
||||
{ Float r;
|
||||
|
||||
typedef IntegrateLast<
|
||||
Fun ,
|
||||
SizeVector ,
|
||||
FloatVector ,
|
||||
Float > IntegrateOne;
|
||||
|
||||
IntegrateOne Fm1(&F, m-1, a, b, n, p);
|
||||
RombergMul<
|
||||
IntegrateOne,
|
||||
SizeVector ,
|
||||
FloatVector ,
|
||||
m-1 > RombergMulM1;
|
||||
|
||||
Fm1.ClearEsum();
|
||||
Fm1.ClearEcount();
|
||||
|
||||
r = RombergMulM1(Fm1, a, b, n, p, e);
|
||||
|
||||
size_t i, j;
|
||||
Float prod = 1;
|
||||
size_t pow2 = 1;
|
||||
for(i = 0; i < m-1; i++)
|
||||
{ prod *= (b[i] - a[i]);
|
||||
for(j = 0; j < (n[i] - 1); j++)
|
||||
pow2 *= 2;
|
||||
}
|
||||
assert( Fm1.GetEcount() == (pow2+1) );
|
||||
|
||||
e = e + Fm1.GetEsum() * prod / Float( double(Fm1.GetEcount()) );
|
||||
|
||||
return r;
|
||||
}
|
||||
};
|
||||
|
||||
template <class Fun, class SizeVector, class FloatVector>
|
||||
class RombergMul <Fun, SizeVector, FloatVector, 1> {
|
||||
typedef typename FloatVector::value_type Float;
|
||||
public:
|
||||
Float operator() (
|
||||
Fun &F ,
|
||||
const FloatVector &a ,
|
||||
const FloatVector &b ,
|
||||
const SizeVector &n ,
|
||||
const SizeVector &p ,
|
||||
Float &e )
|
||||
{ Float r;
|
||||
typedef IntegrateLast<
|
||||
Fun ,
|
||||
SizeVector ,
|
||||
FloatVector ,
|
||||
Float > IntegrateOne;
|
||||
|
||||
// check simple vector class specifications
|
||||
CheckSimpleVector<Float, FloatVector>();
|
||||
|
||||
// check numeric type specifications
|
||||
CheckNumericType<Float>();
|
||||
|
||||
IntegrateOne F0(&F, 0, a, b, n, p);
|
||||
|
||||
F0.ClearEsum();
|
||||
F0.ClearEcount();
|
||||
|
||||
r = F0(a);
|
||||
|
||||
assert( F0.GetEcount() == 1 );
|
||||
e = F0.GetEsum();
|
||||
|
||||
return r;
|
||||
}
|
||||
};
|
||||
|
||||
} // END CppAD namespace
|
||||
|
||||
# endif
|
||||
@@ -0,0 +1,214 @@
|
||||
# ifndef CPPAD_UTILITY_ROMBERG_ONE_HPP
|
||||
# define CPPAD_UTILITY_ROMBERG_ONE_HPP
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-17 Bradley M. Bell
|
||||
|
||||
CppAD is distributed under multiple licenses. This distribution is under
|
||||
the terms of the
|
||||
Eclipse Public License Version 1.0.
|
||||
|
||||
A copy of this license is included in the COPYING file of this distribution.
|
||||
Please visit http://www.coin-or.org/CppAD/ for information on other licenses.
|
||||
-------------------------------------------------------------------------- */
|
||||
/*
|
||||
$begin RombergOne$$
|
||||
$spell
|
||||
cppad.hpp
|
||||
bool
|
||||
const
|
||||
Cpp
|
||||
RombergOne
|
||||
$$
|
||||
|
||||
$section One DimensionalRomberg Integration$$
|
||||
$mindex integrate Romberg$$
|
||||
|
||||
|
||||
$head Syntax$$
|
||||
$codei%# include <cppad/utility/romberg_one.hpp>
|
||||
%$$
|
||||
$icode%r% = RombergOne(%F%, %a%, %b%, %n%, %e%)%$$
|
||||
|
||||
|
||||
$head Description$$
|
||||
Returns the Romberg integration estimate
|
||||
$latex r$$ for a one dimensional integral
|
||||
$latex \[
|
||||
r = \int_a^b F(x) {\bf d} x + O \left[ (b - a) / 2^{n-1} \right]^{2(p+1)}
|
||||
\] $$
|
||||
|
||||
$head Include$$
|
||||
The file $code cppad/romberg_one.hpp$$ is included by $code cppad/cppad.hpp$$
|
||||
but it can also be included separately with out the rest of
|
||||
the $code CppAD$$ routines.
|
||||
|
||||
$head r$$
|
||||
The return value $icode r$$ has prototype
|
||||
$codei%
|
||||
%Float% %r%
|
||||
%$$
|
||||
It is the estimate computed by $code RombergOne$$ for the integral above.
|
||||
|
||||
$head F$$
|
||||
The object $icode F$$ can be of any type, but it must support
|
||||
the operation
|
||||
$codei%
|
||||
%F%(%x%)
|
||||
%$$
|
||||
The argument $icode x$$ to $icode F$$ has prototype
|
||||
$codei%
|
||||
const %Float% &%x%
|
||||
%$$
|
||||
The return value of $icode F$$ is a $icode Float$$ object
|
||||
(see description of $cref/Float/RombergOne/Float/$$ below).
|
||||
|
||||
$head a$$
|
||||
The argument $icode a$$ has prototype
|
||||
$codei%
|
||||
const %Float% &%a%
|
||||
%$$
|
||||
It specifies the lower limit for the integration.
|
||||
|
||||
$head b$$
|
||||
The argument $icode b$$ has prototype
|
||||
$codei%
|
||||
const %Float% &%b%
|
||||
%$$
|
||||
It specifies the upper limit for the integration.
|
||||
|
||||
$head n$$
|
||||
The argument $icode n$$ has prototype
|
||||
$codei%
|
||||
size_t %n%
|
||||
%$$
|
||||
A total number of $latex 2^{n-1} + 1$$ evaluations of $icode%F%(%x%)%$$
|
||||
are used to estimate the integral.
|
||||
|
||||
$head p$$
|
||||
The argument $icode p$$ has prototype
|
||||
$codei%
|
||||
size_t %p%
|
||||
%$$
|
||||
It must be less than or equal $latex n$$
|
||||
and determines the accuracy order in the approximation for the integral
|
||||
that is returned by $code RombergOne$$.
|
||||
To be specific
|
||||
$latex \[
|
||||
r = \int_a^b F(x) {\bf d} x + O \left[ (b - a) / 2^{n-1} \right]^{2(p+1)}
|
||||
\] $$
|
||||
|
||||
|
||||
$head e$$
|
||||
The argument $icode e$$ has prototype
|
||||
$codei%
|
||||
%Float% &%e%
|
||||
%$$
|
||||
The input value of $icode e$$ does not matter
|
||||
and its output value is an approximation for the error in
|
||||
the integral estimates; i.e.,
|
||||
$latex \[
|
||||
e \approx \left| r - \int_a^b F(x) {\bf d} x \right|
|
||||
\] $$
|
||||
|
||||
$head Float$$
|
||||
The type $icode Float$$ must satisfy the conditions
|
||||
for a $cref NumericType$$ type.
|
||||
The routine $cref CheckNumericType$$ will generate an error message
|
||||
if this is not the case.
|
||||
In addition, if $icode x$$ and $icode y$$ are $icode Float$$ objects,
|
||||
$codei%
|
||||
%x% < %y%
|
||||
%$$
|
||||
returns the $code bool$$ value true if $icode x$$ is less than
|
||||
$icode y$$ and false otherwise.
|
||||
|
||||
$children%
|
||||
example/utility/romberg_one.cpp
|
||||
%$$
|
||||
$head Example$$
|
||||
$comment%
|
||||
example/utility/romberg_one.cpp
|
||||
%$$
|
||||
The file
|
||||
$cref romberg_one.cpp$$
|
||||
contains an example and test a test of using this routine.
|
||||
It returns true if it succeeds and false otherwise.
|
||||
|
||||
$head Source Code$$
|
||||
The source code for this routine is in the file
|
||||
$code cppad/romberg_one.hpp$$.
|
||||
|
||||
$end
|
||||
*/
|
||||
|
||||
# include <cppad/utility/check_numeric_type.hpp>
|
||||
# include <cppad/core/cppad_assert.hpp>
|
||||
# include <cppad/utility/vector.hpp>
|
||||
|
||||
namespace CppAD { // BEGIN CppAD namespace
|
||||
|
||||
template <class Fun, class Float>
|
||||
Float RombergOne(
|
||||
Fun &F ,
|
||||
const Float &a ,
|
||||
const Float &b ,
|
||||
size_t n ,
|
||||
size_t p ,
|
||||
Float &e )
|
||||
{
|
||||
size_t ipow2 = 1;
|
||||
size_t k, i;
|
||||
Float pow2, sum, x;
|
||||
|
||||
Float zero = Float(0);
|
||||
Float two = Float(2);
|
||||
|
||||
// check specifications for a NumericType
|
||||
CheckNumericType<Float>();
|
||||
|
||||
CPPAD_ASSERT_KNOWN(
|
||||
n >= 2,
|
||||
"RombergOne: n must be greater than or equal 2"
|
||||
);
|
||||
CppAD::vector<Float> r(n);
|
||||
|
||||
// set r[i] = trapazoidal rule with 2^i intervals in [a, b]
|
||||
r[0] = ( F(a) + F(b) ) * (b - a) / two;
|
||||
for(i = 1; i < n; i++)
|
||||
{ ipow2 *= 2;
|
||||
// there must be a conversion from int to any numeric type
|
||||
pow2 = Float(int(ipow2));
|
||||
sum = zero;
|
||||
for(k = 1; k < ipow2; k += 2)
|
||||
{ // start = a + (b-a)/pow2, increment = 2*(b-a)/pow2
|
||||
x = ( (pow2 - Float(double(k))) * a + double(k) * b ) / pow2;
|
||||
sum = sum + F(x);
|
||||
}
|
||||
// combine function evaluations in sum with those in T[i-1]
|
||||
r[i] = r[i-1] / two + sum * (b - a) / pow2;
|
||||
}
|
||||
|
||||
// now compute the higher order estimates
|
||||
size_t ipow4 = 1; // order of accuract for previous estimate
|
||||
Float pow4, pow4minus;
|
||||
for(i = 0; i < p; i++)
|
||||
{ // compute estimate accurate to O[ step^(2*(i+1)) ]
|
||||
// put resutls in r[n-1], r[n-2], ... , r[n-i+1]
|
||||
ipow4 *= 4;
|
||||
pow4 = Float(int(ipow4));
|
||||
pow4minus = Float(ipow4-1);
|
||||
for(k = n-1; k > i; k--)
|
||||
r[k] = ( pow4 * r[k] - r[k-1] ) / pow4minus;
|
||||
}
|
||||
|
||||
// error estimate for r[n]
|
||||
e = r[n-1] - r[n-2];
|
||||
if( e < zero )
|
||||
e = - e;
|
||||
return r[n-1];
|
||||
}
|
||||
|
||||
} // END CppAD namespace
|
||||
|
||||
# endif
|
||||
+497
@@ -0,0 +1,497 @@
|
||||
# ifndef CPPAD_UTILITY_ROSEN_34_HPP
|
||||
# define CPPAD_UTILITY_ROSEN_34_HPP
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-17 Bradley M. Bell
|
||||
|
||||
CppAD is distributed under multiple licenses. This distribution is under
|
||||
the terms of the
|
||||
Eclipse Public License Version 1.0.
|
||||
|
||||
A copy of this license is included in the COPYING file of this distribution.
|
||||
Please visit http://www.coin-or.org/CppAD/ for information on other licenses.
|
||||
-------------------------------------------------------------------------- */
|
||||
|
||||
/*
|
||||
$begin Rosen34$$
|
||||
$spell
|
||||
cppad.hpp
|
||||
bool
|
||||
xf
|
||||
templated
|
||||
const
|
||||
Rosenbrock
|
||||
CppAD
|
||||
xi
|
||||
ti
|
||||
tf
|
||||
Karp
|
||||
Rosen
|
||||
Shampine
|
||||
ind
|
||||
dep
|
||||
$$
|
||||
|
||||
|
||||
$section A 3rd and 4th Order Rosenbrock ODE Solver$$
|
||||
$mindex Rosen34 solve stiff differential equation$$
|
||||
|
||||
$head Syntax$$
|
||||
$codei%# include <cppad/utility/rosen_34.hpp>
|
||||
%$$
|
||||
$icode%xf% = Rosen34(%F%, %M%, %ti%, %tf%, %xi%)
|
||||
%$$
|
||||
$icode%xf% = Rosen34(%F%, %M%, %ti%, %tf%, %xi%, %e%)
|
||||
%$$
|
||||
|
||||
|
||||
$head Description$$
|
||||
This is an embedded 3rd and 4th order Rosenbrock ODE solver
|
||||
(see Section 16.6 of $cref/Numerical Recipes/Bib/Numerical Recipes/$$
|
||||
for a description of Rosenbrock ODE solvers).
|
||||
In particular, we use the formulas taken from page 100 of
|
||||
$cref/Shampine, L.F./Bib/Shampine, L.F./$$
|
||||
(except that the fraction 98/108 has been correction to be 97/108).
|
||||
$pre
|
||||
|
||||
$$
|
||||
We use $latex n$$ for the size of the vector $icode xi$$.
|
||||
Let $latex \B{R}$$ denote the real numbers
|
||||
and let $latex F : \B{R} \times \B{R}^n \rightarrow \B{R}^n$$ be a smooth function.
|
||||
The return value $icode xf$$ contains a 5th order
|
||||
approximation for the value $latex X(tf)$$ where
|
||||
$latex X : [ti , tf] \rightarrow \B{R}^n$$ is defined by
|
||||
the following initial value problem:
|
||||
$latex \[
|
||||
\begin{array}{rcl}
|
||||
X(ti) & = & xi \\
|
||||
X'(t) & = & F[t , X(t)]
|
||||
\end{array}
|
||||
\] $$
|
||||
If your set of ordinary differential equations are not stiff
|
||||
an explicit method may be better (perhaps $cref Runge45$$.)
|
||||
|
||||
$head Include$$
|
||||
The file $code cppad/rosen_34.hpp$$ is included by $code cppad/cppad.hpp$$
|
||||
but it can also be included separately with out the rest of
|
||||
the $code CppAD$$ routines.
|
||||
|
||||
$head xf$$
|
||||
The return value $icode xf$$ has the prototype
|
||||
$codei%
|
||||
%Vector% %xf%
|
||||
%$$
|
||||
and the size of $icode xf$$ is equal to $icode n$$
|
||||
(see description of $cref/Vector/Rosen34/Vector/$$ below).
|
||||
$latex \[
|
||||
X(tf) = xf + O( h^5 )
|
||||
\] $$
|
||||
where $latex h = (tf - ti) / M$$ is the step size.
|
||||
If $icode xf$$ contains not a number $cref nan$$,
|
||||
see the discussion of $cref/f/Rosen34/Fun/Nan/$$.
|
||||
|
||||
$head Fun$$
|
||||
The class $icode Fun$$
|
||||
and the object $icode F$$ satisfy the prototype
|
||||
$codei%
|
||||
%Fun% &%F%
|
||||
%$$
|
||||
This must support the following set of calls
|
||||
$codei%
|
||||
%F%.Ode(%t%, %x%, %f%)
|
||||
%F%.Ode_ind(%t%, %x%, %f_t%)
|
||||
%F%.Ode_dep(%t%, %x%, %f_x%)
|
||||
%$$
|
||||
|
||||
$subhead t$$
|
||||
In all three cases,
|
||||
the argument $icode t$$ has prototype
|
||||
$codei%
|
||||
const %Scalar% &%t%
|
||||
%$$
|
||||
(see description of $cref/Scalar/Rosen34/Scalar/$$ below).
|
||||
|
||||
$subhead x$$
|
||||
In all three cases,
|
||||
the argument $icode x$$ has prototype
|
||||
$codei%
|
||||
const %Vector% &%x%
|
||||
%$$
|
||||
and has size $icode n$$
|
||||
(see description of $cref/Vector/Rosen34/Vector/$$ below).
|
||||
|
||||
$subhead f$$
|
||||
The argument $icode f$$ to $icode%F%.Ode%$$ has prototype
|
||||
$codei%
|
||||
%Vector% &%f%
|
||||
%$$
|
||||
On input and output, $icode f$$ is a vector of size $icode n$$
|
||||
and the input values of the elements of $icode f$$ do not matter.
|
||||
On output,
|
||||
$icode f$$ is set equal to $latex F(t, x)$$
|
||||
(see $icode F(t, x)$$ in $cref/Description/Rosen34/Description/$$).
|
||||
|
||||
$subhead f_t$$
|
||||
The argument $icode f_t$$ to $icode%F%.Ode_ind%$$ has prototype
|
||||
$codei%
|
||||
%Vector% &%f_t%
|
||||
%$$
|
||||
On input and output, $icode f_t$$ is a vector of size $icode n$$
|
||||
and the input values of the elements of $icode f_t$$ do not matter.
|
||||
On output, the $th i$$ element of
|
||||
$icode f_t$$ is set equal to $latex \partial_t F_i (t, x)$$
|
||||
(see $icode F(t, x)$$ in $cref/Description/Rosen34/Description/$$).
|
||||
|
||||
$subhead f_x$$
|
||||
The argument $icode f_x$$ to $icode%F%.Ode_dep%$$ has prototype
|
||||
$codei%
|
||||
%Vector% &%f_x%
|
||||
%$$
|
||||
On input and output, $icode f_x$$ is a vector of size $icode%n%*%n%$$
|
||||
and the input values of the elements of $icode f_x$$ do not matter.
|
||||
On output, the [$icode%i%*%n%+%j%$$] element of
|
||||
$icode f_x$$ is set equal to $latex \partial_{x(j)} F_i (t, x)$$
|
||||
(see $icode F(t, x)$$ in $cref/Description/Rosen34/Description/$$).
|
||||
|
||||
$subhead Nan$$
|
||||
If any of the elements of $icode f$$, $icode f_t$$, or $icode f_x$$
|
||||
have the value not a number $code nan$$,
|
||||
the routine $code Rosen34$$ returns with all the
|
||||
elements of $icode xf$$ and $icode e$$ equal to $code nan$$.
|
||||
|
||||
$subhead Warning$$
|
||||
The arguments $icode f$$, $icode f_t$$, and $icode f_x$$
|
||||
must have a call by reference in their prototypes; i.e.,
|
||||
do not forget the $code &$$ in the prototype for
|
||||
$icode f$$, $icode f_t$$ and $icode f_x$$.
|
||||
|
||||
$subhead Optimization$$
|
||||
Every call of the form
|
||||
$codei%
|
||||
%F%.Ode_ind(%t%, %x%, %f_t%)
|
||||
%$$
|
||||
is directly followed by a call of the form
|
||||
$codei%
|
||||
%F%.Ode_dep(%t%, %x%, %f_x%)
|
||||
%$$
|
||||
where the arguments $icode t$$ and $icode x$$ have not changed between calls.
|
||||
In many cases it is faster to compute the values of $icode f_t$$
|
||||
and $icode f_x$$ together and then pass them back one at a time.
|
||||
|
||||
$head M$$
|
||||
The argument $icode M$$ has prototype
|
||||
$codei%
|
||||
size_t %M%
|
||||
%$$
|
||||
It specifies the number of steps
|
||||
to use when solving the differential equation.
|
||||
This must be greater than or equal one.
|
||||
The step size is given by $latex h = (tf - ti) / M$$, thus
|
||||
the larger $icode M$$, the more accurate the
|
||||
return value $icode xf$$ is as an approximation
|
||||
for $latex X(tf)$$.
|
||||
|
||||
$head ti$$
|
||||
The argument $icode ti$$ has prototype
|
||||
$codei%
|
||||
const %Scalar% &%ti%
|
||||
%$$
|
||||
(see description of $cref/Scalar/Rosen34/Scalar/$$ below).
|
||||
It specifies the initial time for $icode t$$ in the
|
||||
differential equation; i.e.,
|
||||
the time corresponding to the value $icode xi$$.
|
||||
|
||||
$head tf$$
|
||||
The argument $icode tf$$ has prototype
|
||||
$codei%
|
||||
const %Scalar% &%tf%
|
||||
%$$
|
||||
It specifies the final time for $icode t$$ in the
|
||||
differential equation; i.e.,
|
||||
the time corresponding to the value $icode xf$$.
|
||||
|
||||
$head xi$$
|
||||
The argument $icode xi$$ has the prototype
|
||||
$codei%
|
||||
const %Vector% &%xi%
|
||||
%$$
|
||||
and the size of $icode xi$$ is equal to $icode n$$.
|
||||
It specifies the value of $latex X(ti)$$
|
||||
|
||||
$head e$$
|
||||
The argument $icode e$$ is optional and has the prototype
|
||||
$codei%
|
||||
%Vector% &%e%
|
||||
%$$
|
||||
If $icode e$$ is present,
|
||||
the size of $icode e$$ must be equal to $icode n$$.
|
||||
The input value of the elements of $icode e$$ does not matter.
|
||||
On output
|
||||
it contains an element by element
|
||||
estimated bound for the absolute value of the error in $icode xf$$
|
||||
$latex \[
|
||||
e = O( h^4 )
|
||||
\] $$
|
||||
where $latex h = (tf - ti) / M$$ is the step size.
|
||||
|
||||
$head Scalar$$
|
||||
The type $icode Scalar$$ must satisfy the conditions
|
||||
for a $cref NumericType$$ type.
|
||||
The routine $cref CheckNumericType$$ will generate an error message
|
||||
if this is not the case.
|
||||
In addition, the following operations must be defined for
|
||||
$icode Scalar$$ objects $icode a$$ and $icode b$$:
|
||||
|
||||
$table
|
||||
$bold Operation$$ $cnext $bold Description$$ $rnext
|
||||
$icode%a% < %b%$$ $cnext
|
||||
less than operator (returns a $code bool$$ object)
|
||||
$tend
|
||||
|
||||
$head Vector$$
|
||||
The type $icode Vector$$ must be a $cref SimpleVector$$ class with
|
||||
$cref/elements of type Scalar/SimpleVector/Elements of Specified Type/$$.
|
||||
The routine $cref CheckSimpleVector$$ will generate an error message
|
||||
if this is not the case.
|
||||
|
||||
$head Parallel Mode$$
|
||||
For each set of types
|
||||
$cref/Scalar/Rosen34/Scalar/$$,
|
||||
$cref/Vector/Rosen34/Vector/$$, and
|
||||
$cref/Fun/Rosen34/Fun/$$,
|
||||
the first call to $code Rosen34$$
|
||||
must not be $cref/parallel/ta_in_parallel/$$ execution mode.
|
||||
|
||||
$head Example$$
|
||||
$children%
|
||||
example/general/rosen_34.cpp
|
||||
%$$
|
||||
The file
|
||||
$cref rosen_34.cpp$$
|
||||
contains an example and test a test of using this routine.
|
||||
It returns true if it succeeds and false otherwise.
|
||||
|
||||
$head Source Code$$
|
||||
The source code for this routine is in the file
|
||||
$code cppad/rosen_34.hpp$$.
|
||||
|
||||
$end
|
||||
--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
# include <cstddef>
|
||||
# include <cppad/core/cppad_assert.hpp>
|
||||
# include <cppad/utility/check_simple_vector.hpp>
|
||||
# include <cppad/utility/check_numeric_type.hpp>
|
||||
# include <cppad/utility/vector.hpp>
|
||||
# include <cppad/utility/lu_factor.hpp>
|
||||
# include <cppad/utility/lu_invert.hpp>
|
||||
|
||||
// needed before one can use CPPAD_ASSERT_FIRST_CALL_NOT_PARALLEL
|
||||
# include <cppad/utility/thread_alloc.hpp>
|
||||
|
||||
namespace CppAD { // BEGIN CppAD namespace
|
||||
|
||||
template <typename Scalar, typename Vector, typename Fun>
|
||||
Vector Rosen34(
|
||||
Fun &F ,
|
||||
size_t M ,
|
||||
const Scalar &ti ,
|
||||
const Scalar &tf ,
|
||||
const Vector &xi )
|
||||
{ Vector e( xi.size() );
|
||||
return Rosen34(F, M, ti, tf, xi, e);
|
||||
}
|
||||
|
||||
template <typename Scalar, typename Vector, typename Fun>
|
||||
Vector Rosen34(
|
||||
Fun &F ,
|
||||
size_t M ,
|
||||
const Scalar &ti ,
|
||||
const Scalar &tf ,
|
||||
const Vector &xi ,
|
||||
Vector &e )
|
||||
{
|
||||
CPPAD_ASSERT_FIRST_CALL_NOT_PARALLEL;
|
||||
|
||||
// check numeric type specifications
|
||||
CheckNumericType<Scalar>();
|
||||
|
||||
// check simple vector class specifications
|
||||
CheckSimpleVector<Scalar, Vector>();
|
||||
|
||||
// Parameters for Shampine's Rosenbrock method
|
||||
// are static to avoid recalculation on each call and
|
||||
// do not use Vector to avoid possible memory leak
|
||||
static Scalar a[3] = {
|
||||
Scalar(0),
|
||||
Scalar(1),
|
||||
Scalar(3) / Scalar(5)
|
||||
};
|
||||
static Scalar b[2 * 2] = {
|
||||
Scalar(1),
|
||||
Scalar(0),
|
||||
Scalar(24) / Scalar(25),
|
||||
Scalar(3) / Scalar(25)
|
||||
};
|
||||
static Scalar ct[4] = {
|
||||
Scalar(1) / Scalar(2),
|
||||
- Scalar(3) / Scalar(2),
|
||||
Scalar(121) / Scalar(50),
|
||||
Scalar(29) / Scalar(250)
|
||||
};
|
||||
static Scalar cg[3 * 3] = {
|
||||
- Scalar(4),
|
||||
Scalar(0),
|
||||
Scalar(0),
|
||||
Scalar(186) / Scalar(25),
|
||||
Scalar(6) / Scalar(5),
|
||||
Scalar(0),
|
||||
- Scalar(56) / Scalar(125),
|
||||
- Scalar(27) / Scalar(125),
|
||||
- Scalar(1) / Scalar(5)
|
||||
};
|
||||
static Scalar d3[3] = {
|
||||
Scalar(97) / Scalar(108),
|
||||
Scalar(11) / Scalar(72),
|
||||
Scalar(25) / Scalar(216)
|
||||
};
|
||||
static Scalar d4[4] = {
|
||||
Scalar(19) / Scalar(18),
|
||||
Scalar(1) / Scalar(4),
|
||||
Scalar(25) / Scalar(216),
|
||||
Scalar(125) / Scalar(216)
|
||||
};
|
||||
CPPAD_ASSERT_KNOWN(
|
||||
M >= 1,
|
||||
"Error in Rosen34: the number of steps is less than one"
|
||||
);
|
||||
CPPAD_ASSERT_KNOWN(
|
||||
e.size() == xi.size(),
|
||||
"Error in Rosen34: size of e not equal to size of xi"
|
||||
);
|
||||
size_t i, j, k, l, m; // indices
|
||||
|
||||
size_t n = xi.size(); // number of components in X(t)
|
||||
Scalar ns = Scalar(double(M)); // number of steps as Scalar object
|
||||
Scalar h = (tf - ti) / ns; // step size
|
||||
Scalar zero = Scalar(0); // some constants
|
||||
Scalar one = Scalar(1);
|
||||
Scalar two = Scalar(2);
|
||||
|
||||
// permutation vectors needed for LU factorization routine
|
||||
CppAD::vector<size_t> ip(n), jp(n);
|
||||
|
||||
// vectors used to store values returned by F
|
||||
Vector E(n * n), Eg(n), f_t(n);
|
||||
Vector g(n * 3), x3(n), x4(n), xf(n), ftmp(n), xtmp(n), nan_vec(n);
|
||||
|
||||
// initialize e = 0, nan_vec = nan
|
||||
for(i = 0; i < n; i++)
|
||||
{ e[i] = zero;
|
||||
nan_vec[i] = nan(zero);
|
||||
}
|
||||
|
||||
xf = xi; // initialize solution
|
||||
for(m = 0; m < M; m++)
|
||||
{ // time at beginning of this interval
|
||||
Scalar t = ti * (Scalar(int(M - m)) / ns)
|
||||
+ tf * (Scalar(int(m)) / ns);
|
||||
|
||||
// value of x at beginning of this interval
|
||||
x3 = x4 = xf;
|
||||
|
||||
// evaluate partial derivatives at beginning of this interval
|
||||
F.Ode_ind(t, xf, f_t);
|
||||
F.Ode_dep(t, xf, E); // E = f_x
|
||||
if( hasnan(f_t) || hasnan(E) )
|
||||
{ e = nan_vec;
|
||||
return nan_vec;
|
||||
}
|
||||
|
||||
// E = I - f_x * h / 2
|
||||
for(i = 0; i < n; i++)
|
||||
{ for(j = 0; j < n; j++)
|
||||
E[i * n + j] = - E[i * n + j] * h / two;
|
||||
E[i * n + i] += one;
|
||||
}
|
||||
|
||||
// LU factor the matrix E
|
||||
# ifndef NDEBUG
|
||||
int sign = LuFactor(ip, jp, E);
|
||||
# else
|
||||
LuFactor(ip, jp, E);
|
||||
# endif
|
||||
CPPAD_ASSERT_KNOWN(
|
||||
sign != 0,
|
||||
"Error in Rosen34: I - f_x * h / 2 not invertible"
|
||||
);
|
||||
|
||||
// loop over integration steps
|
||||
for(k = 0; k < 3; k++)
|
||||
{ // set location for next function evaluation
|
||||
xtmp = xf;
|
||||
for(l = 0; l < k; l++)
|
||||
{ // loop over previous function evaluations
|
||||
Scalar bkl = b[(k-1)*2 + l];
|
||||
for(i = 0; i < n; i++)
|
||||
{ // loop over elements of x
|
||||
xtmp[i] += bkl * g[i*3 + l] * h;
|
||||
}
|
||||
}
|
||||
// ftmp = F(t + a[k] * h, xtmp)
|
||||
F.Ode(t + a[k] * h, xtmp, ftmp);
|
||||
if( hasnan(ftmp) )
|
||||
{ e = nan_vec;
|
||||
return nan_vec;
|
||||
}
|
||||
|
||||
// Form Eg for this integration step
|
||||
for(i = 0; i < n; i++)
|
||||
Eg[i] = ftmp[i] + ct[k] * f_t[i] * h;
|
||||
for(l = 0; l < k; l++)
|
||||
{ for(i = 0; i < n; i++)
|
||||
Eg[i] += cg[(k-1)*3 + l] * g[i*3 + l];
|
||||
}
|
||||
|
||||
// Solve the equation E * g = Eg
|
||||
LuInvert(ip, jp, E, Eg);
|
||||
|
||||
// save solution and advance x3, x4
|
||||
for(i = 0; i < n; i++)
|
||||
{ g[i*3 + k] = Eg[i];
|
||||
x3[i] += h * d3[k] * Eg[i];
|
||||
x4[i] += h * d4[k] * Eg[i];
|
||||
}
|
||||
}
|
||||
// Form Eg for last update to x4 only
|
||||
for(i = 0; i < n; i++)
|
||||
Eg[i] = ftmp[i] + ct[3] * f_t[i] * h;
|
||||
for(l = 0; l < 3; l++)
|
||||
{ for(i = 0; i < n; i++)
|
||||
Eg[i] += cg[2*3 + l] * g[i*3 + l];
|
||||
}
|
||||
|
||||
// Solve the equation E * g = Eg
|
||||
LuInvert(ip, jp, E, Eg);
|
||||
|
||||
// advance x4 and accumulate error bound
|
||||
for(i = 0; i < n; i++)
|
||||
{ x4[i] += h * d4[3] * Eg[i];
|
||||
|
||||
// cant use abs because cppad.hpp may not be included
|
||||
Scalar diff = x4[i] - x3[i];
|
||||
if( diff < zero )
|
||||
e[i] -= diff;
|
||||
else e[i] += diff;
|
||||
}
|
||||
|
||||
// advance xf for this step using x4
|
||||
xf = x4;
|
||||
}
|
||||
return xf;
|
||||
}
|
||||
|
||||
} // End CppAD namespace
|
||||
|
||||
# endif
|
||||
+428
@@ -0,0 +1,428 @@
|
||||
# ifndef CPPAD_UTILITY_RUNGE_45_HPP
|
||||
# define CPPAD_UTILITY_RUNGE_45_HPP
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-17 Bradley M. Bell
|
||||
|
||||
CppAD is distributed under multiple licenses. This distribution is under
|
||||
the terms of the
|
||||
Eclipse Public License Version 1.0.
|
||||
|
||||
A copy of this license is included in the COPYING file of this distribution.
|
||||
Please visit http://www.coin-or.org/CppAD/ for information on other licenses.
|
||||
-------------------------------------------------------------------------- */
|
||||
|
||||
/*
|
||||
$begin Runge45$$
|
||||
$spell
|
||||
std
|
||||
fabs
|
||||
cppad.hpp
|
||||
bool
|
||||
xf
|
||||
templated
|
||||
const
|
||||
Runge-Kutta
|
||||
CppAD
|
||||
xi
|
||||
ti
|
||||
tf
|
||||
Karp
|
||||
$$
|
||||
|
||||
|
||||
$section An Embedded 4th and 5th Order Runge-Kutta ODE Solver$$
|
||||
$mindex Runge45 Runge Kutta solve differential equation$$
|
||||
|
||||
$head Syntax$$
|
||||
$codei%# include <cppad/utility/runge_45.hpp>
|
||||
%$$
|
||||
$icode%xf% = Runge45(%F%, %M%, %ti%, %tf%, %xi%)
|
||||
%$$
|
||||
$icode%xf% = Runge45(%F%, %M%, %ti%, %tf%, %xi%, %e%)
|
||||
%$$
|
||||
|
||||
|
||||
$head Purpose$$
|
||||
This is an implementation of the
|
||||
Cash-Karp embedded 4th and 5th order Runge-Kutta ODE solver
|
||||
described in Section 16.2 of $cref/Numerical Recipes/Bib/Numerical Recipes/$$.
|
||||
We use $latex n$$ for the size of the vector $icode xi$$.
|
||||
Let $latex \B{R}$$ denote the real numbers
|
||||
and let $latex F : \B{R} \times \B{R}^n \rightarrow \B{R}^n$$
|
||||
be a smooth function.
|
||||
The return value $icode xf$$ contains a 5th order
|
||||
approximation for the value $latex X(tf)$$ where
|
||||
$latex X : [ti , tf] \rightarrow \B{R}^n$$ is defined by
|
||||
the following initial value problem:
|
||||
$latex \[
|
||||
\begin{array}{rcl}
|
||||
X(ti) & = & xi \\
|
||||
X'(t) & = & F[t , X(t)]
|
||||
\end{array}
|
||||
\] $$
|
||||
If your set of ordinary differential equations
|
||||
are stiff, an implicit method may be better
|
||||
(perhaps $cref Rosen34$$.)
|
||||
|
||||
$head Operation Sequence$$
|
||||
The $cref/operation sequence/glossary/Operation/Sequence/$$ for $icode Runge$$
|
||||
does not depend on any of its $icode Scalar$$ input values provided that
|
||||
the operation sequence for
|
||||
$codei%
|
||||
%F%.Ode(%t%, %x%, %f%)
|
||||
%$$
|
||||
does not on any of its $icode Scalar$$ inputs (see below).
|
||||
|
||||
$head Include$$
|
||||
The file $code cppad/runge_45.hpp$$ is included by $code cppad/cppad.hpp$$
|
||||
but it can also be included separately with out the rest of
|
||||
the $code CppAD$$ routines.
|
||||
|
||||
$head xf$$
|
||||
The return value $icode xf$$ has the prototype
|
||||
$codei%
|
||||
%Vector% %xf%
|
||||
%$$
|
||||
and the size of $icode xf$$ is equal to $icode n$$
|
||||
(see description of $cref/Vector/Runge45/Vector/$$ below).
|
||||
$latex \[
|
||||
X(tf) = xf + O( h^6 )
|
||||
\] $$
|
||||
where $latex h = (tf - ti) / M$$ is the step size.
|
||||
If $icode xf$$ contains not a number $cref nan$$,
|
||||
see the discussion for $cref/f/Runge45/Fun/f/$$.
|
||||
|
||||
$head Fun$$
|
||||
The class $icode Fun$$
|
||||
and the object $icode F$$ satisfy the prototype
|
||||
$codei%
|
||||
%Fun% &%F%
|
||||
%$$
|
||||
The object $icode F$$ (and the class $icode Fun$$)
|
||||
must have a member function named $code Ode$$
|
||||
that supports the syntax
|
||||
$codei%
|
||||
%F%.Ode(%t%, %x%, %f%)
|
||||
%$$
|
||||
|
||||
$subhead t$$
|
||||
The argument $icode t$$ to $icode%F%.Ode%$$ has prototype
|
||||
$codei%
|
||||
const %Scalar% &%t%
|
||||
%$$
|
||||
(see description of $cref/Scalar/Runge45/Scalar/$$ below).
|
||||
|
||||
$subhead x$$
|
||||
The argument $icode x$$ to $icode%F%.Ode%$$ has prototype
|
||||
$codei%
|
||||
const %Vector% &%x%
|
||||
%$$
|
||||
and has size $icode n$$
|
||||
(see description of $cref/Vector/Runge45/Vector/$$ below).
|
||||
|
||||
$subhead f$$
|
||||
The argument $icode f$$ to $icode%F%.Ode%$$ has prototype
|
||||
$codei%
|
||||
%Vector% &%f%
|
||||
%$$
|
||||
On input and output, $icode f$$ is a vector of size $icode n$$
|
||||
and the input values of the elements of $icode f$$ do not matter.
|
||||
On output,
|
||||
$icode f$$ is set equal to $latex F(t, x)$$ in the differential equation.
|
||||
If any of the elements of $icode f$$ have the value not a number $code nan$$
|
||||
the routine $code Runge45$$ returns with all the
|
||||
elements of $icode xf$$ and $icode e$$ equal to $code nan$$.
|
||||
|
||||
$subhead Warning$$
|
||||
The argument $icode f$$ to $icode%F%.Ode%$$
|
||||
must have a call by reference in its prototype; i.e.,
|
||||
do not forget the $code &$$ in the prototype for $icode f$$.
|
||||
|
||||
$head M$$
|
||||
The argument $icode M$$ has prototype
|
||||
$codei%
|
||||
size_t %M%
|
||||
%$$
|
||||
It specifies the number of steps
|
||||
to use when solving the differential equation.
|
||||
This must be greater than or equal one.
|
||||
The step size is given by $latex h = (tf - ti) / M$$, thus
|
||||
the larger $icode M$$, the more accurate the
|
||||
return value $icode xf$$ is as an approximation
|
||||
for $latex X(tf)$$.
|
||||
|
||||
$head ti$$
|
||||
The argument $icode ti$$ has prototype
|
||||
$codei%
|
||||
const %Scalar% &%ti%
|
||||
%$$
|
||||
(see description of $cref/Scalar/Runge45/Scalar/$$ below).
|
||||
It specifies the initial time for $icode t$$ in the
|
||||
differential equation; i.e.,
|
||||
the time corresponding to the value $icode xi$$.
|
||||
|
||||
$head tf$$
|
||||
The argument $icode tf$$ has prototype
|
||||
$codei%
|
||||
const %Scalar% &%tf%
|
||||
%$$
|
||||
It specifies the final time for $icode t$$ in the
|
||||
differential equation; i.e.,
|
||||
the time corresponding to the value $icode xf$$.
|
||||
|
||||
$head xi$$
|
||||
The argument $icode xi$$ has the prototype
|
||||
$codei%
|
||||
const %Vector% &%xi%
|
||||
%$$
|
||||
and the size of $icode xi$$ is equal to $icode n$$.
|
||||
It specifies the value of $latex X(ti)$$
|
||||
|
||||
$head e$$
|
||||
The argument $icode e$$ is optional and has the prototype
|
||||
$codei%
|
||||
%Vector% &%e%
|
||||
%$$
|
||||
If $icode e$$ is present,
|
||||
the size of $icode e$$ must be equal to $icode n$$.
|
||||
The input value of the elements of $icode e$$ does not matter.
|
||||
On output
|
||||
it contains an element by element
|
||||
estimated bound for the absolute value of the error in $icode xf$$
|
||||
$latex \[
|
||||
e = O( h^5 )
|
||||
\] $$
|
||||
where $latex h = (tf - ti) / M$$ is the step size.
|
||||
If on output, $icode e$$ contains not a number $code nan$$,
|
||||
see the discussion for $cref/f/Runge45/Fun/f/$$.
|
||||
|
||||
$head Scalar$$
|
||||
The type $icode Scalar$$ must satisfy the conditions
|
||||
for a $cref NumericType$$ type.
|
||||
The routine $cref CheckNumericType$$ will generate an error message
|
||||
if this is not the case.
|
||||
|
||||
$subhead fabs$$
|
||||
In addition, the following function must be defined for
|
||||
$icode Scalar$$ objects $icode a$$ and $icode b$$
|
||||
$codei%
|
||||
%a% = fabs(%b%)
|
||||
%$$
|
||||
Note that this operation is only used for computing $icode e$$; hence
|
||||
the operation sequence for $icode xf$$ can still be independent of
|
||||
the arguments to $code Runge45$$ even if
|
||||
$codei%
|
||||
fabs(%b%) = std::max(-%b%, %b%)
|
||||
%$$.
|
||||
|
||||
$head Vector$$
|
||||
The type $icode Vector$$ must be a $cref SimpleVector$$ class with
|
||||
$cref/elements of type Scalar/SimpleVector/Elements of Specified Type/$$.
|
||||
The routine $cref CheckSimpleVector$$ will generate an error message
|
||||
if this is not the case.
|
||||
|
||||
$head Parallel Mode$$
|
||||
For each set of types
|
||||
$cref/Scalar/Runge45/Scalar/$$,
|
||||
$cref/Vector/Runge45/Vector/$$, and
|
||||
$cref/Fun/Runge45/Fun/$$,
|
||||
the first call to $code Runge45$$
|
||||
must not be $cref/parallel/ta_in_parallel/$$ execution mode.
|
||||
|
||||
|
||||
$head Example$$
|
||||
$children%
|
||||
example/utility/runge45_1.cpp%
|
||||
example/general/runge45_2.cpp
|
||||
%$$
|
||||
The file
|
||||
$cref runge45_1.cpp$$
|
||||
contains a simple example and test of $code Runge45$$.
|
||||
It returns true if it succeeds and false otherwise.
|
||||
$pre
|
||||
|
||||
$$
|
||||
The file
|
||||
$cref runge45_2.cpp$$ contains an example using $code Runge45$$
|
||||
in the context of algorithmic differentiation.
|
||||
It also returns true if it succeeds and false otherwise.
|
||||
|
||||
$head Source Code$$
|
||||
The source code for this routine is in the file
|
||||
$code cppad/runge_45.hpp$$.
|
||||
|
||||
$end
|
||||
--------------------------------------------------------------------------
|
||||
*/
|
||||
# include <cstddef>
|
||||
# include <cppad/core/cppad_assert.hpp>
|
||||
# include <cppad/utility/check_simple_vector.hpp>
|
||||
# include <cppad/utility/check_numeric_type.hpp>
|
||||
# include <cppad/utility/nan.hpp>
|
||||
|
||||
// needed before one can use CPPAD_ASSERT_FIRST_CALL_NOT_PARALLEL
|
||||
# include <cppad/utility/thread_alloc.hpp>
|
||||
|
||||
namespace CppAD { // BEGIN CppAD namespace
|
||||
|
||||
template <typename Scalar, typename Vector, typename Fun>
|
||||
Vector Runge45(
|
||||
Fun &F ,
|
||||
size_t M ,
|
||||
const Scalar &ti ,
|
||||
const Scalar &tf ,
|
||||
const Vector &xi )
|
||||
{ Vector e( xi.size() );
|
||||
return Runge45(F, M, ti, tf, xi, e);
|
||||
}
|
||||
|
||||
template <typename Scalar, typename Vector, typename Fun>
|
||||
Vector Runge45(
|
||||
Fun &F ,
|
||||
size_t M ,
|
||||
const Scalar &ti ,
|
||||
const Scalar &tf ,
|
||||
const Vector &xi ,
|
||||
Vector &e )
|
||||
{
|
||||
CPPAD_ASSERT_FIRST_CALL_NOT_PARALLEL;
|
||||
|
||||
// check numeric type specifications
|
||||
CheckNumericType<Scalar>();
|
||||
|
||||
// check simple vector class specifications
|
||||
CheckSimpleVector<Scalar, Vector>();
|
||||
|
||||
// Cash-Karp parameters for embedded Runge-Kutta method
|
||||
// are static to avoid recalculation on each call and
|
||||
// do not use Vector to avoid possible memory leak
|
||||
static Scalar a[6] = {
|
||||
Scalar(0),
|
||||
Scalar(1) / Scalar(5),
|
||||
Scalar(3) / Scalar(10),
|
||||
Scalar(3) / Scalar(5),
|
||||
Scalar(1),
|
||||
Scalar(7) / Scalar(8)
|
||||
};
|
||||
static Scalar b[5 * 5] = {
|
||||
Scalar(1) / Scalar(5),
|
||||
Scalar(0),
|
||||
Scalar(0),
|
||||
Scalar(0),
|
||||
Scalar(0),
|
||||
|
||||
Scalar(3) / Scalar(40),
|
||||
Scalar(9) / Scalar(40),
|
||||
Scalar(0),
|
||||
Scalar(0),
|
||||
Scalar(0),
|
||||
|
||||
Scalar(3) / Scalar(10),
|
||||
-Scalar(9) / Scalar(10),
|
||||
Scalar(6) / Scalar(5),
|
||||
Scalar(0),
|
||||
Scalar(0),
|
||||
|
||||
-Scalar(11) / Scalar(54),
|
||||
Scalar(5) / Scalar(2),
|
||||
-Scalar(70) / Scalar(27),
|
||||
Scalar(35) / Scalar(27),
|
||||
Scalar(0),
|
||||
|
||||
Scalar(1631) / Scalar(55296),
|
||||
Scalar(175) / Scalar(512),
|
||||
Scalar(575) / Scalar(13824),
|
||||
Scalar(44275) / Scalar(110592),
|
||||
Scalar(253) / Scalar(4096)
|
||||
};
|
||||
static Scalar c4[6] = {
|
||||
Scalar(2825) / Scalar(27648),
|
||||
Scalar(0),
|
||||
Scalar(18575) / Scalar(48384),
|
||||
Scalar(13525) / Scalar(55296),
|
||||
Scalar(277) / Scalar(14336),
|
||||
Scalar(1) / Scalar(4),
|
||||
};
|
||||
static Scalar c5[6] = {
|
||||
Scalar(37) / Scalar(378),
|
||||
Scalar(0),
|
||||
Scalar(250) / Scalar(621),
|
||||
Scalar(125) / Scalar(594),
|
||||
Scalar(0),
|
||||
Scalar(512) / Scalar(1771)
|
||||
};
|
||||
|
||||
CPPAD_ASSERT_KNOWN(
|
||||
M >= 1,
|
||||
"Error in Runge45: the number of steps is less than one"
|
||||
);
|
||||
CPPAD_ASSERT_KNOWN(
|
||||
e.size() == xi.size(),
|
||||
"Error in Runge45: size of e not equal to size of xi"
|
||||
);
|
||||
size_t i, j, k, m; // indices
|
||||
|
||||
size_t n = xi.size(); // number of components in X(t)
|
||||
Scalar ns = Scalar(int(M)); // number of steps as Scalar object
|
||||
Scalar h = (tf - ti) / ns; // step size
|
||||
Scalar zero_or_nan = Scalar(0); // zero (nan if Ode returns has a nan)
|
||||
for(i = 0; i < n; i++) // initialize e = 0
|
||||
e[i] = zero_or_nan;
|
||||
|
||||
// vectors used to store values returned by F
|
||||
Vector fh(6 * n), xtmp(n), ftmp(n), x4(n), x5(n), xf(n);
|
||||
|
||||
xf = xi; // initialize solution
|
||||
for(m = 0; m < M; m++)
|
||||
{ // time at beginning of this interval
|
||||
// (convert to int to avoid MS compiler warning)
|
||||
Scalar t = ti * (Scalar(int(M - m)) / ns)
|
||||
+ tf * (Scalar(int(m)) / ns);
|
||||
|
||||
// loop over integration steps
|
||||
x4 = x5 = xf; // start x4 and x5 at same point for each step
|
||||
for(j = 0; j < 6; j++)
|
||||
{ // loop over function evaluations for this step
|
||||
xtmp = xf; // location for next function evaluation
|
||||
for(k = 0; k < j; k++)
|
||||
{ // loop over previous function evaluations
|
||||
Scalar bjk = b[ (j-1) * 5 + k ];
|
||||
for(i = 0; i < n; i++)
|
||||
{ // loop over elements of x
|
||||
xtmp[i] += bjk * fh[i * 6 + k];
|
||||
}
|
||||
}
|
||||
// ftmp = F(t + a[j] * h, xtmp)
|
||||
F.Ode(t + a[j] * h, xtmp, ftmp);
|
||||
|
||||
// if ftmp has a nan, set zero_or_nan to nan
|
||||
for(i = 0; i < n; i++)
|
||||
zero_or_nan *= ftmp[i];
|
||||
|
||||
for(i = 0; i < n; i++)
|
||||
{ // loop over elements of x
|
||||
Scalar fhi = ftmp[i] * h;
|
||||
fh[i * 6 + j] = fhi;
|
||||
x4[i] += c4[j] * fhi;
|
||||
x5[i] += c5[j] * fhi;
|
||||
x5[i] += zero_or_nan;
|
||||
}
|
||||
}
|
||||
// accumulate error bound
|
||||
for(i = 0; i < n; i++)
|
||||
{ // cant use abs because cppad.hpp may not be included
|
||||
Scalar diff = x5[i] - x4[i];
|
||||
e[i] += fabs(diff);
|
||||
e[i] += zero_or_nan;
|
||||
}
|
||||
|
||||
// advance xf for this step using x5
|
||||
xf = x5;
|
||||
}
|
||||
return xf;
|
||||
}
|
||||
|
||||
} // End CppAD namespace
|
||||
|
||||
# endif
|
||||
@@ -0,0 +1,88 @@
|
||||
# ifndef CPPAD_UTILITY_SET_UNION_HPP
|
||||
# define CPPAD_UTILITY_SET_UNION_HPP
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-17 Bradley M. Bell
|
||||
|
||||
CppAD is distributed under multiple licenses. This distribution is under
|
||||
the terms of the
|
||||
Eclipse Public License Version 1.0.
|
||||
|
||||
A copy of this license is included in the COPYING file of this distribution.
|
||||
Please visit http://www.coin-or.org/CppAD/ for information on other licenses.
|
||||
-------------------------------------------------------------------------- */
|
||||
|
||||
/*
|
||||
$begin set_union$$
|
||||
$spell
|
||||
set
|
||||
const
|
||||
std
|
||||
$$
|
||||
|
||||
$section Union of Standard Sets$$
|
||||
|
||||
$head Syntax$$
|
||||
$icode%result% = set_union(%left%, %right%)%$$
|
||||
|
||||
$head Purpose$$
|
||||
This is a simplified (and restricted) interface to
|
||||
the $code std::union$$ operation.
|
||||
|
||||
$head Element$$
|
||||
This is the type of the elements of the sets.
|
||||
|
||||
$head left$$
|
||||
This argument has prototype
|
||||
$codei%
|
||||
const std::set<%Element%>& %left%
|
||||
%$$
|
||||
|
||||
$head right$$
|
||||
This argument has prototype
|
||||
$codei%
|
||||
const std::set<%Element%>& %right%
|
||||
%$$
|
||||
|
||||
$head result$$
|
||||
The return value has prototype
|
||||
$codei%
|
||||
std::set<%Element%>& %result%
|
||||
%$$
|
||||
It contains the union of $icode left$$ and $icode right$$.
|
||||
Note that C++11 detects that the return value is a temporary
|
||||
and uses it for the result instead of making a separate copy.
|
||||
|
||||
$children%
|
||||
example/utility/set_union.cpp
|
||||
%$$
|
||||
$head Example$$
|
||||
The file $cref set_union.cpp$$ contains an example and test of this
|
||||
operation. It returns true if the test passes and false otherwise.
|
||||
|
||||
|
||||
$end
|
||||
*/
|
||||
|
||||
# include <set>
|
||||
# include <algorithm>
|
||||
# include <iterator>
|
||||
|
||||
namespace CppAD {
|
||||
template <class Element>
|
||||
std::set<Element> set_union(
|
||||
const std::set<Element>& left ,
|
||||
const std::set<Element>& right )
|
||||
{ std::set<Element> result;
|
||||
std::set_union(
|
||||
left.begin() ,
|
||||
left.end() ,
|
||||
right.begin() ,
|
||||
right.end() ,
|
||||
std::inserter(result, result.begin())
|
||||
);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
# endif
|
||||
+348
@@ -0,0 +1,348 @@
|
||||
# ifndef CPPAD_UTILITY_SPARSE_RC_HPP
|
||||
# define CPPAD_UTILITY_SPARSE_RC_HPP
|
||||
/* --------------------------------------------------------------------------
|
||||
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-17 Bradley M. Bell
|
||||
|
||||
CppAD is distributed under multiple licenses. This distribution is under
|
||||
the terms of the
|
||||
Eclipse Public License Version 1.0.
|
||||
|
||||
A copy of this license is included in the COPYING file of this distribution.
|
||||
Please visit http://www.coin-or.org/CppAD/ for information on other licenses.
|
||||
-------------------------------------------------------------------------- */
|
||||
|
||||
/*
|
||||
$begin sparse_rc$$
|
||||
$spell
|
||||
CppAD
|
||||
const
|
||||
nnz
|
||||
cppad
|
||||
hpp
|
||||
rc
|
||||
nr
|
||||
nc
|
||||
resize
|
||||
$$
|
||||
$section Row and Column Index Sparsity Patterns$$
|
||||
|
||||
$head Syntax$$
|
||||
$codei%# include <cppad/utility/sparse_rc.hpp>
|
||||
%$$
|
||||
$codei%sparse_rc<%SizeVector%> %empty%
|
||||
%$$
|
||||
$codei%sparse_rc<%SizeVector%> %pattern%(%nr%, %nc%, %nnz%)
|
||||
%$$
|
||||
$codei%target% = %pattern%
|
||||
%$$
|
||||
$icode%resize%(%nr%, %nc%, %nnz%)
|
||||
%$$
|
||||
$icode%pattern%.set(%k%, %r%, %c%)
|
||||
%$$
|
||||
$icode%pattern%.nr()
|
||||
%$$
|
||||
$icode%pattern%.nc()
|
||||
%$$
|
||||
$icode%pattern%.nnz()
|
||||
%$$
|
||||
$codei%const %SizeVector%& %row%( %pattern%.row() )
|
||||
%$$
|
||||
$codei%const %SizeVector%& %col%( %pattern%.col() )
|
||||
%$$
|
||||
$icode%row_major% = %pattern%.row_major()
|
||||
%$$
|
||||
$icode%col_major% = %pattern%.col_major()
|
||||
%$$
|
||||
|
||||
$head SizeVector$$
|
||||
We use $icode SizeVector$$ to denote $cref SimpleVector$$ class
|
||||
$cref/with elements of type/SimpleVector/Elements of Specified Type/$$
|
||||
$code size$$.
|
||||
|
||||
$head empty$$
|
||||
This is an empty sparsity pattern. To be specific,
|
||||
the corresponding number of rows $icode nr$$,
|
||||
number of columns $icode nc$$,
|
||||
and number of possibly non-zero values $icode nnz$$,
|
||||
are all zero.
|
||||
|
||||
$head pattern$$
|
||||
This object is used to hold a sparsity pattern for a matrix.
|
||||
The sparsity $icode pattern$$ is $code const$$
|
||||
except during its constructor, $code resize$$, and $code set$$.
|
||||
|
||||
$head target$$
|
||||
The target of the assignment statement must have prototype
|
||||
$codei%
|
||||
sparse_rc<%SizeVector%> %target%
|
||||
%$$
|
||||
After this assignment statement, $icode target$$ is an independent copy
|
||||
of $icode pattern$$; i.e. it has all the same values as $icode pattern$$
|
||||
and changes to $icode target$$ do not affect $icode pattern$$.
|
||||
|
||||
$head nr$$
|
||||
This argument has prototype
|
||||
$codei%
|
||||
size_t %nr%
|
||||
%$$
|
||||
It specifies the number of rows in the sparsity pattern.
|
||||
The function call $code nr()$$ returns the value of $icode nr$$.
|
||||
|
||||
$head nc$$
|
||||
This argument has prototype
|
||||
$codei%
|
||||
size_t %nc%
|
||||
%$$
|
||||
It specifies the number of columns in the sparsity pattern.
|
||||
The function call $code nc()$$ returns the value of $icode nc$$.
|
||||
|
||||
$head nnz$$
|
||||
This argument has prototype
|
||||
$codei%
|
||||
size_t %nnz%
|
||||
%$$
|
||||
It specifies the number of possibly non-zero
|
||||
index pairs in the sparsity pattern.
|
||||
The function call $code nnz()$$ returns the value of $icode nnz$$.
|
||||
|
||||
$head resize$$
|
||||
The current sparsity pattern is lost and a new one is started
|
||||
with the specified parameters. The elements in the $icode row$$
|
||||
and $icode col$$ vectors should be assigned using $code set$$.
|
||||
|
||||
$head set$$
|
||||
This function sets the values
|
||||
$codei%
|
||||
%row%[%k%] = %r%
|
||||
%col%[%k%] = %c%
|
||||
%$$
|
||||
|
||||
$subhead k$$
|
||||
This argument has type
|
||||
$codei%
|
||||
size_t %k%
|
||||
%$$
|
||||
and must be less than $icode nnz$$.
|
||||
|
||||
$subhead r$$
|
||||
This argument has type
|
||||
$codei%
|
||||
size_t %r%
|
||||
%$$
|
||||
It specifies the value assigned to $icode%row%[%k%]%$$ and must
|
||||
be less than $icode nr$$.
|
||||
|
||||
$subhead c$$
|
||||
This argument has type
|
||||
$codei%
|
||||
size_t %c%
|
||||
%$$
|
||||
It specifies the value assigned to $icode%col%[%k%]%$$ and must
|
||||
be less than $icode nc$$.
|
||||
|
||||
$head row$$
|
||||
This vector has size $icode nnz$$ and
|
||||
$icode%row%[%k%]%$$
|
||||
is the row index of the $th k$$ possibly non-zero
|
||||
index pair in the sparsity pattern.
|
||||
|
||||
$head col$$
|
||||
This vector has size $icode nnz$$ and
|
||||
$icode%col%[%k%]%$$ is the column index of the $th k$$ possibly non-zero
|
||||
index pair in the sparsity pattern.
|
||||
|
||||
$head row_major$$
|
||||
This vector has prototype
|
||||
$codei%
|
||||
%SizeVector% %row_major%
|
||||
%$$
|
||||
and its size $icode nnz$$.
|
||||
It sorts the sparsity pattern in row-major order.
|
||||
To be specific,
|
||||
$codei%
|
||||
%col%[ %row_major%[%k%] ] <= %col%[ %row_major%[%k%+1] ]
|
||||
%$$
|
||||
and if $icode%col%[ %row_major%[%k%] ] == %col%[ %row_major%[%k%+1] ]%$$,
|
||||
$codei%
|
||||
%row%[ %row_major%[%k%] ] < %row%[ %row_major%[%k%+1] ]
|
||||
%$$
|
||||
This routine generates an assert if there are two entries with the same
|
||||
row and column values (if $code NDEBUG$$ is not defined).
|
||||
|
||||
$head col_major$$
|
||||
This vector has prototype
|
||||
$codei%
|
||||
%SizeVector% %col_major%
|
||||
%$$
|
||||
and its size $icode nnz$$.
|
||||
It sorts the sparsity pattern in column-major order.
|
||||
To be specific,
|
||||
$codei%
|
||||
%row%[ %col_major%[%k%] ] <= %row%[ %col_major%[%k%+1] ]
|
||||
%$$
|
||||
and if $icode%row%[ %col_major%[%k%] ] == %row%[ %col_major%[%k%+1] ]%$$,
|
||||
$codei%
|
||||
%col%[ %col_major%[%k%] ] < %col%[ %col_major%[%k%+1] ]
|
||||
%$$
|
||||
This routine generates an assert if there are two entries with the same
|
||||
row and column values (if $code NDEBUG$$ is not defined).
|
||||
|
||||
$children%
|
||||
example/utility/sparse_rc.cpp
|
||||
%$$
|
||||
$head Example$$
|
||||
The file $cref sparse_rc.cpp$$
|
||||
contains an example and test of this class.
|
||||
It returns true if it succeeds and false otherwise.
|
||||
|
||||
$end
|
||||
*/
|
||||
/*!
|
||||
\file sparse_rc.hpp
|
||||
A Matrix sparsity pattern class.
|
||||
*/
|
||||
# include <cstddef> // for size_t
|
||||
# include <cppad/core/cppad_assert.hpp> // for CPPAD_ASSERT
|
||||
# include <cppad/utility/index_sort.hpp> // for row and column major ordering
|
||||
|
||||
namespace CppAD { // BEGIN CPPAD_NAMESPACE
|
||||
|
||||
/// sparsity pattern for a matrix with indices of type size_t
|
||||
template <class SizeVector>
|
||||
class sparse_rc {
|
||||
private:
|
||||
/// number of rows in the sparsity pattern
|
||||
size_t nr_;
|
||||
/// number of columns in the sparsity pattern
|
||||
size_t nc_;
|
||||
/// number of possibly non-zero index pairs
|
||||
size_t nnz_;
|
||||
/// row_[k] is the row index for the k-th possibly non-zero entry
|
||||
SizeVector row_;
|
||||
/// col_[k] is the column index for the k-th possibly non-zero entry
|
||||
SizeVector col_;
|
||||
public:
|
||||
/// default constructor
|
||||
/// Eigen vector is ambiguous for row_(0), col_(0) so use default ctor
|
||||
sparse_rc(void)
|
||||
: nr_(0), nc_(0), nnz_(0)
|
||||
{ }
|
||||
/// sizing constructor
|
||||
/// Eigen vector is ambiguous for row_(0), col_(0) so use default ctor
|
||||
sparse_rc(size_t nr, size_t nc, size_t nnz)
|
||||
: nr_(nr), nc_(nc), nnz_(nnz)
|
||||
{ row_.resize(nnz);
|
||||
col_.resize(nnz);
|
||||
}
|
||||
/// copy constructor
|
||||
sparse_rc(const sparse_rc& other)
|
||||
:
|
||||
nr_(other.nr_) ,
|
||||
nc_(other.nc_) ,
|
||||
nnz_(other.nnz_) ,
|
||||
row_(other.row_) ,
|
||||
col_(other.col_)
|
||||
{ }
|
||||
/// assignment
|
||||
void operator=(const sparse_rc& pattern)
|
||||
{ nr_ = pattern.nr_;
|
||||
nc_ = pattern.nc_;
|
||||
nnz_ = pattern.nnz_;
|
||||
// simple vector assignment requires vectors to have same size
|
||||
row_.resize(nnz_);
|
||||
col_.resize(nnz_);
|
||||
row_ = pattern.row_;
|
||||
col_ = pattern.col_;
|
||||
}
|
||||
/// resize
|
||||
void resize(size_t nr, size_t nc, size_t nnz)
|
||||
{ nr_ = nr;
|
||||
nc_ = nc;
|
||||
nnz_ = nnz;
|
||||
row_.resize(nnz);
|
||||
col_.resize(nnz);
|
||||
}
|
||||
/// set row and column for a possibly non-zero element
|
||||
void set(size_t k, size_t r, size_t c)
|
||||
{ CPPAD_ASSERT_KNOWN(
|
||||
k < nnz_,
|
||||
"The index k is not less than nnz in sparse_rc::set"
|
||||
);
|
||||
CPPAD_ASSERT_KNOWN(
|
||||
r < nr_,
|
||||
"The index r is not less than nr in sparse_rc::set"
|
||||
);
|
||||
CPPAD_ASSERT_KNOWN(
|
||||
c < nc_,
|
||||
"The index c is to not less than nc in sparse_rc::set"
|
||||
);
|
||||
row_[k] = r;
|
||||
col_[k] = c;
|
||||
//
|
||||
}
|
||||
/// number of rows in matrix
|
||||
size_t nr(void) const
|
||||
{ return nr_; }
|
||||
/// number of columns in matrix
|
||||
size_t nc(void) const
|
||||
{ return nc_; }
|
||||
/// number of possibly non-zero elements in matrix
|
||||
size_t nnz(void) const
|
||||
{ return nnz_; }
|
||||
/// row indices
|
||||
const SizeVector& row(void) const
|
||||
{ return row_; }
|
||||
/// column indices
|
||||
const SizeVector& col(void) const
|
||||
{ return col_; }
|
||||
/// row-major order
|
||||
SizeVector row_major(void) const
|
||||
{ SizeVector keys(nnz_), row_major(nnz_);
|
||||
for(size_t k = 0; k < nnz_; k++)
|
||||
{ CPPAD_ASSERT_UNKNOWN( row_[k] < nr_ );
|
||||
keys[k] = row_[k] * nc_ + col_[k];
|
||||
}
|
||||
index_sort(keys, row_major);
|
||||
# ifndef NDEBUG
|
||||
for(size_t ell = 0; ell + 1 < nnz_; ell++)
|
||||
{ size_t k = row_major[ ell ];
|
||||
size_t kp = row_major[ ell + 1 ];
|
||||
CPPAD_ASSERT_KNOWN(
|
||||
row_[k] != row_[kp] || col_[k] != col_[kp],
|
||||
"sparse_rc: row_major: duplicate entry in this pattern"
|
||||
);
|
||||
CPPAD_ASSERT_UNKNOWN(
|
||||
row_[k]<row_[kp] || (row_[k]==row_[kp] && col_[k]<col_[kp])
|
||||
);
|
||||
}
|
||||
# endif
|
||||
return row_major;
|
||||
}
|
||||
/// column-major indices
|
||||
SizeVector col_major(void) const
|
||||
{ SizeVector keys(nnz_), col_major(nnz_);
|
||||
for(size_t k = 0; k < nnz_; k++)
|
||||
{ CPPAD_ASSERT_UNKNOWN( col_[k] < nc_ );
|
||||
keys[k] = col_[k] * nr_ + row_[k];
|
||||
}
|
||||
index_sort(keys, col_major);
|
||||
# ifndef NDEBUG
|
||||
for(size_t ell = 0; ell + 1 < nnz_; ell++)
|
||||
{ size_t k = col_major[ ell ];
|
||||
size_t kp = col_major[ ell + 1 ];
|
||||
CPPAD_ASSERT_KNOWN(
|
||||
col_[k] != col_[kp] || row_[k] != row_[kp],
|
||||
"sparse_rc: col_major: duplicate entry in this pattern"
|
||||
);
|
||||
CPPAD_ASSERT_UNKNOWN(
|
||||
col_[k]<col_[kp] || (col_[k]==col_[kp] && row_[k]<row_[kp])
|
||||
);
|
||||
}
|
||||
# endif
|
||||
return col_major;
|
||||
}
|
||||
};
|
||||
|
||||
} // END_CPPAD_NAMESPACE
|
||||
|
||||
# endif
|
||||
+275
@@ -0,0 +1,275 @@
|
||||
# ifndef CPPAD_UTILITY_SPARSE_RCV_HPP
|
||||
# define CPPAD_UTILITY_SPARSE_RCV_HPP
|
||||
/* --------------------------------------------------------------------------
|
||||
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-17 Bradley M. Bell
|
||||
|
||||
CppAD is distributed under multiple licenses. This distribution is under
|
||||
the terms of the
|
||||
Eclipse Public License Version 1.0.
|
||||
|
||||
A copy of this license is included in the COPYING file of this distribution.
|
||||
Please visit http://www.coin-or.org/CppAD/ for information on other licenses.
|
||||
-------------------------------------------------------------------------- */
|
||||
|
||||
/*
|
||||
------------------------------------------------------------------------------
|
||||
$begin sparse_rcv$$
|
||||
$spell
|
||||
CppAD
|
||||
nr
|
||||
nc
|
||||
const
|
||||
var
|
||||
nnz
|
||||
cppad
|
||||
hpp
|
||||
rcv
|
||||
rc
|
||||
$$
|
||||
$section Sparse Matrix Row, Column, Value Representation$$
|
||||
|
||||
$head Syntax$$
|
||||
$codei%# include <cppad/utility/sparse_rcv.hpp>
|
||||
%$$
|
||||
$codei%sparse_rcv<%SizeVector%, %ValueVector%> %empty%
|
||||
%$$
|
||||
$codei%sparse_rcv<%SizeVector%, %ValueVector%> %matrix%(%pattern%)
|
||||
%$$
|
||||
$codei%target% = %matrix%
|
||||
%$$
|
||||
$icode%matrix%.set(%k%, %v%)
|
||||
%$$
|
||||
$icode%nr% = %matrix%.nr()
|
||||
%$$
|
||||
$icode%nc% = %matrix%.nc()
|
||||
%$$
|
||||
$icode%nnz% = %matrix%.nnz()
|
||||
%$$
|
||||
$codei%const %SizeVector%& %row%( %matrix%.row() )
|
||||
%$$
|
||||
$codei%const %SizeVector%& %col%( %matrix%.col() )
|
||||
%$$
|
||||
$codei%const %ValueVector%& %val%( %matrix%.val() )
|
||||
%$$
|
||||
$icode%row_major% = %matrix%.row_major()
|
||||
%$$
|
||||
$icode%col_major% = %matrix%.col_major()
|
||||
%$$
|
||||
|
||||
$head SizeVector$$
|
||||
We use $cref/SizeVector/sparse_rc/SizeVector/$$ to denote the
|
||||
$cref SimpleVector$$ class corresponding to $icode pattern$$.
|
||||
|
||||
$head ValueVector$$
|
||||
We use $icode ValueVector$$ to denote the
|
||||
$cref SimpleVector$$ class corresponding to $icode val$$.
|
||||
|
||||
$head empty$$
|
||||
This is an empty sparse matrix object. To be specific,
|
||||
the corresponding number of rows $icode nr$$,
|
||||
number of columns $icode nc$$,
|
||||
and number of possibly non-zero values $icode nnz$$,
|
||||
are all zero.
|
||||
|
||||
|
||||
$head pattern$$
|
||||
This argument has prototype
|
||||
$codei%
|
||||
const sparse_rc<%SizeVector%>& %pattern%
|
||||
%$$
|
||||
It specifies the number of rows, number of columns and
|
||||
the possibly non-zero entries in the $icode matrix$$.
|
||||
|
||||
$head matrix$$
|
||||
This is a sparse matrix object with the sparsity specified by $icode pattern$$.
|
||||
Only the $icode val$$ vector can be changed. All other values returned by
|
||||
$icode matrix$$ are fixed during the constructor and constant there after.
|
||||
The $icode val$$ vector is only changed by the constructor
|
||||
and the $code set$$ function.
|
||||
There is one exception to the rule, where $icode matrix$$ corresponds
|
||||
to $icode target$$ for an assignment statement.
|
||||
|
||||
$head target$$
|
||||
The target of the assignment statement must have prototype
|
||||
$codei%
|
||||
sparse_rcv<%SizeVector%, %ValueVector%> %target%
|
||||
%$$
|
||||
After this assignment statement, $icode target$$ is an independent copy
|
||||
of $icode matrix$$; i.e. it has all the same values as $icode matrix$$
|
||||
and changes to $icode target$$ do not affect $icode matrix$$.
|
||||
|
||||
$head nr$$
|
||||
This return value has prototype
|
||||
$codei%
|
||||
size_t %nr%
|
||||
%$$
|
||||
and is the number of rows in $icode matrix$$.
|
||||
|
||||
$head nc$$
|
||||
This argument and return value has prototype
|
||||
$codei%
|
||||
size_t %nc%
|
||||
%$$
|
||||
and is the number of columns in $icode matrix$$.
|
||||
|
||||
$head nnz$$
|
||||
We use the notation $icode nnz$$ to denote the number of
|
||||
possibly non-zero entries in $icode matrix$$.
|
||||
|
||||
$head set$$
|
||||
This function sets the value
|
||||
$codei%
|
||||
%val%[%k%] = %v%
|
||||
%$$
|
||||
|
||||
$subhead k$$
|
||||
This argument has type
|
||||
$codei%
|
||||
size_t %k%
|
||||
%$$
|
||||
and must be less than $icode nnz$$.
|
||||
|
||||
$subhead v$$
|
||||
This argument has type
|
||||
$codei%
|
||||
const %ValueVector%::value_type& %v%
|
||||
%$$
|
||||
It specifies the value assigned to $icode%val%[%k%]%$$.
|
||||
|
||||
|
||||
$head row$$
|
||||
This vector has size $icode nnz$$ and
|
||||
$icode%row%[%k%]%$$
|
||||
is the row index of the $th k$$ possibly non-zero
|
||||
element in $icode matrix$$.
|
||||
|
||||
$head col$$
|
||||
This vector has size $icode nnz$$ and
|
||||
$icode%col[%k%]%$$ is the column index of the $th k$$ possibly non-zero
|
||||
element in $icode matrix$$
|
||||
|
||||
$head val$$
|
||||
This vector has size $icode nnz$$ and
|
||||
$icode%val[%k%]%$$ is value of the $th k$$ possibly non-zero entry
|
||||
in the sparse matrix (the value may be zero).
|
||||
|
||||
$head row_major$$
|
||||
This vector has prototype
|
||||
$codei%
|
||||
%SizeVector% %row_major%
|
||||
%$$
|
||||
and its size $icode nnz$$.
|
||||
It sorts the sparsity pattern in row-major order.
|
||||
To be specific,
|
||||
$codei%
|
||||
%col%[ %row_major%[%k%] ] <= %col%[ %row_major%[%k%+1] ]
|
||||
%$$
|
||||
and if $icode%col%[ %row_major%[%k%] ] == %col%[ %row_major%[%k%+1] ]%$$,
|
||||
$codei%
|
||||
%row%[ %row_major%[%k%] ] < %row%[ %row_major%[%k%+1] ]
|
||||
%$$
|
||||
This routine generates an assert if there are two entries with the same
|
||||
row and column values (if $code NDEBUG$$ is not defined).
|
||||
|
||||
$head col_major$$
|
||||
This vector has prototype
|
||||
$codei%
|
||||
%SizeVector% %col_major%
|
||||
%$$
|
||||
and its size $icode nnz$$.
|
||||
It sorts the sparsity pattern in column-major order.
|
||||
To be specific,
|
||||
$codei%
|
||||
%row%[ %col_major%[%k%] ] <= %row%[ %col_major%[%k%+1] ]
|
||||
%$$
|
||||
and if $icode%row%[ %col_major%[%k%] ] == %row%[ %col_major%[%k%+1] ]%$$,
|
||||
$codei%
|
||||
%col%[ %col_major%[%k%] ] < %col%[ %col_major%[%k%+1] ]
|
||||
%$$
|
||||
This routine generates an assert if there are two entries with the same
|
||||
row and column values (if $code NDEBUG$$ is not defined).
|
||||
|
||||
$children%
|
||||
example/utility/sparse_rcv.cpp
|
||||
%$$
|
||||
$head Example$$
|
||||
The file $cref sparse_rcv.cpp$$
|
||||
contains an example and test of this class.
|
||||
It returns true if it succeeds and false otherwise.
|
||||
|
||||
$end
|
||||
*/
|
||||
/*!
|
||||
\file sparse_rcv.hpp
|
||||
A sparse matrix class.
|
||||
*/
|
||||
# include <cppad/utility/sparse_rc.hpp>
|
||||
|
||||
namespace CppAD { // BEGIN CPPAD_NAMESPACE
|
||||
|
||||
/// Sparse matrices with elements of type Scalar
|
||||
template <class SizeVector, class ValueVector>
|
||||
class sparse_rcv {
|
||||
private:
|
||||
/// sparsity pattern
|
||||
sparse_rc<SizeVector> pattern_;
|
||||
/// value_type
|
||||
typedef typename ValueVector::value_type value_type;
|
||||
/// val_[k] is the value for the k-th possibly non-zero entry in the matrix
|
||||
ValueVector val_;
|
||||
public:
|
||||
// ------------------------------------------------------------------------
|
||||
/// default constructor
|
||||
sparse_rcv(void)
|
||||
: pattern_(0, 0, 0), val_(0)
|
||||
{ }
|
||||
/// constructor
|
||||
sparse_rcv(const sparse_rc<SizeVector>& pattern )
|
||||
:
|
||||
pattern_(pattern) ,
|
||||
val_(pattern_.nnz())
|
||||
{ }
|
||||
/// assignment
|
||||
void operator=(const sparse_rcv& matrix)
|
||||
{ pattern_ = matrix.pattern_;
|
||||
// simple vector assignment requires vectors to have same size
|
||||
val_.resize( matrix.nnz() );
|
||||
val_ = matrix.val();
|
||||
}
|
||||
// ------------------------------------------------------------------------
|
||||
void set(size_t k, const value_type& v)
|
||||
{ CPPAD_ASSERT_KNOWN(
|
||||
pattern_.nnz(),
|
||||
"The index k is not less than nnz in sparse_rcv::set"
|
||||
);
|
||||
val_[k] = v;
|
||||
}
|
||||
/// number of rows in matrix
|
||||
size_t nr(void) const
|
||||
{ return pattern_.nr(); }
|
||||
/// number of columns in matrix
|
||||
size_t nc(void) const
|
||||
{ return pattern_.nc(); }
|
||||
/// number of possibly non-zero elements in matrix
|
||||
size_t nnz(void) const
|
||||
{ return pattern_.nnz(); }
|
||||
/// row indices
|
||||
const SizeVector& row(void) const
|
||||
{ return pattern_.row(); }
|
||||
/// column indices
|
||||
const SizeVector& col(void) const
|
||||
{ return pattern_.col(); }
|
||||
/// value for possibly non-zero elements
|
||||
const ValueVector& val(void) const
|
||||
{ return val_; }
|
||||
/// row-major order
|
||||
SizeVector row_major(void) const
|
||||
{ return pattern_.row_major(); }
|
||||
/// column-major indices
|
||||
SizeVector col_major(void) const
|
||||
{ return pattern_.col_major(); }
|
||||
};
|
||||
|
||||
} // END_CPPAD_NAMESPACE
|
||||
|
||||
# endif
|
||||
+472
@@ -0,0 +1,472 @@
|
||||
# ifndef CPPAD_UTILITY_SPEED_TEST_HPP
|
||||
# define CPPAD_UTILITY_SPEED_TEST_HPP
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-17 Bradley M. Bell
|
||||
|
||||
CppAD is distributed under multiple licenses. This distribution is under
|
||||
the terms of the
|
||||
Eclipse Public License Version 1.0.
|
||||
|
||||
A copy of this license is included in the COPYING file of this distribution.
|
||||
Please visit http://www.coin-or.org/CppAD/ for information on other licenses.
|
||||
-------------------------------------------------------------------------- */
|
||||
|
||||
/*
|
||||
$begin speed_test$$
|
||||
$spell
|
||||
gettimeofday
|
||||
vec
|
||||
cppad.hpp
|
||||
Microsoft
|
||||
namespace
|
||||
std
|
||||
const
|
||||
cout
|
||||
ctime
|
||||
ifdef
|
||||
const
|
||||
endif
|
||||
cpp
|
||||
$$
|
||||
|
||||
|
||||
$section Run One Speed Test and Return Results$$
|
||||
$mindex speed_test$$
|
||||
|
||||
$head Syntax$$
|
||||
$codei%# include <cppad/utility/speed_test.hpp>
|
||||
%$$
|
||||
$icode%rate_vec% = speed_test(%test%, %size_vec%, %time_min%)%$$
|
||||
|
||||
$head Purpose$$
|
||||
The $code speed_test$$ function executes a speed test
|
||||
for various sized problems
|
||||
and reports the rate of execution.
|
||||
|
||||
$head Motivation$$
|
||||
It is important to separate small calculation units
|
||||
and test them individually.
|
||||
This way individual changes can be tested in the context of the
|
||||
routine that they are in.
|
||||
On many machines, accurate timing of a very short execution
|
||||
sequences is not possible.
|
||||
In addition,
|
||||
there may be set up and tear down time for a test that
|
||||
we do not really want included in the timing.
|
||||
For this reason $code speed_test$$
|
||||
automatically determines how many times to
|
||||
repeat the section of the test that we wish to time.
|
||||
|
||||
|
||||
$head Include$$
|
||||
The file $code cppad/speed_test.hpp$$ defines the
|
||||
$code speed_test$$ function.
|
||||
This file is included by $code cppad/cppad.hpp$$
|
||||
and it can also be included separately with out the rest of
|
||||
the $code CppAD$$ routines.
|
||||
|
||||
$head Vector$$
|
||||
We use $icode Vector$$ to denote a
|
||||
$cref/simple vector class/SimpleVector/$$ with elements
|
||||
of type $code size_t$$.
|
||||
|
||||
$head test$$
|
||||
The $code speed_test$$ argument $icode test$$ is a function with the syntax
|
||||
$codei%
|
||||
%test%(%size%, %repeat%)
|
||||
%$$
|
||||
and its return value is $code void$$.
|
||||
|
||||
$subhead size$$
|
||||
The $icode test$$ argument $icode size$$ has prototype
|
||||
$codei%
|
||||
size_t %size%
|
||||
%$$
|
||||
It specifies the size for this test.
|
||||
|
||||
$subhead repeat$$
|
||||
The $icode test$$ argument $icode repeat$$ has prototype
|
||||
$codei%
|
||||
size_t %repeat%
|
||||
%$$
|
||||
It specifies the number of times to repeat the test.
|
||||
|
||||
$head size_vec$$
|
||||
The $code speed_test$$ argument $icode size_vec$$ has prototype
|
||||
$codei%
|
||||
const %Vector%& %size_vec%
|
||||
%$$
|
||||
This vector determines the size for each of the tests problems.
|
||||
|
||||
$head time_min$$
|
||||
The argument $icode time_min$$ has prototype
|
||||
$codei%
|
||||
double %time_min%
|
||||
%$$
|
||||
It specifies the minimum amount of time in seconds
|
||||
that the $icode test$$ routine should take.
|
||||
The $icode repeat$$ argument to $icode test$$ is increased
|
||||
until this amount of execution time is reached.
|
||||
|
||||
$head rate_vec$$
|
||||
The return value $icode rate_vec$$ has prototype
|
||||
$codei%
|
||||
%Vector%& %rate_vec%
|
||||
%$$
|
||||
We use $latex n$$ to denote its size which is the same as
|
||||
the vector $icode size_vec$$.
|
||||
For $latex i = 0 , \ldots , n-1$$,
|
||||
$codei%
|
||||
%rate_vec%[%i%]
|
||||
%$$
|
||||
is the ratio of $icode repeat$$ divided by time in seconds
|
||||
for the problem with size $icode%size_vec%[%i%]%$$.
|
||||
|
||||
$head Timing$$
|
||||
If your system supports the unix $code gettimeofday$$ function,
|
||||
it will be used to measure time.
|
||||
Otherwise,
|
||||
time is measured by the difference in
|
||||
$codep
|
||||
(double) clock() / (double) CLOCKS_PER_SEC
|
||||
$$
|
||||
in the context of the standard $code <ctime>$$ definitions.
|
||||
|
||||
$children%
|
||||
speed/example/speed_test.cpp
|
||||
%$$
|
||||
$head Example$$
|
||||
The routine $cref speed_test.cpp$$ is an example and test
|
||||
of $code speed_test$$.
|
||||
|
||||
$end
|
||||
-----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
# include <cstddef>
|
||||
# include <cmath>
|
||||
|
||||
# include <cppad/utility/check_simple_vector.hpp>
|
||||
# include <cppad/utility/elapsed_seconds.hpp>
|
||||
|
||||
|
||||
namespace CppAD { // BEGIN CppAD namespace
|
||||
|
||||
// implemented as an inline so that can include in multiple link modules
|
||||
// with this same file
|
||||
template <class Vector>
|
||||
inline Vector speed_test(
|
||||
void test(size_t size, size_t repeat),
|
||||
const Vector& size_vec ,
|
||||
double time_min )
|
||||
{
|
||||
// check that size_vec is a simple vector with size_t elements
|
||||
CheckSimpleVector<size_t, Vector>();
|
||||
|
||||
size_t n = size_vec.size();
|
||||
Vector rate_vec(n);
|
||||
size_t i;
|
||||
for(i = 0; i < n; i++)
|
||||
{ size_t size = size_vec[i];
|
||||
size_t repeat = 1;
|
||||
double s0 = elapsed_seconds();
|
||||
double s1 = elapsed_seconds();
|
||||
while( s1 - s0 < time_min )
|
||||
{ repeat = 2 * repeat;
|
||||
s0 = elapsed_seconds();
|
||||
test(size, repeat);
|
||||
s1 = elapsed_seconds();
|
||||
}
|
||||
double rate = .5 + double(repeat) / (s1 - s0);
|
||||
// first convert to float to avoid warning with g++ -Wconversion
|
||||
rate_vec[i] = static_cast<size_t>( static_cast<float>(rate) );
|
||||
}
|
||||
return rate_vec;
|
||||
}
|
||||
|
||||
} // END CppAD namespace
|
||||
|
||||
/*
|
||||
$begin SpeedTest$$
|
||||
$spell
|
||||
cppad.hpp
|
||||
Microsoft
|
||||
namespace
|
||||
std
|
||||
const
|
||||
cout
|
||||
ctime
|
||||
ifdef
|
||||
const
|
||||
endif
|
||||
cpp
|
||||
$$
|
||||
|
||||
|
||||
$section Run One Speed Test and Print Results$$
|
||||
$mindex SpeedTest$$
|
||||
|
||||
$head Syntax$$
|
||||
|
||||
$codei%# include <cppad/utility/speed_test.hpp>
|
||||
%$$
|
||||
$codei%SpeedTest(%Test%, %first%, %inc%, %last%)%$$
|
||||
|
||||
|
||||
$head Purpose$$
|
||||
The $code SpeedTest$$ function executes a speed test
|
||||
for various sized problems
|
||||
and reports the results on standard output; i.e. $code std::cout$$.
|
||||
The size of each test problem is included in its report
|
||||
(unless $icode first$$ is equal to $icode last$$).
|
||||
|
||||
$head Motivation$$
|
||||
It is important to separate small calculation units
|
||||
and test them individually.
|
||||
This way individual changes can be tested in the context of the
|
||||
routine that they are in.
|
||||
On many machines, accurate timing of a very short execution
|
||||
sequences is not possible.
|
||||
In addition,
|
||||
there may be set up time for a test that
|
||||
we do not really want included in the timing.
|
||||
For this reason $code SpeedTest$$
|
||||
automatically determines how many times to
|
||||
repeat the section of the test that we wish to time.
|
||||
|
||||
|
||||
$head Include$$
|
||||
The file $code speed_test.hpp$$ contains the
|
||||
$code SpeedTest$$ function.
|
||||
This file is included by $code cppad/cppad.hpp$$
|
||||
but it can also be included separately with out the rest of
|
||||
the $code CppAD$$ routines.
|
||||
|
||||
$head Test$$
|
||||
The $code SpeedTest$$ argument $icode Test$$ is a function with the syntax
|
||||
$codei%
|
||||
%name% = %Test%(%size%, %repeat%)
|
||||
%$$
|
||||
|
||||
$subhead size$$
|
||||
The $icode Test$$ argument $icode size$$ has prototype
|
||||
$codei%
|
||||
size_t %size%
|
||||
%$$
|
||||
It specifies the size for this test.
|
||||
|
||||
$subhead repeat$$
|
||||
The $icode Test$$ argument $icode repeat$$ has prototype
|
||||
$codei%
|
||||
size_t %repeat%
|
||||
%$$
|
||||
It specifies the number of times to repeat the test.
|
||||
|
||||
$subhead name$$
|
||||
The $icode Test$$ result $icode name$$ has prototype
|
||||
$codei%
|
||||
std::string %name%
|
||||
%$$
|
||||
The results for this test are reported on $code std::cout$$
|
||||
with $icode name$$ as an identifier for the test.
|
||||
It is assumed that,
|
||||
for the duration of this call to $code SpeedTest$$,
|
||||
$icode Test$$ will always return
|
||||
the same value for $icode name$$.
|
||||
If $icode name$$ is the empty string,
|
||||
no test name is reported by $code SpeedTest$$.
|
||||
|
||||
$head first$$
|
||||
The $code SpeedTest$$ argument $icode first$$ has prototype
|
||||
$codei%
|
||||
size_t %first%
|
||||
%$$
|
||||
It specifies the size of the first test problem reported by this call to
|
||||
$code SpeedTest$$.
|
||||
|
||||
$head last$$
|
||||
The $code SpeedTest$$ argument $icode last$$ has prototype
|
||||
$codei%
|
||||
size_t %last%
|
||||
%$$
|
||||
It specifies the size of the last test problem reported by this call to
|
||||
$code SpeedTest$$.
|
||||
|
||||
$head inc$$
|
||||
The $code SpeedTest$$ argument $icode inc$$ has prototype
|
||||
$codei%
|
||||
int %inc%
|
||||
%$$
|
||||
It specifies the increment between problem sizes; i.e.,
|
||||
all values of $icode size$$ in calls to $icode Test$$ are given by
|
||||
$codei%
|
||||
%size% = %first% + %j% * %inc%
|
||||
%$$
|
||||
where $icode j$$ is a positive integer.
|
||||
The increment can be positive or negative but it cannot be zero.
|
||||
The values $icode first$$, $icode last$$ and $icode inc$$ must
|
||||
satisfy the relation
|
||||
$latex \[
|
||||
inc * ( last - first ) \geq 0
|
||||
\] $$
|
||||
|
||||
$head rate$$
|
||||
The value displayed in the $code rate$$ column on $code std::cout$$
|
||||
is defined as the value of $icode repeat$$ divided by the
|
||||
corresponding elapsed execution time in seconds.
|
||||
The elapsed execution time is measured by the difference in
|
||||
$codep
|
||||
(double) clock() / (double) CLOCKS_PER_SEC
|
||||
$$
|
||||
in the context of the standard $code <ctime>$$ definitions.
|
||||
|
||||
|
||||
$head Errors$$
|
||||
If one of the restrictions above is violated,
|
||||
the CppAD error handler is used to report the error.
|
||||
You can redefine this action using the instructions in
|
||||
$cref ErrorHandler$$
|
||||
|
||||
$head Example$$
|
||||
$children%
|
||||
speed/example/speed_program.cpp
|
||||
%$$
|
||||
The program $cref speed_program.cpp$$ is an example usage
|
||||
of $code SpeedTest$$.
|
||||
|
||||
$end
|
||||
-----------------------------------------------------------------------
|
||||
*/
|
||||
// BEGIN C++
|
||||
|
||||
|
||||
# include <string>
|
||||
# include <iostream>
|
||||
# include <iomanip>
|
||||
# include <cppad/core/cppad_assert.hpp>
|
||||
|
||||
namespace CppAD { // BEGIN CppAD namespace
|
||||
|
||||
inline void SpeedTestNdigit(size_t value, size_t &ndigit, size_t &pow10)
|
||||
{ pow10 = 10;
|
||||
ndigit = 1;
|
||||
while( pow10 <= value )
|
||||
{ pow10 *= 10;
|
||||
ndigit += 1;
|
||||
}
|
||||
}
|
||||
|
||||
// implemented as an inline so that can include in multiple link modules
|
||||
// with this same file
|
||||
inline void SpeedTest(
|
||||
std::string Test(size_t size, size_t repeat),
|
||||
size_t first,
|
||||
int inc,
|
||||
size_t last
|
||||
)
|
||||
{
|
||||
|
||||
using std::cout;
|
||||
using std::endl;
|
||||
|
||||
size_t size;
|
||||
size_t repeat;
|
||||
size_t rate;
|
||||
size_t digit;
|
||||
size_t ndigit;
|
||||
size_t pow10;
|
||||
size_t maxSize;
|
||||
size_t maxSizeDigit;
|
||||
|
||||
double s0;
|
||||
double s1;
|
||||
|
||||
std::string name;
|
||||
|
||||
CPPAD_ASSERT_KNOWN(
|
||||
inc != 0 && first != 0 && last != 0,
|
||||
"inc, first, or last is zero in call to SpeedTest"
|
||||
);
|
||||
CPPAD_ASSERT_KNOWN(
|
||||
(inc > 0 && first <= last) || (inc < 0 && first >= last),
|
||||
"SpeedTest: increment is positive and first > last or "
|
||||
"increment is negative and first < last"
|
||||
);
|
||||
|
||||
// compute maxSize
|
||||
maxSize = size = first;
|
||||
while( (inc > 0 && size <= last) || (inc < 0 && size >= last) )
|
||||
{
|
||||
if( size > maxSize )
|
||||
maxSize = size;
|
||||
|
||||
// next size
|
||||
if( ((int) size) + inc > 0 )
|
||||
size += inc;
|
||||
else size = 0;
|
||||
}
|
||||
SpeedTestNdigit(maxSize, maxSizeDigit, pow10);
|
||||
|
||||
size = first;
|
||||
while( (inc > 0 && size <= last) || (inc < 0 && size >= last) )
|
||||
{
|
||||
repeat = 1;
|
||||
s0 = elapsed_seconds();
|
||||
s1 = elapsed_seconds();
|
||||
while( s1 - s0 < 1. )
|
||||
{ repeat = 2 * repeat;
|
||||
s0 = elapsed_seconds();
|
||||
name = Test(size, repeat);
|
||||
s1 = elapsed_seconds();
|
||||
}
|
||||
double r = .5 + double(repeat) / (s1 - s0);
|
||||
// first convert to float to avoid warning with g++ -Wconversion
|
||||
rate = static_cast<size_t>( static_cast<float>( r ) );
|
||||
|
||||
if( size == first && name != "" )
|
||||
cout << name << endl;
|
||||
|
||||
if( first != last )
|
||||
{
|
||||
// convert int(size_t) to avoid warning on _MSC_VER sys
|
||||
std::cout << "size = " << int(size);
|
||||
|
||||
SpeedTestNdigit(size, ndigit, pow10);
|
||||
while( ndigit < maxSizeDigit )
|
||||
{ cout << " ";
|
||||
ndigit++;
|
||||
}
|
||||
cout << " ";
|
||||
}
|
||||
|
||||
cout << "rate = ";
|
||||
SpeedTestNdigit(rate, ndigit, pow10);
|
||||
while( ndigit > 0 )
|
||||
{
|
||||
pow10 /= 10;
|
||||
digit = rate / pow10;
|
||||
|
||||
// convert int(size_t) to avoid warning on _MSC_VER sys
|
||||
std::cout << int(digit);
|
||||
|
||||
rate = rate % pow10;
|
||||
ndigit -= 1;
|
||||
|
||||
if( (ndigit > 0) && (ndigit % 3 == 0) )
|
||||
cout << ",";
|
||||
}
|
||||
cout << endl;
|
||||
|
||||
// next size
|
||||
if( ((int) size) + inc > 0 )
|
||||
size += inc;
|
||||
else size = 0;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
} // END CppAD namespace
|
||||
|
||||
// END C++
|
||||
# endif
|
||||
@@ -0,0 +1,166 @@
|
||||
# ifndef CPPAD_UTILITY_TEST_BOOLOFVOID_HPP
|
||||
# define CPPAD_UTILITY_TEST_BOOLOFVOID_HPP
|
||||
/* --------------------------------------------------------------------------
|
||||
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-17 Bradley M. Bell
|
||||
|
||||
CppAD is distributed under multiple licenses. This distribution is under
|
||||
the terms of the
|
||||
Eclipse Public License Version 1.0.
|
||||
|
||||
A copy of this license is included in the COPYING file of this distribution.
|
||||
Please visit http://www.coin-or.org/CppAD/ for information on other licenses.
|
||||
-------------------------------------------------------------------------- */
|
||||
/*
|
||||
$begin test_boolofvoid$$
|
||||
$spell
|
||||
boolofvoid
|
||||
const
|
||||
std
|
||||
bool
|
||||
ipopt
|
||||
cpp
|
||||
$$
|
||||
|
||||
$section Object that Runs a Group of Tests$$
|
||||
|
||||
$head Syntax$$
|
||||
$codei%test_boolofvoid %Run%(%group%, %width%)
|
||||
%$$
|
||||
$icode%Run%(%test%, %name%)
|
||||
%$$
|
||||
$icode%ok% = %Run%.summary(%memory_ok%)%$$
|
||||
|
||||
$head Purpose$$
|
||||
The object $icode Run$$ is used to run a group of tests functions
|
||||
and report the results on standard output.
|
||||
|
||||
$head group$$
|
||||
The argument has prototype
|
||||
$codei%
|
||||
const std::string& %group%
|
||||
%$$
|
||||
It is the name for this group of tests.
|
||||
|
||||
$head width$$
|
||||
The argument has prototype
|
||||
$codei%
|
||||
size_t %width%
|
||||
%$$
|
||||
It is the number of columns used to display the name of each test.
|
||||
It must be greater than the maximum number of characters in a test name.
|
||||
|
||||
$head test$$
|
||||
The argument has prototype
|
||||
$codei%
|
||||
bool %test%(void)
|
||||
%$$
|
||||
It is a function that returns true (when the test passes) and false
|
||||
otherwise.
|
||||
|
||||
$head name$$
|
||||
The argument has prototype
|
||||
$codei%
|
||||
const std::string& %name%
|
||||
%$$
|
||||
It is the name for the corresponding $icode test$$.
|
||||
|
||||
$head memory_ok$$
|
||||
The argument has prototype
|
||||
$codei%
|
||||
bool %memory_ok%
|
||||
%$$
|
||||
It is false if a memory leak is detected (and true otherwise).
|
||||
|
||||
$head ok$$
|
||||
This is true if all of the tests pass (including the memory leak test),
|
||||
otherwise it is false.
|
||||
|
||||
$head Example$$
|
||||
See any of the main programs in the example directory; e.g.,
|
||||
$code example/ipopt_solve.cpp$$.
|
||||
|
||||
$end
|
||||
*/
|
||||
|
||||
# include <string>
|
||||
|
||||
namespace CppAD { // BEGIN_CPPAD_NAMESPACE
|
||||
|
||||
/// One class object is used to run a group of tests
|
||||
class test_boolofvoid {
|
||||
private:
|
||||
/// name for the group of test this object will run
|
||||
const std::string group_;
|
||||
/// number of characters used to display the name for each indiviual test
|
||||
/// (must be larger than the number of characters in name for each test)
|
||||
const size_t width_;
|
||||
/// number of tests that have passed
|
||||
size_t n_ok_;
|
||||
/// number of tests that have failed
|
||||
size_t n_error_;
|
||||
|
||||
public:
|
||||
/// ctor
|
||||
test_boolofvoid(const std::string& group, size_t width) :
|
||||
group_(group) ,
|
||||
width_(width) ,
|
||||
n_ok_(0) ,
|
||||
n_error_(0)
|
||||
{ std::cout << "Begin test group " << group_ << std::endl; }
|
||||
/// destructor
|
||||
~test_boolofvoid(void)
|
||||
{ std::cout << "End test group " << group_ << std::endl; }
|
||||
/// run one test
|
||||
bool operator()(bool test(void), const std::string& name)
|
||||
{ CPPAD_ASSERT_KNOWN(
|
||||
name.size() < width_ ,
|
||||
"test_boolofvoid: name does not have less characters than width"
|
||||
);
|
||||
std::cout.width( width_ );
|
||||
std::cout.setf( std::ios_base::left );
|
||||
std::cout << name;
|
||||
//
|
||||
bool ok = test();
|
||||
if( ok )
|
||||
{ std::cout << "OK" << std::endl;
|
||||
n_ok_++;
|
||||
}
|
||||
else
|
||||
{ std::cout << "Error" << std::endl;
|
||||
n_error_++;
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
/// nuber of tests that passed
|
||||
size_t n_ok(void) const
|
||||
{ return n_ok_; }
|
||||
/// nuber of tests that failed
|
||||
size_t n_error(void) const
|
||||
{ return n_error_; }
|
||||
/// summary
|
||||
bool summary(bool memory_ok )
|
||||
{
|
||||
std::cout.width( width_ );
|
||||
std::cout.setf( std::ios_base::left );
|
||||
std::cout << "memory_leak";
|
||||
//
|
||||
if( memory_ok )
|
||||
{ std::cout << "OK" << std::endl;
|
||||
n_ok_++;
|
||||
}
|
||||
else
|
||||
{ std::cout << "Error" << std::endl;
|
||||
n_error_++;
|
||||
}
|
||||
if( n_error_ == 0 )
|
||||
std::cout << "All " << n_ok_ << " tests passed." << std::endl;
|
||||
else
|
||||
std::cout << n_error_ << " tests failed." << std::endl;
|
||||
//
|
||||
return n_error_ == 0;
|
||||
}
|
||||
};
|
||||
|
||||
} // END_CPPAD_NAMESPACE
|
||||
|
||||
# endif
|
||||
+1524
File diff suppressed because it is too large
Load Diff
+234
@@ -0,0 +1,234 @@
|
||||
// $Id: time_test.hpp 3855 2016-12-19 00:30:54Z bradbell $
|
||||
# ifndef CPPAD_UTILITY_TIME_TEST_HPP
|
||||
# define CPPAD_UTILITY_TIME_TEST_HPP
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-16 Bradley M. Bell
|
||||
|
||||
CppAD is distributed under multiple licenses. This distribution is under
|
||||
the terms of the
|
||||
Eclipse Public License Version 1.0.
|
||||
|
||||
A copy of this license is included in the COPYING file of this distribution.
|
||||
Please visit http://www.coin-or.org/CppAD/ for information on other licenses.
|
||||
-------------------------------------------------------------------------- */
|
||||
|
||||
/*
|
||||
$begin time_test$$
|
||||
$spell
|
||||
gettimeofday
|
||||
vec
|
||||
cppad.hpp
|
||||
Microsoft
|
||||
namespace
|
||||
std
|
||||
const
|
||||
cout
|
||||
ctime
|
||||
ifdef
|
||||
const
|
||||
endif
|
||||
cpp
|
||||
$$
|
||||
|
||||
|
||||
$section Determine Amount of Time to Execute a Test$$
|
||||
$mindex time_test speed$$
|
||||
|
||||
$head Syntax$$
|
||||
$codei%# include <cppad/utility/time_test.hpp>
|
||||
%$$
|
||||
$icode%time% = time_test(%test%, %time_min%)
|
||||
%$$
|
||||
$icode%time% = time_test(%test%, %time_min%, %test_size%)%$$
|
||||
|
||||
$head Purpose$$
|
||||
The $code time_test$$ function executes a timing test
|
||||
and reports the amount of wall clock time for execution.
|
||||
|
||||
$head Motivation$$
|
||||
It is important to separate small calculation units
|
||||
and test them individually.
|
||||
This way individual changes can be tested in the context of the
|
||||
routine that they are in.
|
||||
On many machines, accurate timing of a very short execution
|
||||
sequences is not possible.
|
||||
In addition,
|
||||
there may be set up and tear down time for a test that
|
||||
we do not really want included in the timing.
|
||||
For this reason $code time_test$$
|
||||
automatically determines how many times to
|
||||
repeat the section of the test that we wish to time.
|
||||
|
||||
$head Include$$
|
||||
The file $code cppad/time_test.hpp$$ defines the
|
||||
$code time_test$$ function.
|
||||
This file is included by $code cppad/cppad.hpp$$
|
||||
and it can also be included separately with out the rest of
|
||||
the $code CppAD$$ routines.
|
||||
|
||||
$head test$$
|
||||
The $code time_test$$ argument $icode test$$ is a function,
|
||||
or function object.
|
||||
In the case where $icode test_size$$ is not present,
|
||||
$icode test$$ supports the syntax
|
||||
$codei%
|
||||
%test%(%repeat%)
|
||||
%$$
|
||||
In the case where $icode test_size$$ is present,
|
||||
$icode test$$ supports the syntax
|
||||
$codei%
|
||||
%test%(%size%, %repeat%)
|
||||
%$$
|
||||
In either case, the return value for $icode test$$ is $code void$$.
|
||||
|
||||
$subhead size$$
|
||||
If the argument $icode size$$ is present,
|
||||
it has prototype
|
||||
$codei%
|
||||
size_t %size%
|
||||
%$$
|
||||
and is equal to the $icode test_size$$ argument to $code time_test$$.
|
||||
|
||||
$subhead repeat$$
|
||||
The $icode test$$ argument $icode repeat$$ has prototype
|
||||
$codei%
|
||||
size_t %repeat%
|
||||
%$$
|
||||
It will be equal to the $icode size$$ argument to $code time_test$$.
|
||||
|
||||
$head time_min$$
|
||||
The argument $icode time_min$$ has prototype
|
||||
$codei%
|
||||
double %time_min%
|
||||
%$$
|
||||
It specifies the minimum amount of time in seconds
|
||||
that the $icode test$$ routine should take.
|
||||
The $icode repeat$$ argument to $icode test$$ is increased
|
||||
until this amount of execution time (or more) is reached.
|
||||
|
||||
$head test_size$$
|
||||
This argument has prototype
|
||||
$codei%
|
||||
size_t %test_size%
|
||||
%$$
|
||||
It specifies the $icode size$$ argument to $icode test$$.
|
||||
|
||||
$head time$$
|
||||
The return value $icode time$$ has prototype
|
||||
$codei%
|
||||
double %time%
|
||||
%$$
|
||||
and is the number of wall clock seconds that it took
|
||||
to execute $icode test$$ divided by the value used for $icode repeat$$.
|
||||
|
||||
$head Timing$$
|
||||
The routine $cref elapsed_seconds$$ will be used to determine the
|
||||
amount of time it took to execute the test.
|
||||
|
||||
$children%
|
||||
cppad/utility/elapsed_seconds.hpp%
|
||||
speed/example/time_test.cpp
|
||||
%$$
|
||||
$head Example$$
|
||||
The routine $cref time_test.cpp$$ is an example and test
|
||||
of $code time_test$$.
|
||||
|
||||
$end
|
||||
-----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
# include <algorithm>
|
||||
# include <cstddef>
|
||||
# include <cmath>
|
||||
# include <cppad/utility/elapsed_seconds.hpp>
|
||||
# include <cppad/core/define.hpp>
|
||||
|
||||
# define CPPAD_EXTRA_RUN_BEFORE_TIMING 0
|
||||
|
||||
namespace CppAD { // BEGIN_CPPAD_NAMESPACE
|
||||
/*!
|
||||
\file time_test.hpp
|
||||
\brief Function that preforms one timing test (for speed of execution).
|
||||
*/
|
||||
|
||||
/*!
|
||||
Preform one wall clock execution timing test.
|
||||
|
||||
\tparam Test
|
||||
Either the type <code>void (*)(size_t)</code> or a function object
|
||||
type that supports the same syntax.
|
||||
|
||||
\param test
|
||||
The function, or function object, that supports the operation
|
||||
<code>test(repeat)</code> where \c repeat is the number of times
|
||||
to repeat the tests operaiton that is being timed.
|
||||
|
||||
\param time_min
|
||||
is the minimum amount of time that \c test should take to preform
|
||||
the repetitions of the operation being timed.
|
||||
*/
|
||||
template <class Test>
|
||||
double time_test(Test test, double time_min )
|
||||
{
|
||||
# if CPPAD_EXTRA_RUN_BEFORE_TIMING
|
||||
test(1);
|
||||
# endif
|
||||
size_t repeat = 0;
|
||||
double s0 = elapsed_seconds();
|
||||
double s1 = s0;
|
||||
while( s1 - s0 < time_min )
|
||||
{ repeat = std::max(size_t(1), 2 * repeat);
|
||||
s0 = elapsed_seconds();
|
||||
test(repeat);
|
||||
s1 = elapsed_seconds();
|
||||
}
|
||||
double time = (s1 - s0) / double(repeat);
|
||||
return time;
|
||||
}
|
||||
|
||||
/*!
|
||||
Preform one wall clock execution timing test.
|
||||
|
||||
\tparam Test
|
||||
Either the type <code>void (*)(size_t, size_t)</code> or a function object
|
||||
type that supports the same syntax.
|
||||
|
||||
\param test
|
||||
The function, or function object, that supports the operation
|
||||
<code>test(size, repeat)</code> where
|
||||
\c is the size for this test and
|
||||
\c repeat is the number of times
|
||||
to repeat the tests operaiton that is being timed.
|
||||
|
||||
\param time_min
|
||||
is the minimum amount of time that \c test should take to preform
|
||||
the repetitions of the operation being timed.
|
||||
|
||||
\param test_size
|
||||
will be used for the value of \c size in the call to \c test.
|
||||
*/
|
||||
template <class Test>
|
||||
double time_test(Test test, double time_min, size_t test_size)
|
||||
{
|
||||
# if CPPAD_EXTRA_RUN_BEFORE_TIMING
|
||||
test(test_size, 1);
|
||||
# endif
|
||||
size_t repeat = 0;
|
||||
double s0 = elapsed_seconds();
|
||||
double s1 = s0;
|
||||
while( s1 - s0 < time_min )
|
||||
{ repeat = std::max(size_t(1), 2 * repeat);
|
||||
s0 = elapsed_seconds();
|
||||
test(test_size, repeat);
|
||||
s1 = elapsed_seconds();
|
||||
}
|
||||
double time = (s1 - s0) / double(repeat);
|
||||
return time;
|
||||
}
|
||||
|
||||
} // END_CPPAD_NAMESPACE
|
||||
|
||||
# undef CPPAD_EXTRA_RUN_BEFORE_TIMING
|
||||
// END PROGRAM
|
||||
# endif
|
||||
+174
@@ -0,0 +1,174 @@
|
||||
# ifndef CPPAD_UTILITY_TO_STRING_HPP
|
||||
# define CPPAD_UTILITY_TO_STRING_HPP
|
||||
/* --------------------------------------------------------------------------
|
||||
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-17 Bradley M. Bell
|
||||
|
||||
CppAD is distributed under multiple licenses. This distribution is under
|
||||
the terms of the
|
||||
Eclipse Public License Version 1.0.
|
||||
|
||||
A copy of this license is included in the COPYING file of this distribution.
|
||||
Please visit http://www.coin-or.org/CppAD/ for information on other licenses.
|
||||
-------------------------------------------------------------------------- */
|
||||
|
||||
/*
|
||||
$begin to_string$$
|
||||
$spell
|
||||
cppad.hpp
|
||||
long long
|
||||
std
|
||||
const
|
||||
ostringstream
|
||||
$$
|
||||
|
||||
$section Convert Certain Types to a String$$
|
||||
|
||||
$head Syntax$$
|
||||
$codei%# include <cppad/utility/to_string.hpp>
|
||||
%$$
|
||||
$icode%s% = to_string(%value%)%$$.
|
||||
|
||||
$head See Also$$
|
||||
$cref base_to_string$$, $cref ad_to_string$$
|
||||
|
||||
$head Purpose$$
|
||||
This routine is similar to the C++11 routine $code std::to_string$$
|
||||
with the following differences:
|
||||
$list number$$
|
||||
It works with C++98.
|
||||
$lnext
|
||||
It has been extended to the fundamental floating point types.
|
||||
$lnext
|
||||
It has specifications for extending to an arbitrary type; see
|
||||
$cref base_to_string$$.
|
||||
$lnext
|
||||
If $code <cppad/cppad.hpp>$$ is included,
|
||||
and it has been extended to a $icode Base$$ type,
|
||||
it automatically extends to the
|
||||
$cref/AD types above Base/glossary/AD Type Above Base/$$.
|
||||
$lnext
|
||||
For integer types, conversion to a string is exact.
|
||||
For floating point types, conversion to a string yields a value
|
||||
that has relative error within machine epsilon.
|
||||
$lend
|
||||
|
||||
$head value$$
|
||||
|
||||
$subhead Integer$$
|
||||
The argument $icode value$$ can have the following prototype
|
||||
$codei%
|
||||
const %Integer%& %value%
|
||||
%$$
|
||||
where $icode Integer$$ is any of the fundamental integer types; e.g.,
|
||||
$code short int$$ and $code unsigned long$$.
|
||||
Note that if C++11 is supported by this compilation,
|
||||
$code unsigned long long$$ is also a fundamental integer type.
|
||||
|
||||
$subhead Float$$
|
||||
The argument $icode value$$ can have the following prototype
|
||||
$codei%
|
||||
const %Float%& %value%
|
||||
%$$
|
||||
where $icode Float$$ is any of the fundamental floating point types; i.e.,
|
||||
$code float$$, $code double$$, and $code long double$$.
|
||||
|
||||
$head s$$
|
||||
The return value has prototype
|
||||
$codei%
|
||||
std::string %s%
|
||||
%$$
|
||||
and contains a representation of the specified $icode value$$.
|
||||
|
||||
$subhead Integer$$
|
||||
If $icode value$$ is an $codei Integer$$,
|
||||
the representation is equivalent to $codei%os% << %value%$$
|
||||
where $icode os$$ is an $code std::ostringstream$$.
|
||||
|
||||
$subhead Float$$
|
||||
If $icode value$$ is a $codei Float$$,
|
||||
enough digits are used in the representation so that
|
||||
the result is accurate to withing round off error.
|
||||
|
||||
$children%
|
||||
example/utility/to_string.cpp
|
||||
%$$
|
||||
$head Example$$
|
||||
The file $cref to_string.cpp$$
|
||||
contains an example and test of this routine.
|
||||
It returns true if it succeeds and false otherwise.
|
||||
|
||||
$end
|
||||
*/
|
||||
# include <limits>
|
||||
# include <cmath>
|
||||
# include <iomanip>
|
||||
# include <sstream>
|
||||
# include <cppad/core/cppad_assert.hpp>
|
||||
|
||||
# define CPPAD_SPECIALIZE_TO_STRING_INTEGER(Type) \
|
||||
template <> struct to_string_struct<Type>\
|
||||
{ std::string operator()(const Type& value) \
|
||||
{ std::stringstream os;\
|
||||
os << value;\
|
||||
return os.str();\
|
||||
}\
|
||||
};
|
||||
|
||||
# define CPPAD_SPECIALIZE_TO_STRING_FLOAT(Float) \
|
||||
template <> struct to_string_struct<Float>\
|
||||
{ std::string operator()(const Float& value) \
|
||||
{ std::stringstream os;\
|
||||
int n_digits = 1 + std::numeric_limits<Float>::digits10;\
|
||||
os << std::setprecision(n_digits);\
|
||||
os << value;\
|
||||
return os.str();\
|
||||
}\
|
||||
};
|
||||
|
||||
namespace CppAD {
|
||||
|
||||
// Default implementation,
|
||||
// each type must define its own specilization.
|
||||
template <class Type>
|
||||
struct to_string_struct
|
||||
{ std::string operator()(const Type& value)
|
||||
{ CPPAD_ASSERT_KNOWN(
|
||||
false,
|
||||
"to_string is not implemented for this type"
|
||||
);
|
||||
// return empty string
|
||||
return std::string("");
|
||||
}
|
||||
};
|
||||
|
||||
// specialization for the fundamental integer types
|
||||
CPPAD_SPECIALIZE_TO_STRING_INTEGER(signed short)
|
||||
CPPAD_SPECIALIZE_TO_STRING_INTEGER(unsigned short)
|
||||
//
|
||||
CPPAD_SPECIALIZE_TO_STRING_INTEGER(signed int)
|
||||
CPPAD_SPECIALIZE_TO_STRING_INTEGER(unsigned int)
|
||||
//
|
||||
CPPAD_SPECIALIZE_TO_STRING_INTEGER(signed long)
|
||||
CPPAD_SPECIALIZE_TO_STRING_INTEGER(unsigned long)
|
||||
//
|
||||
# if CPPAD_USE_CPLUSPLUS_2011
|
||||
CPPAD_SPECIALIZE_TO_STRING_INTEGER(signed long long)
|
||||
CPPAD_SPECIALIZE_TO_STRING_INTEGER(unsigned long long)
|
||||
# endif
|
||||
|
||||
// specialization for the fundamental floating point types
|
||||
CPPAD_SPECIALIZE_TO_STRING_FLOAT(float)
|
||||
CPPAD_SPECIALIZE_TO_STRING_FLOAT(double)
|
||||
CPPAD_SPECIALIZE_TO_STRING_FLOAT(long double)
|
||||
|
||||
// link from function to function object in structure
|
||||
template<class Type>
|
||||
std::string to_string(const Type& value)
|
||||
{ to_string_struct<Type> to_str;
|
||||
return to_str(value);
|
||||
}
|
||||
}
|
||||
|
||||
# undef CPPAD_SPECIALIZE_TO_STRING_FLOAT
|
||||
# undef CPPAD_SPECIALIZE_TO_STRING_INTEGER
|
||||
# endif
|
||||
@@ -0,0 +1,542 @@
|
||||
# ifndef CPPAD_UTILITY_TRACK_NEW_DEL_HPP
|
||||
# define CPPAD_UTILITY_TRACK_NEW_DEL_HPP
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-17 Bradley M. Bell
|
||||
|
||||
CppAD is distributed under multiple licenses. This distribution is under
|
||||
the terms of the
|
||||
Eclipse Public License Version 1.0.
|
||||
|
||||
A copy of this license is included in the COPYING file of this distribution.
|
||||
Please visit http://www.coin-or.org/CppAD/ for information on other licenses.
|
||||
-------------------------------------------------------------------------- */
|
||||
/*
|
||||
$begin TrackNewDel$$
|
||||
$spell
|
||||
cppad.hpp
|
||||
Cpp
|
||||
newptr
|
||||
Vec
|
||||
oldptr
|
||||
newlen
|
||||
ncopy
|
||||
const
|
||||
$$
|
||||
|
||||
$section Routines That Track Use of New and Delete$$
|
||||
$mindex memory NDEBUG CPPAD_TRACK_NEW_VEC CppADTrackNewVec CPPAD_TRACK_DEL_VEC CppADTrackDelVec CPPAD_TRACK_EXTEND CppADTrackExtend CPPAD_TRACK_COUNT thread multi$$
|
||||
|
||||
$head Deprecated 2007-07-23$$
|
||||
All these routines have been deprecated.
|
||||
You should use the $cref thread_alloc$$ memory allocator instead
|
||||
(which works better in both a single thread and
|
||||
properly in multi-threading environment).
|
||||
|
||||
$head Syntax$$
|
||||
$codei%# include <cppad/utility/track_new_del.hpp>
|
||||
%$$
|
||||
$icode%newptr% = TrackNewVec(%file%, %line%, %newlen%, %oldptr%)
|
||||
%$$
|
||||
$codei%TrackDelVec(%file%, %line%, %oldptr%)
|
||||
%$$
|
||||
$icode%newptr% = TrackExtend(%file%, %line%, %newlen%, %ncopy%, %oldptr%)
|
||||
%$$
|
||||
$icode%count% = TrackCount(%file%, %line%)%$$
|
||||
|
||||
|
||||
$head Purpose$$
|
||||
These routines
|
||||
aid in the use of $code new[]$$ and $code delete[]$$
|
||||
during the execution of a C++ program.
|
||||
|
||||
$head Include$$
|
||||
The file $code cppad/track_new_del.hpp$$ is included by
|
||||
$code cppad/cppad.hpp$$
|
||||
but it can also be included separately with out the rest of the
|
||||
CppAD include files.
|
||||
|
||||
|
||||
$head file$$
|
||||
The argument $icode file$$ has prototype
|
||||
$codei%
|
||||
const char *%file%
|
||||
%$$
|
||||
It should be the source code file name
|
||||
where the call to $code TrackNew$$ is located.
|
||||
The best way to accomplish this is the use the preprocessor symbol
|
||||
$code __FILE__$$ for this argument.
|
||||
|
||||
$head line$$
|
||||
The argument $icode line$$ has prototype
|
||||
$codei%
|
||||
int %line%
|
||||
%$$
|
||||
It should be the source code file line number
|
||||
where the call to $code TrackNew$$ is located.
|
||||
The best way to accomplish this is the use the preprocessor symbol
|
||||
$code __LINE__$$ for this argument.
|
||||
|
||||
$head oldptr$$
|
||||
The argument $icode oldptr$$ has prototype
|
||||
$codei%
|
||||
%Type% *%oldptr%
|
||||
%$$
|
||||
This argument is used to identify the type $icode Type$$.
|
||||
|
||||
$head newlen$$
|
||||
The argument $icode newlen$$ has prototype
|
||||
$codei%
|
||||
size_t %newlen%
|
||||
%$$
|
||||
|
||||
$head head newptr$$
|
||||
The return value $icode newptr$$ has prototype
|
||||
$codei%
|
||||
%Type% *%newptr%
|
||||
%$$
|
||||
It points to the newly allocated vector of objects
|
||||
that were allocated using
|
||||
$codei%
|
||||
new Type[%newlen%]
|
||||
%$$
|
||||
|
||||
$head ncopy$$
|
||||
The argument $icode ncopy$$ has prototype
|
||||
$codei%
|
||||
size_t %ncopy%
|
||||
%$$
|
||||
This specifies the number of elements that are copied from
|
||||
the old array to the new array.
|
||||
The value of $icode ncopy$$
|
||||
must be less than or equal $icode newlen$$.
|
||||
|
||||
$head TrackNewVec$$
|
||||
If $code NDEBUG$$ is defined, this routine only sets
|
||||
$codei%
|
||||
%newptr% = %Type% new[%newlen%]
|
||||
%$$
|
||||
The value of $icode oldptr$$ does not matter
|
||||
(except that it is used to identify $icode Type$$).
|
||||
If $code NDEBUG$$ is not defined, $code TrackNewVec$$ also
|
||||
tracks the this memory allocation.
|
||||
In this case, if memory cannot be allocated
|
||||
$cref ErrorHandler$$ is used to generate a message
|
||||
stating that there was not sufficient memory.
|
||||
|
||||
$subhead Macro$$
|
||||
The preprocessor macro call
|
||||
$codei%
|
||||
CPPAD_TRACK_NEW_VEC(%newlen%, %oldptr%)
|
||||
%$$
|
||||
expands to
|
||||
$codei%
|
||||
CppAD::TrackNewVec(__FILE__, __LINE__, %newlen%, %oldptr%)
|
||||
%$$
|
||||
|
||||
$subhead Previously Deprecated$$
|
||||
The preprocessor macro $code CppADTrackNewVec$$ is the
|
||||
same as $code CPPAD_TRACK_NEW_VEC$$ and was previously deprecated.
|
||||
|
||||
$head TrackDelVec$$
|
||||
This routine is used to a vector of objects
|
||||
that have been allocated using $code TrackNew$$ or $code TrackExtend$$.
|
||||
If $code NDEBUG$$ is defined, this routine only frees memory with
|
||||
$codei%
|
||||
delete [] %oldptr%
|
||||
%$$
|
||||
If $code NDEBUG$$ is not defined, $code TrackDelete$$ also checks that
|
||||
$icode oldptr$$ was allocated by $code TrackNew$$ or $code TrackExtend$$
|
||||
and has not yet been freed.
|
||||
If this is not the case,
|
||||
$cref ErrorHandler$$ is used to generate an error message.
|
||||
|
||||
$subhead Macro$$
|
||||
The preprocessor macro call
|
||||
$codei%
|
||||
CPPAD_TRACK_DEL_VEC(%oldptr%)
|
||||
%$$
|
||||
expands to
|
||||
$codei%
|
||||
CppAD::TrackDelVec(__FILE__, __LINE__, %oldptr%)
|
||||
%$$
|
||||
|
||||
$subhead Previously Deprecated$$
|
||||
The preprocessor macro $code CppADTrackDelVec$$ is the
|
||||
same as $code CPPAD_TRACK_DEL_VEC$$ was previously deprecated.
|
||||
|
||||
$head TrackExtend$$
|
||||
This routine is used to
|
||||
allocate a new vector (using $code TrackNewVec$$),
|
||||
copy $icode ncopy$$ elements from the old vector to the new vector.
|
||||
If $icode ncopy$$ is greater than zero, $icode oldptr$$
|
||||
must have been allocated using $code TrackNewVec$$ or $code TrackExtend$$.
|
||||
In this case, the vector pointed to by $icode oldptr$$
|
||||
must be have at least $icode ncopy$$ elements
|
||||
and it will be deleted (using $code TrackDelVec$$).
|
||||
Note that the dependence of $code TrackExtend$$ on $code NDEBUG$$
|
||||
is indirectly through the routines $code TrackNewVec$$ and
|
||||
$code TrackDelVec$$.
|
||||
|
||||
$subhead Macro$$
|
||||
The preprocessor macro call
|
||||
$codei%
|
||||
CPPAD_TRACK_EXTEND(%newlen%, %ncopy%, %oldptr%)
|
||||
%$$
|
||||
expands to
|
||||
$codei%
|
||||
CppAD::TrackExtend(__FILE__, __LINE__, %newlen%, %ncopy%, %oldptr%)
|
||||
%$$
|
||||
|
||||
$subhead Previously Deprecated$$
|
||||
The preprocessor macro $code CppADTrackExtend$$ is the
|
||||
same as $code CPPAD_TRACK_EXTEND$$ and was previously deprecated.
|
||||
|
||||
$head TrackCount$$
|
||||
The return value $icode count$$ has prototype
|
||||
$codei%
|
||||
size_t %count%
|
||||
%$$
|
||||
If $code NDEBUG$$ is defined, $icode count$$ will be zero.
|
||||
Otherwise, it will be
|
||||
the number of vectors that
|
||||
have been allocated
|
||||
(by $code TrackNewVec$$ or $code TrackExtend$$)
|
||||
and not yet freed
|
||||
(by $code TrackDelete$$).
|
||||
|
||||
$subhead Macro$$
|
||||
The preprocessor macro call
|
||||
$codei%
|
||||
CPPAD_TRACK_COUNT()
|
||||
%$$
|
||||
expands to
|
||||
$codei%
|
||||
CppAD::TrackCount(__FILE__, __LINE__)
|
||||
%$$
|
||||
|
||||
$subhead Previously Deprecated$$
|
||||
The preprocessor macro $code CppADTrackCount$$ is the
|
||||
same as $code CPPAD_TRACK_COUNT$$ and was previously deprecated.
|
||||
|
||||
$head Multi-Threading$$
|
||||
These routines cannot be used $cref/in_parallel/ta_in_parallel/$$
|
||||
execution mode.
|
||||
Use the $cref thread_alloc$$ routines instead.
|
||||
|
||||
$head Example$$
|
||||
$children%
|
||||
example/deprecated/track_new_del.cpp
|
||||
%$$
|
||||
The file $cref TrackNewDel.cpp$$
|
||||
contains an example and test of these functions.
|
||||
It returns true, if it succeeds, and false otherwise.
|
||||
|
||||
$end
|
||||
------------------------------------------------------------------------------
|
||||
*/
|
||||
# include <cppad/core/define.hpp>
|
||||
# include <cppad/core/cppad_assert.hpp>
|
||||
# include <cppad/utility/thread_alloc.hpp>
|
||||
# include <sstream>
|
||||
# include <string>
|
||||
|
||||
# ifndef CPPAD_TRACK_DEBUG
|
||||
# define CPPAD_TRACK_DEBUG 0
|
||||
# endif
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
# define CPPAD_TRACK_NEW_VEC(newlen, oldptr) \
|
||||
CppAD::TrackNewVec(__FILE__, __LINE__, newlen, oldptr)
|
||||
|
||||
# define CPPAD_TRACK_DEL_VEC(oldptr) \
|
||||
CppAD::TrackDelVec(__FILE__, __LINE__, oldptr)
|
||||
|
||||
# define CPPAD_TRACK_EXTEND(newlen, ncopy, oldptr) \
|
||||
CppAD::TrackExtend(__FILE__, __LINE__, newlen, ncopy, oldptr)
|
||||
|
||||
# define CPPAD_TRACK_COUNT() \
|
||||
CppAD::TrackCount(__FILE__, __LINE__)
|
||||
// -------------------------------------------------------------------------
|
||||
# define CppADTrackNewVec CPPAD_TRACK_NEW_VEC
|
||||
# define CppADTrackDelVec CPPAD_TRACK_DEL_VEC
|
||||
# define CppADTrackExtend CPPAD_TRACK_EXTEND
|
||||
# define CppADTrackCount CPPAD_TRACK_COUNT
|
||||
// -------------------------------------------------------------------------
|
||||
namespace CppAD { // Begin CppAD namespace
|
||||
|
||||
// TrackElement ------------------------------------------------------------
|
||||
class TrackElement {
|
||||
|
||||
public:
|
||||
std::string file; // corresponding file name
|
||||
int line; // corresponding line number
|
||||
void *ptr; // value returned by TrackNew
|
||||
TrackElement *next; // next element in linked list
|
||||
|
||||
// default contructor (used to initialize root)
|
||||
TrackElement(void)
|
||||
: file(""), line(0), ptr(CPPAD_NULL), next(CPPAD_NULL)
|
||||
{ }
|
||||
|
||||
TrackElement(const char *f, int l, void *p)
|
||||
: file(f), line(l), ptr(p), next(CPPAD_NULL)
|
||||
{ CPPAD_ASSERT_UNKNOWN( p != CPPAD_NULL);
|
||||
}
|
||||
|
||||
// There is only one tracking list and it starts it here
|
||||
static TrackElement *Root(void)
|
||||
{ CPPAD_ASSERT_UNKNOWN( ! thread_alloc::in_parallel() );
|
||||
static TrackElement root;
|
||||
return &root;
|
||||
}
|
||||
|
||||
// Print one tracking element
|
||||
static void Print(TrackElement* E)
|
||||
{
|
||||
CPPAD_ASSERT_UNKNOWN( ! thread_alloc::in_parallel() );
|
||||
using std::cout;
|
||||
cout << "E = " << E;
|
||||
cout << ", E->next = " << E->next;
|
||||
cout << ", E->ptr = " << E->ptr;
|
||||
cout << ", E->line = " << E->line;
|
||||
cout << ", E->file = " << E->file;
|
||||
cout << std::endl;
|
||||
}
|
||||
|
||||
// Print the linked list for a thread
|
||||
static void Print(void)
|
||||
{
|
||||
CPPAD_ASSERT_UNKNOWN( ! thread_alloc::in_parallel() );
|
||||
using std::cout;
|
||||
using std::endl;
|
||||
TrackElement *E = Root();
|
||||
// convert int(size_t) to avoid warning on _MSC_VER systems
|
||||
cout << "Begin Track List" << endl;
|
||||
while( E->next != CPPAD_NULL )
|
||||
{ E = E->next;
|
||||
Print(E);
|
||||
}
|
||||
cout << "End Track List:" << endl;
|
||||
cout << endl;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// TrackError ----------------------------------------------------------------
|
||||
inline void TrackError(
|
||||
const char *routine,
|
||||
const char *file,
|
||||
int line,
|
||||
const char *msg )
|
||||
{
|
||||
CPPAD_ASSERT_UNKNOWN( ! thread_alloc::in_parallel() );
|
||||
std::ostringstream buf;
|
||||
buf << routine
|
||||
<< ": at line "
|
||||
<< line
|
||||
<< " in file "
|
||||
<< file
|
||||
<< std::endl
|
||||
<< msg;
|
||||
std::string str = buf.str();
|
||||
size_t n = str.size();
|
||||
size_t i;
|
||||
char *message = new char[n + 1];
|
||||
for(i = 0; i < n; i++)
|
||||
message[i] = str[i];
|
||||
message[n] = '\0';
|
||||
CPPAD_ASSERT_KNOWN( false , message);
|
||||
}
|
||||
|
||||
// TrackNewVec ---------------------------------------------------------------
|
||||
# ifdef NDEBUG
|
||||
template <class Type>
|
||||
inline Type *TrackNewVec(
|
||||
const char *file, int line, size_t len, Type * /* oldptr */ )
|
||||
{
|
||||
# if CPPAD_TRACK_DEBUG
|
||||
static bool first = true;
|
||||
if( first )
|
||||
{ std::cout << "NDEBUG is defined for TrackNewVec" << std::endl;
|
||||
first = false;
|
||||
}
|
||||
# endif
|
||||
return (new Type[len]);
|
||||
}
|
||||
|
||||
# else
|
||||
|
||||
template <class Type>
|
||||
Type *TrackNewVec(
|
||||
const char *file ,
|
||||
int line ,
|
||||
size_t len ,
|
||||
Type * /* oldptr */ )
|
||||
{
|
||||
CPPAD_ASSERT_KNOWN(
|
||||
! thread_alloc::in_parallel() ,
|
||||
"attempt to use TrackNewVec in parallel execution mode."
|
||||
);
|
||||
// try to allocate the new memrory
|
||||
Type *newptr = CPPAD_NULL;
|
||||
try
|
||||
{ newptr = new Type[len];
|
||||
}
|
||||
catch(...)
|
||||
{ TrackError("TrackNewVec", file, line,
|
||||
"Cannot allocate sufficient memory"
|
||||
);
|
||||
}
|
||||
// create tracking element
|
||||
void *vptr = static_cast<void *>(newptr);
|
||||
TrackElement *E = new TrackElement(file, line, vptr);
|
||||
|
||||
// get the root
|
||||
TrackElement *root = TrackElement::Root();
|
||||
|
||||
// put this elemenent at the front of linked list
|
||||
E->next = root->next;
|
||||
root->next = E;
|
||||
|
||||
# if CPPAD_TRACK_DEBUG
|
||||
std::cout << "TrackNewVec: ";
|
||||
TrackElement::Print(E);
|
||||
# endif
|
||||
|
||||
return newptr;
|
||||
}
|
||||
|
||||
# endif
|
||||
|
||||
// TrackDelVec --------------------------------------------------------------
|
||||
# ifdef NDEBUG
|
||||
template <class Type>
|
||||
inline void TrackDelVec(const char *file, int line, Type *oldptr)
|
||||
{
|
||||
# if CPPAD_TRACK_DEBUG
|
||||
static bool first = true;
|
||||
if( first )
|
||||
{ std::cout << "NDEBUG is defined in TrackDelVec" << std::endl;
|
||||
first = false;
|
||||
}
|
||||
# endif
|
||||
delete [] oldptr;
|
||||
}
|
||||
|
||||
# else
|
||||
|
||||
template <class Type>
|
||||
void TrackDelVec(
|
||||
const char *file ,
|
||||
int line ,
|
||||
Type *oldptr )
|
||||
{
|
||||
CPPAD_ASSERT_KNOWN(
|
||||
! thread_alloc::in_parallel() ,
|
||||
"attempt to use TrackDelVec in parallel execution mode."
|
||||
);
|
||||
TrackElement *P;
|
||||
TrackElement *E;
|
||||
|
||||
// search list for pointer
|
||||
P = TrackElement::Root();
|
||||
E = P->next;
|
||||
void *vptr = static_cast<void *>(oldptr);
|
||||
while(E != CPPAD_NULL && E->ptr != vptr)
|
||||
{ P = E;
|
||||
E = E->next;
|
||||
}
|
||||
|
||||
// check if pointer was not in list
|
||||
if( E == CPPAD_NULL || E->ptr != vptr ) TrackError(
|
||||
"TrackDelVec", file, line,
|
||||
"Invalid value for the argument oldptr.\n"
|
||||
"Possible linking of debug and NDEBUG compilations of CppAD."
|
||||
);
|
||||
|
||||
# if CPPAD_TRACK_DEBUG
|
||||
std::cout << "TrackDelVec: ";
|
||||
TrackElement::Print(E);
|
||||
# endif
|
||||
|
||||
// remove tracking element from list
|
||||
P->next = E->next;
|
||||
|
||||
// delete allocated pointer
|
||||
delete [] oldptr;
|
||||
|
||||
// delete tracking element
|
||||
delete E;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
# endif
|
||||
|
||||
// TrackExtend --------------------------------------------------------------
|
||||
template <class Type>
|
||||
Type *TrackExtend(
|
||||
const char *file ,
|
||||
int line ,
|
||||
size_t newlen ,
|
||||
size_t ncopy ,
|
||||
Type *oldptr )
|
||||
{
|
||||
CPPAD_ASSERT_KNOWN(
|
||||
! thread_alloc::in_parallel() ,
|
||||
"attempt to use TrackExtend in parallel execution mode."
|
||||
);
|
||||
|
||||
# if CPPAD_TRACK_DEBUG
|
||||
using std::cout;
|
||||
cout << "TrackExtend: file = " << file;
|
||||
cout << ", line = " << line;
|
||||
cout << ", newlen = " << newlen;
|
||||
cout << ", ncopy = " << ncopy;
|
||||
cout << ", oldptr = " << oldptr;
|
||||
cout << std::endl;
|
||||
# endif
|
||||
CPPAD_ASSERT_KNOWN(
|
||||
ncopy <= newlen,
|
||||
"TrackExtend: ncopy is greater than newlen."
|
||||
);
|
||||
|
||||
// allocate the new memrory
|
||||
Type *newptr = TrackNewVec(file, line, newlen, oldptr);
|
||||
|
||||
// copy the data
|
||||
size_t i;
|
||||
for(i = 0; i < ncopy; i++)
|
||||
newptr[i] = oldptr[i];
|
||||
|
||||
// delete the old vector
|
||||
if( ncopy > 0 )
|
||||
TrackDelVec(file, line, oldptr);
|
||||
|
||||
return newptr;
|
||||
}
|
||||
|
||||
// TrackCount --------------------------------------------------------------
|
||||
inline size_t TrackCount(const char *file, int line)
|
||||
{
|
||||
CPPAD_ASSERT_KNOWN(
|
||||
! thread_alloc::in_parallel() ,
|
||||
"attempt to use TrackCount in parallel execution mode."
|
||||
);
|
||||
size_t count = 0;
|
||||
TrackElement *E = TrackElement::Root();
|
||||
while( E->next != CPPAD_NULL )
|
||||
{ ++count;
|
||||
E = E->next;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
} // End CppAD namespace
|
||||
|
||||
// preprocessor symbols local to this file
|
||||
# undef CPPAD_TRACK_DEBUG
|
||||
|
||||
# endif
|
||||
+914
@@ -0,0 +1,914 @@
|
||||
# ifndef CPPAD_UTILITY_VECTOR_HPP
|
||||
# define CPPAD_UTILITY_VECTOR_HPP
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-17 Bradley M. Bell
|
||||
|
||||
CppAD is distributed under multiple licenses. This distribution is under
|
||||
the terms of the
|
||||
Eclipse Public License Version 1.0.
|
||||
|
||||
A copy of this license is included in the COPYING file of this distribution.
|
||||
Please visit http://www.coin-or.org/CppAD/ for information on other licenses.
|
||||
-------------------------------------------------------------------------- */
|
||||
|
||||
/*
|
||||
$begin CppAD_vector$$
|
||||
$spell
|
||||
rvalues
|
||||
thread_alloc
|
||||
cppad.hpp
|
||||
Bool
|
||||
resize
|
||||
cout
|
||||
endl
|
||||
std
|
||||
Cpp
|
||||
const
|
||||
vec
|
||||
ostream
|
||||
elem
|
||||
$$
|
||||
|
||||
|
||||
$section The CppAD::vector Template Class$$
|
||||
$mindex vector CppAD [] push thread_alloc$$
|
||||
|
||||
$head Syntax$$
|
||||
$code%# include <cppad/utility/vector.hpp>$$
|
||||
|
||||
$head Description$$
|
||||
The include file $code cppad/vector.hpp$$ defines the
|
||||
vector template class $code CppAD::vector$$.
|
||||
This is a $cref SimpleVector$$ template class and in addition
|
||||
it has the features listed below:
|
||||
|
||||
$head Include$$
|
||||
The file $code cppad/vector.hpp$$ is included by $code cppad/cppad.hpp$$
|
||||
but it can also be included separately with out the rest of the
|
||||
CppAD include files.
|
||||
|
||||
$head capacity$$
|
||||
If $icode x$$ is a $codei%CppAD::vector<%Scalar%>%$$,
|
||||
and $icode cap$$ is a $code size_t$$ object,
|
||||
$codei%
|
||||
%cap% = %x%.capacity()
|
||||
%$$
|
||||
set $icode cap$$ to the number of $icode Scalar$$ objects that
|
||||
could fit in the memory currently allocated for $icode x$$.
|
||||
Note that
|
||||
$codei%
|
||||
%x%.size() <= %x%.capacity()
|
||||
%$$
|
||||
|
||||
$head Assignment$$
|
||||
If $icode x$$ and $icode y$$ are
|
||||
$codei%CppAD::vector<%Scalar%>%$$ objects,
|
||||
$codei%
|
||||
%y% = %x%
|
||||
%$$
|
||||
has all the properties listed for a
|
||||
$cref/simple vector assignment/SimpleVector/Assignment/$$
|
||||
plus the following:
|
||||
|
||||
$subhead Check Size$$
|
||||
The $code CppAD::vector$$ template class will check that
|
||||
the size of $icode x$$ is either zero or the size of $icode y$$
|
||||
before doing the assignment.
|
||||
If this is not the case, $code CppAD::vector$$ will use
|
||||
$cref ErrorHandler$$
|
||||
to generate an appropriate error report.
|
||||
Allowing for assignment to a vector with size zero makes the following
|
||||
code work:
|
||||
$codei%
|
||||
CppAD::vector<%Scalar%> %y%;
|
||||
%y% = %x%;
|
||||
%$$
|
||||
|
||||
$subhead Return Reference$$
|
||||
A reference to the vector $icode y$$ is returned.
|
||||
An example use of this reference is in multiple assignments of the form
|
||||
$codei%
|
||||
%z% = %y% = %x%
|
||||
%$$
|
||||
|
||||
$subhead Move Semantics$$
|
||||
If the C++ compiler supports move semantic rvalues using the $code &&$$
|
||||
syntax, then it will be used during the vector assignment statement.
|
||||
This means that return values and other temporaries are not be copied,
|
||||
but rather pointers are transferred.
|
||||
|
||||
$head Element Access$$
|
||||
If $icode x$$ is a $codei%CppAD::vector<%Scalar%>%$$ object
|
||||
and $icode i$$ has type $code size_t$$,
|
||||
$codei%
|
||||
%x%[%i%]
|
||||
%$$
|
||||
has all the properties listed for a
|
||||
$cref/simple vector element access/SimpleVector/Element Access/$$
|
||||
plus the following:
|
||||
$pre
|
||||
|
||||
$$
|
||||
The object $icode%x%[%i%]%$$ has type $icode Scalar$$
|
||||
(is not possibly a different type that can be converted to $icode Scalar$$).
|
||||
$pre
|
||||
|
||||
$$
|
||||
If $icode i$$ is not less than the size of the $icode x$$,
|
||||
$code CppAD::vector$$ will use
|
||||
$cref ErrorHandler$$
|
||||
to generate an appropriate error report.
|
||||
|
||||
$head push_back$$
|
||||
If $icode x$$ is a $codei%CppAD::vector<%Scalar%>%$$ object
|
||||
with size equal to $icode n$$ and
|
||||
$icode s$$ has type $icode Scalar$$,
|
||||
$codei%
|
||||
%x%.push_back(%s%)
|
||||
%$$
|
||||
extends the vector $icode x$$ so that its new size is $icode n$$ plus one
|
||||
and $icode%x%[%n%]%$$ is equal to $icode s$$
|
||||
(equal in the sense of the $icode Scalar$$ assignment operator).
|
||||
|
||||
$head push_vector$$
|
||||
If $icode x$$ is a $codei%CppAD::vector<%Scalar%>%$$ object
|
||||
with size equal to $icode n$$ and
|
||||
$icode v$$ is a $cref/simple vector/SimpleVector/$$
|
||||
with elements of type $icode Scalar$$ and size $icode m$$,
|
||||
$codei%
|
||||
%x%.push_vector(%v%)
|
||||
%$$
|
||||
extends the vector $icode x$$ so that its new size is $icode%n%+%m%$$
|
||||
and $icode%x%[%n% + %i%]%$$ is equal to $icode%v%[%i%]%$$
|
||||
for $icode%i = 1 , ... , m-1%$$
|
||||
(equal in the sense of the $icode Scalar$$ assignment operator).
|
||||
|
||||
$head Output$$
|
||||
If $icode x$$ is a $codei%CppAD::vector<%Scalar%>%$$ object
|
||||
and $icode os$$ is an $code std::ostream$$,
|
||||
and the operation
|
||||
$codei%
|
||||
%os% << %x%
|
||||
%$$
|
||||
will output the vector $icode x$$ to the standard
|
||||
output stream $icode os$$.
|
||||
The elements of $icode x$$ are enclosed at the beginning by a
|
||||
$code {$$ character,
|
||||
they are separated by $code ,$$ characters,
|
||||
and they are enclosed at the end by $code }$$ character.
|
||||
It is assumed by this operation that if $icode e$$
|
||||
is an object with type $icode Scalar$$,
|
||||
$codei%
|
||||
%os% << %e%
|
||||
%$$
|
||||
will output the value $icode e$$ to the standard
|
||||
output stream $icode os$$.
|
||||
|
||||
$head resize$$
|
||||
The call $icode%x%.resize(%n%)%$$ set the size of $icode x$$ equal to
|
||||
$icode n$$.
|
||||
If $icode%n% <= %x%.capacity()%$$,
|
||||
no memory is freed or allocated, the capacity of $icode x$$ does not change,
|
||||
and the data in $icode x$$ is preserved.
|
||||
If $icode%n% > %x%.capacity()%$$,
|
||||
new memory is allocated and the data in $icode x$$ is lost
|
||||
(not copied to the new memory location).
|
||||
|
||||
$head clear$$
|
||||
All memory allocated for the vector is freed
|
||||
and both its size and capacity are set to zero.
|
||||
This can be useful when using very large vectors
|
||||
and when checking for memory leaks (and there are global vectors)
|
||||
see the $cref/memory/CppAD_vector/Memory and Parallel Mode/$$ discussion.
|
||||
|
||||
$head data$$
|
||||
If $icode x$$ is a $codei%CppAD::vector<%Scalar%>%$$ object
|
||||
$codei%
|
||||
%x%.data()
|
||||
%$$
|
||||
returns a pointer to a $icode Scalar$$ object such that for
|
||||
$codei%0 <= %i% < %x%.size()%$$,
|
||||
$icode%x%[%i%]%$$ and $icode%x%.data()[%i%]%$$
|
||||
are the same $icode Scalar$$ object.
|
||||
If $icode x$$ is $code const$$, the pointer is $code const$$.
|
||||
If $icode%x%.capacity()%$$ is zero, the value of the pointer is not defined.
|
||||
The pointer may no longer be valid after the following operations on
|
||||
$icode x$$:
|
||||
its destructor,
|
||||
$code clear$$,
|
||||
$code resize$$,
|
||||
$code push_back$$,
|
||||
$code push_vector$$,
|
||||
assignment to another vector when original size of $icode x$$ is zero.
|
||||
|
||||
$head vectorBool$$
|
||||
The file $code <cppad/vector.hpp>$$ also defines the class
|
||||
$code CppAD::vectorBool$$.
|
||||
This has the same specifications as $code CppAD::vector<bool>$$
|
||||
with the following exceptions:
|
||||
|
||||
$subhead Memory$$
|
||||
The class $code vectorBool$$ conserves on memory
|
||||
(on the other hand, $code CppAD::vector<bool>$$ is expected to be faster
|
||||
than $code vectorBool$$).
|
||||
|
||||
$subhead bit_per_unit$$
|
||||
The static function call
|
||||
$codei%
|
||||
%s% = vectorBool::bit_per_unit()
|
||||
%$$
|
||||
returns the $code size_t$$ value $icode s$$
|
||||
which is equal to the number of boolean values (bits) that are
|
||||
packed into one operational unit.
|
||||
For example, a logical $code or$$
|
||||
acts on this many boolean values with one operation.
|
||||
|
||||
$subhead data$$
|
||||
The $cref/data/CppAD_vector/data/$$ function is not supported by
|
||||
$code vectorBool$$.
|
||||
|
||||
$subhead Output$$
|
||||
The $code CppAD::vectorBool$$ output operator
|
||||
prints each boolean value as
|
||||
a $code 0$$ for false,
|
||||
a $code 1$$ for true,
|
||||
and does not print any other output; i.e.,
|
||||
the vector is written a long sequence of zeros and ones with no
|
||||
surrounding $code {$$, $code }$$ and with no separating commas or spaces.
|
||||
|
||||
$subhead Element Type$$
|
||||
If $icode x$$ has type $code vectorBool$$
|
||||
and $icode i$$ has type $code size_t$$,
|
||||
the element access value $icode%x%[%i%]%$$ has an unspecified type,
|
||||
referred to here as $icode elementType$$, that supports the following
|
||||
operations:
|
||||
|
||||
$list number$$
|
||||
$icode elementType$$ can be converted to $code bool$$; e.g.
|
||||
the following syntax is supported:
|
||||
$codei%
|
||||
static_cast<bool>( %x%[%i%] )
|
||||
%$$
|
||||
|
||||
$lnext
|
||||
$icode elementType$$ supports the assignment operator $code =$$ where the
|
||||
right hand side is a $code bool$$ or an $icode elementType$$ object; e.g.,
|
||||
if $icode y$$ has type $code bool$$, the following syntax is supported:
|
||||
$codei%
|
||||
%x%[%i%] = %y%
|
||||
%$$
|
||||
|
||||
$lnext
|
||||
The result of an assignment to an $icode elementType$$
|
||||
also has type $icode elementType$$.
|
||||
Thus, if $icode z$$ has type $code bool$$, the following syntax is supported:
|
||||
$codei%
|
||||
%z% = %x%[%i%] = %y%
|
||||
%$$
|
||||
$lend
|
||||
|
||||
$head Memory and Parallel Mode$$
|
||||
These vectors use the multi-threaded fast memory allocator
|
||||
$cref thread_alloc$$:
|
||||
|
||||
$list number$$
|
||||
The routine $cref/parallel_setup/ta_parallel_setup/$$ must
|
||||
be called before these vectors can be used
|
||||
$cref/in parallel/ta_in_parallel/$$.
|
||||
$lnext
|
||||
Using these vectors affects the amount of memory
|
||||
$cref/in_use/ta_inuse/$$ and $cref/available/ta_available/$$.
|
||||
$lnext
|
||||
Calling $cref/clear/CppAD_vector/clear/$$,
|
||||
makes the corresponding memory available (though $code thread_alloc$$)
|
||||
to the current thread.
|
||||
$lnext
|
||||
Available memory
|
||||
can then be completely freed using $cref/free_available/ta_free_available/$$.
|
||||
$lend
|
||||
|
||||
$head Example$$
|
||||
$children%
|
||||
example/utility/cppad_vector.cpp%
|
||||
example/utility/vector_bool.cpp
|
||||
%$$
|
||||
The files
|
||||
$cref cppad_vector.cpp$$ and
|
||||
$cref vector_bool.cpp$$ each
|
||||
contain an example and test of this template class.
|
||||
They return true if they succeed and false otherwise.
|
||||
|
||||
$head Exercise$$
|
||||
Create and run a program that contains the following code:
|
||||
$codep
|
||||
CppAD::vector<double> x(3);
|
||||
size_t i;
|
||||
for(i = 0; i < 3; i++)
|
||||
x[i] = 4. - i;
|
||||
std::cout << "x = " << x << std::endl;
|
||||
$$
|
||||
|
||||
$end
|
||||
|
||||
|
||||
$end
|
||||
|
||||
------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
# include <cstddef>
|
||||
# include <iostream>
|
||||
# include <limits>
|
||||
# include <cppad/core/cppad_assert.hpp>
|
||||
# include <cppad/utility/check_simple_vector.hpp>
|
||||
# include <cppad/utility/thread_alloc.hpp>
|
||||
|
||||
namespace CppAD { // BEGIN_CPPAD_NAMESPACE
|
||||
/*!
|
||||
\file vector.hpp
|
||||
File used to define CppAD::vector and CppAD::vectorBool
|
||||
*/
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
/*!
|
||||
The CppAD Simple Vector template class.
|
||||
*/
|
||||
template <class Type>
|
||||
class vector {
|
||||
private:
|
||||
/// maximum number of Type elements current allocation can hold
|
||||
size_t capacity_;
|
||||
/// number of Type elements currently in this vector
|
||||
size_t length_;
|
||||
/// pointer to the first type elements
|
||||
/// (not defined and should not be used when capacity_ = 0)
|
||||
Type* data_;
|
||||
/// delete data pointer
|
||||
void delete_data(Type* data_ptr)
|
||||
{ thread_alloc::delete_array(data_ptr); }
|
||||
public:
|
||||
/// type of the elements in the vector
|
||||
typedef Type value_type;
|
||||
|
||||
/// default constructor sets capacity_ = length_ = data_ = 0
|
||||
inline vector(void)
|
||||
: capacity_(0), length_(0), data_(CPPAD_NULL)
|
||||
{ }
|
||||
/// sizing constructor
|
||||
inline vector(
|
||||
/// number of elements in this vector
|
||||
size_t n
|
||||
) : capacity_(0), length_(0), data_(CPPAD_NULL)
|
||||
{ resize(n); }
|
||||
|
||||
/// copy constructor
|
||||
inline vector(
|
||||
/// the *this vector will be a copy of \c x
|
||||
const vector& x
|
||||
) : capacity_(0), length_(0), data_(CPPAD_NULL)
|
||||
{ resize(x.length_);
|
||||
|
||||
// copy the data
|
||||
for(size_t i = 0; i < length_; i++)
|
||||
data_[i] = x.data_[i];
|
||||
}
|
||||
/// destructor
|
||||
~vector(void)
|
||||
{ if( capacity_ > 0 )
|
||||
delete_data(data_);
|
||||
}
|
||||
|
||||
/// maximum number of elements current allocation can store
|
||||
inline size_t capacity(void) const
|
||||
{ return capacity_; }
|
||||
|
||||
/// number of elements currently in this vector.
|
||||
inline size_t size(void) const
|
||||
{ return length_; }
|
||||
|
||||
/// raw pointer to the data
|
||||
inline Type* data(void)
|
||||
{ return data_; }
|
||||
|
||||
/// const raw pointer to the data
|
||||
inline const Type* data(void) const
|
||||
{ return data_; }
|
||||
|
||||
/// change the number of elements in this vector.
|
||||
inline void resize(
|
||||
/// new number of elements for this vector
|
||||
size_t n
|
||||
)
|
||||
{ length_ = n;
|
||||
|
||||
// check if we must allocate new memory
|
||||
if( capacity_ < length_ )
|
||||
{
|
||||
// check if there is old memory to be freed
|
||||
if( capacity_ > 0 )
|
||||
delete_data(data_);
|
||||
|
||||
// get new memory and set capacity
|
||||
data_ = thread_alloc::create_array<Type>(length_, capacity_);
|
||||
}
|
||||
}
|
||||
|
||||
/// free memory and set number of elements to zero
|
||||
inline void clear(void)
|
||||
{ length_ = 0;
|
||||
// check if there is old memory to be freed
|
||||
if( capacity_ > 0 )
|
||||
delete_data(data_);
|
||||
capacity_ = 0;
|
||||
}
|
||||
|
||||
/// vector assignment operator
|
||||
inline vector& operator=(
|
||||
/// right hand size of the assingment operation
|
||||
const vector& x
|
||||
)
|
||||
{ size_t i;
|
||||
// If original lenght is zero, then resize it.
|
||||
// Otherwise a length mismatch is an error.
|
||||
if( length_ == 0 )
|
||||
resize( x.length_ );
|
||||
CPPAD_ASSERT_KNOWN(
|
||||
length_ == x.length_ ,
|
||||
"vector: size miss match in assignment operation"
|
||||
);
|
||||
for(i = 0; i < length_; i++)
|
||||
data_[i] = x.data_[i];
|
||||
return *this;
|
||||
}
|
||||
# if CPPAD_USE_CPLUSPLUS_2011
|
||||
/// vector assignment operator with move semantics
|
||||
inline vector& operator=(
|
||||
/// right hand size of the assingment operation
|
||||
vector&& x
|
||||
)
|
||||
{ CPPAD_ASSERT_KNOWN(
|
||||
length_ == x.length_ || (length_ == 0),
|
||||
"vector: size miss match in assignment operation"
|
||||
);
|
||||
if( this != &x )
|
||||
{ clear();
|
||||
//
|
||||
length_ = x.length_;
|
||||
capacity_ = x.capacity_;
|
||||
data_ = x.data_;
|
||||
//
|
||||
x.length_ = 0;
|
||||
x.capacity_ = 0;
|
||||
x.data_ = CPPAD_NULL;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
# endif
|
||||
/// non-constant element access; i.e., we can change this element value
|
||||
Type& operator[](
|
||||
/// element index, must be less than length
|
||||
size_t i
|
||||
)
|
||||
{ CPPAD_ASSERT_KNOWN(
|
||||
i < length_,
|
||||
"vector: index greater than or equal vector size"
|
||||
);
|
||||
return data_[i];
|
||||
}
|
||||
/// constant element access; i.e., we cannot change this element value
|
||||
const Type& operator[](
|
||||
/// element index, must be less than length
|
||||
size_t i
|
||||
) const
|
||||
{ CPPAD_ASSERT_KNOWN(
|
||||
i < length_,
|
||||
"vector: index greater than or equal vector size"
|
||||
);
|
||||
return data_[i];
|
||||
}
|
||||
/// add an element to the back of this vector
|
||||
void push_back(
|
||||
/// value of the element
|
||||
const Type& s
|
||||
)
|
||||
{ // case where no allocation is necessary
|
||||
if( length_ + 1 <= capacity_ )
|
||||
{ data_[length_++] = s;
|
||||
return;
|
||||
}
|
||||
CPPAD_ASSERT_UNKNOWN( length_ == capacity_ );
|
||||
|
||||
// store old length, capacity and data
|
||||
size_t old_length = length_;
|
||||
size_t old_capacity = capacity_;
|
||||
Type* old_data = data_;
|
||||
|
||||
// set the new length, capacity and data
|
||||
length_ = 0;
|
||||
capacity_ = 0;
|
||||
resize(old_length + 1);
|
||||
|
||||
// copy old data values
|
||||
for(size_t i = 0; i < old_length; i++)
|
||||
data_[i] = old_data[i];
|
||||
|
||||
// put the new element in the vector
|
||||
CPPAD_ASSERT_UNKNOWN( old_length + 1 <= capacity_ );
|
||||
data_[old_length] = s;
|
||||
|
||||
// free old data
|
||||
if( old_capacity > 0 )
|
||||
delete_data(old_data);
|
||||
|
||||
CPPAD_ASSERT_UNKNOWN( old_length + 1 == length_ );
|
||||
CPPAD_ASSERT_UNKNOWN( length_ <= capacity_ );
|
||||
}
|
||||
|
||||
/*! add vector to the back of this vector
|
||||
(we could not use push_back because MS V++ 7.1 did not resolve
|
||||
to non-template member function when scalar is used.)
|
||||
*/
|
||||
template <class Vector>
|
||||
void push_vector(
|
||||
/// value of the vector that we are adding
|
||||
const Vector& v
|
||||
)
|
||||
{ CheckSimpleVector<Type, Vector>();
|
||||
size_t m = v.size();
|
||||
|
||||
// case where no allcoation is necessary
|
||||
if( length_ + m <= capacity_ )
|
||||
{ for(size_t i = 0; i < m; i++)
|
||||
data_[length_++] = v[i];
|
||||
return;
|
||||
}
|
||||
|
||||
// store old length, capacity and data
|
||||
size_t old_length = length_;
|
||||
size_t old_capacity = capacity_;
|
||||
Type* old_data = data_;
|
||||
|
||||
// set new length, capacity and data
|
||||
length_ = 0;
|
||||
capacity_ = 0;
|
||||
resize(old_length + m);
|
||||
|
||||
// copy old data values
|
||||
for(size_t i = 0; i < old_length; i++)
|
||||
data_[i] = old_data[i];
|
||||
|
||||
// put the new elements in the vector
|
||||
CPPAD_ASSERT_UNKNOWN( old_length + m <= capacity_ );
|
||||
for(size_t i = 0; i < m; i++)
|
||||
data_[old_length + i] = v[i];
|
||||
|
||||
// free old data
|
||||
if( old_capacity > 0 )
|
||||
delete_data(old_data);
|
||||
|
||||
CPPAD_ASSERT_UNKNOWN( old_length + m == length_ );
|
||||
CPPAD_ASSERT_UNKNOWN( length_ <= capacity_ );
|
||||
}
|
||||
};
|
||||
|
||||
/// output a vector
|
||||
template <class Type>
|
||||
inline std::ostream& operator << (
|
||||
/// stream to write the vector to
|
||||
std::ostream& os ,
|
||||
/// vector that is output
|
||||
const CppAD::vector<Type>& vec )
|
||||
{ size_t i = 0;
|
||||
size_t n = vec.size();
|
||||
|
||||
os << "{ ";
|
||||
while(i < n)
|
||||
{ os << vec[i++];
|
||||
if( i < n )
|
||||
os << ", ";
|
||||
}
|
||||
os << " }";
|
||||
return os;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
/*!
|
||||
Class that is used to hold a non-constant element of a vector.
|
||||
*/
|
||||
class vectorBoolElement {
|
||||
/// the boolean data is packed with sizeof(UnitType) bits per value
|
||||
typedef size_t UnitType;
|
||||
private:
|
||||
/// pointer to the UnitType value holding this eleemnt
|
||||
UnitType* unit_;
|
||||
/// mask for the bit corresponding to this element
|
||||
/// (all zero except for bit that corresponds to this element)
|
||||
UnitType mask_;
|
||||
public:
|
||||
/// constructor from member values
|
||||
vectorBoolElement(
|
||||
/// unit for this element
|
||||
UnitType* unit ,
|
||||
/// mask for this element
|
||||
UnitType mask )
|
||||
: unit_(unit) , mask_(mask)
|
||||
{ }
|
||||
/// constuctor from another element
|
||||
vectorBoolElement(
|
||||
/// other element
|
||||
const vectorBoolElement& e )
|
||||
: unit_(e.unit_) , mask_(e.mask_)
|
||||
{ }
|
||||
/// conversion to a boolean value
|
||||
operator bool() const
|
||||
{ return (*unit_ & mask_) != 0; }
|
||||
/// assignment of this element to a bool
|
||||
vectorBoolElement& operator=(
|
||||
/// right hand side for assignment
|
||||
bool bit
|
||||
)
|
||||
{ if(bit)
|
||||
*unit_ |= mask_;
|
||||
else *unit_ &= ~mask_;
|
||||
return *this;
|
||||
}
|
||||
/// assignment of this element to another element
|
||||
vectorBoolElement& operator=(const vectorBoolElement& e)
|
||||
{ if( *(e.unit_) & e.mask_ )
|
||||
*unit_ |= mask_;
|
||||
else *unit_ &= ~mask_;
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
class vectorBool {
|
||||
/// the boolean data is packed with sizeof(UnitType) bits per value
|
||||
typedef size_t UnitType;
|
||||
private:
|
||||
/// number of bits packed into each UnitType value in data_
|
||||
static const size_t bit_per_unit_
|
||||
= std::numeric_limits<UnitType>::digits;
|
||||
/// number of UnitType values in data_
|
||||
size_t n_unit_;
|
||||
/// number of bits currently stored in this vector
|
||||
size_t length_;
|
||||
/// pointer to where the bits are stored
|
||||
UnitType *data_;
|
||||
|
||||
/// minimum number of UnitType values that can store length_ bits
|
||||
/// (note that this is really a function of length_)
|
||||
size_t unit_min(void)
|
||||
{ if( length_ == 0 )
|
||||
return 0;
|
||||
return (length_ - 1) / bit_per_unit_ + 1;
|
||||
}
|
||||
public:
|
||||
/// type corresponding to the elements of this vector
|
||||
/// (note that non-const elements actually use vectorBoolElement)
|
||||
typedef bool value_type;
|
||||
|
||||
// static member function
|
||||
static size_t bit_per_unit(void)
|
||||
{ return bit_per_unit_; }
|
||||
|
||||
/// default constructor (sets all member data to zero)
|
||||
inline vectorBool(void) : n_unit_(0), length_(0), data_(CPPAD_NULL)
|
||||
{ }
|
||||
/// sizing constructor
|
||||
inline vectorBool(
|
||||
/// number of bits in this vector
|
||||
size_t n
|
||||
) : n_unit_(0), length_(n), data_(CPPAD_NULL)
|
||||
{ if( length_ > 0 )
|
||||
{ // set n_unit and data
|
||||
size_t min_unit = unit_min();
|
||||
data_ = thread_alloc::create_array<UnitType>(min_unit, n_unit_);
|
||||
}
|
||||
}
|
||||
/// copy constructor
|
||||
inline vectorBool(
|
||||
/// the *this vector will be a copy of \c v
|
||||
const vectorBool& v
|
||||
) : n_unit_(0), length_(v.length_), data_(CPPAD_NULL)
|
||||
{ if( length_ > 0 )
|
||||
{ // set n_unit and data
|
||||
size_t min_unit = unit_min();
|
||||
data_ = thread_alloc::create_array<UnitType>(min_unit, n_unit_);
|
||||
|
||||
// copy values using UnitType assignment operator
|
||||
CPPAD_ASSERT_UNKNOWN( min_unit <= v.n_unit_ );
|
||||
size_t i;
|
||||
for(i = 0; i < min_unit; i++)
|
||||
data_[i] = v.data_[i];
|
||||
}
|
||||
}
|
||||
/// destructor
|
||||
~vectorBool(void)
|
||||
{ if( n_unit_ > 0 )
|
||||
thread_alloc::delete_array(data_);
|
||||
}
|
||||
|
||||
/// number of elements in this vector
|
||||
inline size_t size(void) const
|
||||
{ return length_; }
|
||||
|
||||
/// maximum number of elements current allocation can store
|
||||
inline size_t capacity(void) const
|
||||
{ return n_unit_ * bit_per_unit_; }
|
||||
|
||||
/// change number of elements in this vector
|
||||
inline void resize(
|
||||
/// new number of elements for this vector
|
||||
size_t n
|
||||
)
|
||||
{ length_ = n;
|
||||
// check if we can use the current memory
|
||||
size_t min_unit = unit_min();
|
||||
if( n_unit_ >= min_unit )
|
||||
return;
|
||||
// check if there is old memory to be freed
|
||||
if( n_unit_ > 0 )
|
||||
thread_alloc::delete_array(data_);
|
||||
// get new memory and set n_unit
|
||||
data_ = thread_alloc::create_array<UnitType>(min_unit, n_unit_);
|
||||
}
|
||||
|
||||
/// free memory and set number of elements to zero
|
||||
inline void clear(void)
|
||||
{ length_ = 0;
|
||||
// check if there is old memory to be freed
|
||||
if( n_unit_ > 0 )
|
||||
thread_alloc::delete_array(data_);
|
||||
n_unit_ = 0;
|
||||
}
|
||||
|
||||
/// vector assignment operator
|
||||
inline vectorBool& operator=(
|
||||
/// right hand size of the assingment operation
|
||||
const vectorBool& v
|
||||
)
|
||||
{ size_t i;
|
||||
// If original lenght is zero, then resize it.
|
||||
// Otherwise a length mismatch is an error.
|
||||
if( length_ == 0 )
|
||||
resize( v.length_ );
|
||||
CPPAD_ASSERT_KNOWN(
|
||||
length_ == v.length_ ,
|
||||
"vectorBool: size miss match in assignment operation"
|
||||
);
|
||||
size_t min_unit = unit_min();
|
||||
CPPAD_ASSERT_UNKNOWN( min_unit <= n_unit_ );
|
||||
CPPAD_ASSERT_UNKNOWN( min_unit <= v.n_unit_ );
|
||||
for(i = 0; i < min_unit; i++)
|
||||
data_[i] = v.data_[i];
|
||||
return *this;
|
||||
}
|
||||
# if CPPAD_USE_CPLUSPLUS_2011
|
||||
/// vector assignment operator with move semantics
|
||||
inline vectorBool& operator=(
|
||||
/// right hand size of the assingment operation
|
||||
vectorBool&& x
|
||||
)
|
||||
{ CPPAD_ASSERT_KNOWN(
|
||||
length_ == x.length_ || (length_ == 0),
|
||||
"vectorBool: size miss match in assignment operation"
|
||||
);
|
||||
if( this != &x )
|
||||
{ clear();
|
||||
//
|
||||
length_ = x.length_;
|
||||
n_unit_ = x.n_unit_;
|
||||
data_ = x.data_;
|
||||
//
|
||||
x.length_ = 0;
|
||||
x.n_unit_ = 0;
|
||||
x.data_ = CPPAD_NULL;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
# endif
|
||||
|
||||
|
||||
/// non-constant element access; i.e., we can change this element value
|
||||
vectorBoolElement operator[](
|
||||
/// element index, must be less than length
|
||||
size_t k
|
||||
)
|
||||
{ size_t i, j;
|
||||
CPPAD_ASSERT_KNOWN(
|
||||
k < length_,
|
||||
"vectorBool: index greater than or equal vector size"
|
||||
);
|
||||
i = k / bit_per_unit_;
|
||||
j = k - i * bit_per_unit_;
|
||||
return vectorBoolElement(data_ + i , UnitType(1) << j );
|
||||
}
|
||||
/// constant element access; i.e., we cannot change this element value
|
||||
bool operator[](size_t k) const
|
||||
{ size_t i, j;
|
||||
UnitType unit, mask;
|
||||
CPPAD_ASSERT_KNOWN(
|
||||
k < length_,
|
||||
"vectorBool: index greater than or equal vector size"
|
||||
);
|
||||
i = k / bit_per_unit_;
|
||||
j = k - i * bit_per_unit_;
|
||||
unit = data_[i];
|
||||
mask = UnitType(1) << j;
|
||||
return (unit & mask) != 0;
|
||||
}
|
||||
/// add an element to the back of this vector
|
||||
void push_back(
|
||||
/// value of the element
|
||||
bool bit
|
||||
)
|
||||
{ CPPAD_ASSERT_UNKNOWN( unit_min() <= n_unit_ );
|
||||
size_t i, j;
|
||||
UnitType mask;
|
||||
if( length_ + 1 > n_unit_ * bit_per_unit_ )
|
||||
{ CPPAD_ASSERT_UNKNOWN( unit_min() == n_unit_ );
|
||||
// store old n_unit and data values
|
||||
size_t old_n_unit = n_unit_;
|
||||
UnitType* old_data = data_;
|
||||
// set new n_unit and data values
|
||||
data_ = thread_alloc::create_array<UnitType>(n_unit_+1, n_unit_);
|
||||
// copy old data values
|
||||
for(i = 0; i < old_n_unit; i++)
|
||||
data_[i] = old_data[i];
|
||||
// free old data
|
||||
if( old_n_unit > 0 )
|
||||
thread_alloc::delete_array(old_data);
|
||||
}
|
||||
i = length_ / bit_per_unit_;
|
||||
j = length_ - i * bit_per_unit_;
|
||||
mask = UnitType(1) << j;
|
||||
if( bit )
|
||||
data_[i] |= mask;
|
||||
else data_[i] &= ~mask;
|
||||
length_++;
|
||||
}
|
||||
/// add vector to the back of this vector
|
||||
template <class Vector>
|
||||
void push_vector(
|
||||
/// value of the vector that we are adding
|
||||
const Vector& v
|
||||
)
|
||||
{ CheckSimpleVector<bool, Vector>();
|
||||
size_t min_unit = unit_min();
|
||||
CPPAD_ASSERT_UNKNOWN( length_ <= n_unit_ * bit_per_unit_ );
|
||||
// some temporaries
|
||||
size_t i, j, k, ell;
|
||||
UnitType mask;
|
||||
bool bit;
|
||||
// store old length
|
||||
size_t old_length = length_;
|
||||
// new length and minium number of units;
|
||||
length_ = length_ + v.size();
|
||||
min_unit = unit_min();
|
||||
if( length_ >= n_unit_ * bit_per_unit_ )
|
||||
{ // store old n_unit and data value
|
||||
size_t old_n_unit = n_unit_;
|
||||
UnitType* old_data = data_;
|
||||
// set new n_unit and data values
|
||||
data_ = thread_alloc::create_array<UnitType>(min_unit, n_unit_);
|
||||
// copy old data values
|
||||
for(i = 0; i < old_n_unit; i++)
|
||||
data_[i] = old_data[i];
|
||||
// free old data
|
||||
if( old_n_unit > 0 )
|
||||
thread_alloc::delete_array(old_data);
|
||||
}
|
||||
ell = old_length;
|
||||
for(k = 0; k < v.size(); k++)
|
||||
{
|
||||
i = ell / bit_per_unit_;
|
||||
j = ell - i * bit_per_unit_;
|
||||
bit = v[k];
|
||||
mask = UnitType(1) << j;
|
||||
if( bit )
|
||||
data_[i] |= mask;
|
||||
else data_[i] &= ~mask;
|
||||
ell++;
|
||||
}
|
||||
CPPAD_ASSERT_UNKNOWN( length_ == ell );
|
||||
CPPAD_ASSERT_UNKNOWN( length_ <= n_unit_ * bit_per_unit_ );
|
||||
}
|
||||
};
|
||||
|
||||
/// output a vector
|
||||
inline std::ostream& operator << (
|
||||
/// steam to write the vector to
|
||||
std::ostream& os ,
|
||||
/// vector that is output
|
||||
const vectorBool& v )
|
||||
{ size_t i = 0;
|
||||
size_t n = v.size();
|
||||
|
||||
while(i < n)
|
||||
os << v[i++];
|
||||
return os;
|
||||
}
|
||||
|
||||
} // END_CPPAD_NAMESPACE
|
||||
# endif
|
||||
Reference in New Issue
Block a user