external folder

This commit is contained in:
George Hotz
2020-01-17 10:33:21 -08:00
parent 23c2d02682
commit 6abffe0ede
578 changed files with 140675 additions and 0 deletions
@@ -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
+175
View File
@@ -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
+235
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
+214
View File
@@ -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
View File
@@ -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
View File
@@ -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
+595
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
+326
View File
@@ -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
+214
View File
@@ -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
View File
@@ -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
View File
@@ -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
+88
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
+166
View File
@@ -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
File diff suppressed because it is too large Load Diff
+234
View File
@@ -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
View File
@@ -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
+542
View File
@@ -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
View File
@@ -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