we need an autodiff library at some point (or we need to roll our own but I do not think that makes sense). CppAD is well tested and header only and easy to include. It is also Liscene compatible with GPL v3.0. Here we bring it in as a dependency
245 lines
7.1 KiB
C++
245 lines
7.1 KiB
C++
# ifndef CPPAD_LOCAL_HASH_CODE_HPP
|
|
# define CPPAD_LOCAL_HASH_CODE_HPP
|
|
/* --------------------------------------------------------------------------
|
|
CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 Bradley M. Bell
|
|
|
|
CppAD is distributed under the terms of the
|
|
Eclipse Public License Version 2.0.
|
|
|
|
This Source Code may also be made available under the following
|
|
Secondary License when the conditions for such availability set forth
|
|
in the Eclipse Public License, Version 2.0 are satisfied:
|
|
GNU General Public License, Version 2.0 or later.
|
|
---------------------------------------------------------------------------- */
|
|
# include <cppad/core/base_hash.hpp>
|
|
/*!
|
|
\file local/hash_code.hpp
|
|
CppAD hashing utility.
|
|
*/
|
|
|
|
|
|
namespace CppAD { namespace local { // BEGIN_CPPAD_LOCAL_NAMESPACE
|
|
/*!
|
|
General purpose hash code for an arbitrary value.
|
|
|
|
\tparam Value
|
|
is the type of the argument being hash coded.
|
|
It should be a plain old data class; i.e.,
|
|
the values included in the equality operator in the object and
|
|
not pointed to by the object.
|
|
|
|
\param value
|
|
the value that we are generating a hash code for.
|
|
All of the fields in value should have been set before the hash code
|
|
is computed (otherwise undefined values are used).
|
|
|
|
\return
|
|
is a hash code that is between zero and CPPAD_HASH_TABLE_SIZE - 1.
|
|
|
|
\par Checked Assertions
|
|
\li std::numeric_limits<unsigned short>::max() >= CPPAD_HASH_TABLE_SIZE
|
|
\li sizeof(value) is even
|
|
\li sizeof(unsigned short) == 2
|
|
*/
|
|
template <class Value>
|
|
unsigned short local_hash_code(const Value& value)
|
|
{ CPPAD_ASSERT_UNKNOWN(
|
|
std::numeric_limits<unsigned short>::max()
|
|
>=
|
|
CPPAD_HASH_TABLE_SIZE
|
|
);
|
|
CPPAD_ASSERT_UNKNOWN( sizeof(unsigned short) == 2 );
|
|
CPPAD_ASSERT_UNKNOWN( sizeof(value) % 2 == 0 );
|
|
//
|
|
const unsigned short* v
|
|
= reinterpret_cast<const unsigned short*>(& value);
|
|
//
|
|
size_t i = sizeof(value) / 2 - 1;
|
|
//
|
|
size_t sum = v[i];
|
|
//
|
|
while(i--)
|
|
sum += v[i];
|
|
//
|
|
unsigned short code = static_cast<unsigned short>(
|
|
sum % CPPAD_HASH_TABLE_SIZE
|
|
);
|
|
return code;
|
|
}
|
|
|
|
/*!
|
|
Specialized hash code for a CppAD operator and its arguments.
|
|
|
|
\param op
|
|
is the operator that we are computing a hash code for.
|
|
If it is not one of the following operartors, the operator is not
|
|
hash coded and zero is returned:
|
|
|
|
\li unary operators:
|
|
AbsOp, AcosOp, AcoshOp, AsinOp, AsinhOp, AtanOp, AtanhOp, CosOp, CoshOp
|
|
ExpOp, Expm1Op, LogOp, Log1pOp, SinOp, SinhOp, SqrtOp, TanOp, TanhOp
|
|
|
|
\li binary operators where first argument is a parameter:
|
|
AddpvOp, DivpvOp, MulpvOp, PowpvOp, SubpvOp, ZmulpvOp
|
|
|
|
\li binary operators where second argument is a parameter:
|
|
DivvpOp, PowvpOp, SubvpOp, Zmulvp
|
|
|
|
\li binary operators where first is an index and second is a variable:
|
|
DisOp
|
|
|
|
\li binary operators where both arguments are variables:
|
|
AddvvOp, DivvvOp, MulvvOp, PowvvOp, SubvvOp, ZmulvvOp
|
|
|
|
\param arg
|
|
is a vector of length NumArg(op) or 2 (which ever is smaller),
|
|
containing the corresponding argument indices for this operator.
|
|
|
|
\param npar
|
|
is the number of parameters corresponding to this operation sequence.
|
|
|
|
\param par
|
|
is a vector of length npar containing the parameters
|
|
for this operation sequence; i.e.,
|
|
given a parameter index of i, the corresponding parameter value is
|
|
par[i].
|
|
|
|
|
|
\return
|
|
is a hash code that is between zero and CPPAD_HASH_TABLE_SIZE - 1.
|
|
|
|
\par Checked Assertions
|
|
op must be one of the operators specified above. In addition,
|
|
\li std::numeric_limits<unsigned short>::max() >= CPPAD_HASH_TABLE_SIZE
|
|
\li sizeof(size_t) is even
|
|
\li sizeof(Base) is even
|
|
\li sizeof(unsigned short) == 2
|
|
\li size_t(op) < size_t(NumberOp) <= CPPAD_HASH_TABLE_SIZE
|
|
\li if the j-th argument for this operation is a parameter, arg[j] < npar.
|
|
*/
|
|
|
|
template <class Base>
|
|
unsigned short local_hash_code(
|
|
OpCode op ,
|
|
const addr_t* arg ,
|
|
size_t npar ,
|
|
const Base* par )
|
|
{ CPPAD_ASSERT_UNKNOWN(
|
|
std::numeric_limits<unsigned short>::max()
|
|
>=
|
|
CPPAD_HASH_TABLE_SIZE
|
|
);
|
|
CPPAD_ASSERT_UNKNOWN( size_t (op) < size_t(NumberOp) );
|
|
CPPAD_ASSERT_UNKNOWN( sizeof(unsigned short) == 2 );
|
|
CPPAD_ASSERT_UNKNOWN( sizeof(addr_t) % 2 == 0 );
|
|
CPPAD_ASSERT_UNKNOWN( sizeof(Base) % 2 == 0 );
|
|
unsigned short op_fac = static_cast<unsigned short> (
|
|
CPPAD_HASH_TABLE_SIZE / static_cast<unsigned short>(NumberOp)
|
|
);
|
|
CPPAD_ASSERT_UNKNOWN( op_fac > 0 );
|
|
|
|
// number of shorts per addr_t value
|
|
size_t short_addr_t = sizeof(addr_t) / 2;
|
|
|
|
// initialize with value that separates operators as much as possible
|
|
unsigned short code = static_cast<unsigned short>(
|
|
static_cast<unsigned short>(op) * op_fac
|
|
);
|
|
|
|
// now code in the operands
|
|
size_t i;
|
|
const unsigned short* v;
|
|
|
|
// first argument
|
|
switch(op)
|
|
{ // Binary operators where first arugment is a parameter.
|
|
// Code parameters by value instead of
|
|
// by index for two reasons. One, it gives better separation.
|
|
// Two, different indices can be same parameter value.
|
|
case AddpvOp:
|
|
case DivpvOp:
|
|
case MulpvOp:
|
|
case PowpvOp:
|
|
case SubpvOp:
|
|
case ZmulpvOp:
|
|
CPPAD_ASSERT_UNKNOWN( NumArg(op) == 2 );
|
|
code += hash_code( par[arg[0]] );
|
|
//
|
|
v = reinterpret_cast<const unsigned short*>(arg + 1);
|
|
i = short_addr_t;
|
|
while(i--)
|
|
code += v[i];
|
|
break;
|
|
|
|
// Binary operator where first argument is an index and
|
|
// second is a variable (same as both variables).
|
|
case DisOp:
|
|
|
|
// Binary operators where both arguments are variables
|
|
case AddvvOp:
|
|
case DivvvOp:
|
|
case MulvvOp:
|
|
case PowvvOp:
|
|
case SubvvOp:
|
|
case ZmulvvOp:
|
|
CPPAD_ASSERT_UNKNOWN( NumArg(op) == 2 );
|
|
v = reinterpret_cast<const unsigned short*>(arg + 0);
|
|
i = 2 * short_addr_t;
|
|
while(i--)
|
|
code += v[i];
|
|
break;
|
|
|
|
// Binary operators where second arugment is a parameter.
|
|
case DivvpOp:
|
|
case PowvpOp:
|
|
case SubvpOp:
|
|
case ZmulvpOp:
|
|
CPPAD_ASSERT_UNKNOWN( NumArg(op) == 2 );
|
|
v = reinterpret_cast<const unsigned short*>(arg + 0);
|
|
i = short_addr_t;
|
|
while(i--)
|
|
code += v[i];
|
|
code += hash_code( par[arg[1]] );
|
|
break;
|
|
|
|
// Unary operators
|
|
case AbsOp:
|
|
case AcosOp:
|
|
case AcoshOp:
|
|
case AsinOp:
|
|
case AsinhOp:
|
|
case AtanOp:
|
|
case AtanhOp:
|
|
case CosOp:
|
|
case CoshOp:
|
|
case ErfOp:
|
|
case ErfcOp:
|
|
case ExpOp:
|
|
case Expm1Op:
|
|
case LogOp:
|
|
case Log1pOp:
|
|
case SignOp:
|
|
case SinOp:
|
|
case SinhOp:
|
|
case SqrtOp:
|
|
case TanOp:
|
|
case TanhOp:
|
|
CPPAD_ASSERT_UNKNOWN( NumArg(op) == 1 || op == ErfOp );
|
|
v = reinterpret_cast<const unsigned short*>(arg + 0);
|
|
i = short_addr_t;
|
|
while(i--)
|
|
code += v[i];
|
|
break;
|
|
|
|
// should have been one of he cases above
|
|
default:
|
|
CPPAD_ASSERT_UNKNOWN(false);
|
|
}
|
|
|
|
return code % CPPAD_HASH_TABLE_SIZE;
|
|
}
|
|
|
|
} } // END_CPPAD_LOCAL_NAMESPACE
|
|
|
|
# endif
|