Skip to content

Commit

Permalink
Merge pull request #1939 from dhruv13J/develop
Browse files Browse the repository at this point in the history
fixes issue #1888
  • Loading branch information
karlnapf committed Mar 6, 2014
2 parents d590c99 + 56ceab6 commit 577e90e
Show file tree
Hide file tree
Showing 10 changed files with 284 additions and 51 deletions.
59 changes: 28 additions & 31 deletions src/shogun/base/Parameter.cpp
Expand Up @@ -3133,7 +3133,7 @@ void TParameter::copy_data(const TParameter* source)
SG_SDEBUG("leaving TParameter::copy_data for %s\n", m_name)
}

bool TParameter::equals(TParameter* other, float64_t accuracy)
bool TParameter::equals(TParameter* other, float64_t accuracy, bool tolerant)
{
SG_SDEBUG("entering TParameter::equals()\n");

Expand Down Expand Up @@ -3181,7 +3181,7 @@ bool TParameter::equals(TParameter* other, float64_t accuracy)
if (!TParameter::compare_stype(m_datatype.m_stype,
m_datatype.m_ptype, m_parameter,
other->m_parameter,
accuracy))
accuracy, tolerant))
{
SG_SDEBUG("leaving TParameter::equals(): scalar data differs\n");
return false;
Expand All @@ -3204,7 +3204,8 @@ bool TParameter::equals(TParameter* other, float64_t accuracy)
void* pointer_b=&((*(char**)other->m_parameter)[x]);

if (!TParameter::compare_stype(m_datatype.m_stype,
m_datatype.m_ptype, pointer_a, pointer_b, accuracy))
m_datatype.m_ptype, pointer_a, pointer_b,
accuracy, tolerant))
{
SG_SDEBUG("leaving TParameter::equals(): vector element "
"differs\n");
Expand Down Expand Up @@ -3237,14 +3238,15 @@ bool TParameter::equals(TParameter* other, float64_t accuracy)

for (index_t i=0; i<length; ++i)
{
SG_SDEBUG("comparing element %d which is %d byes from start\n",
SG_SDEBUG("comparing element %d which is %d bytes from start\n",
i, x);

void* pointer_a=&((*(char**)m_parameter)[x]);
void* pointer_b=&((*(char**)other->m_parameter)[x]);

if (!TParameter::compare_stype(m_datatype.m_stype,
m_datatype.m_ptype, pointer_a, pointer_b, accuracy))
m_datatype.m_ptype, pointer_a, pointer_b,
accuracy, tolerant))
{
SG_SDEBUG("leaving TParameter::equals(): vector element "
"differs\n");
Expand Down Expand Up @@ -3277,10 +3279,10 @@ bool TParameter::equals(TParameter* other, float64_t accuracy)
}

bool TParameter::compare_ptype(EPrimitiveType ptype, void* data1, void* data2,
floatmax_t accuracy)
float64_t accuracy, bool tolerant)
{
SG_SDEBUG("entering TParameter::compare_ptype()\n");

if ((data1 && !data2) || (!data1 && data2))
{
SG_SINFO("leaving TParameter::compare_ptype(): data1 is at %p while "
Expand Down Expand Up @@ -3431,38 +3433,33 @@ bool TParameter::compare_ptype(EPrimitiveType ptype, void* data1, void* data2,
{
float32_t casted1=*((float32_t*)data1);
float32_t casted2=*((float32_t*)data2);

if (CMath::abs(casted1-casted2)>accuracy)
{
SG_SINFO("leaving TParameter::compare_ptype(): PT_FLOAT32: "
"data1=%f, data2=%f\n", casted1, casted2);
return false;
}

SG_SINFO("leaving TParameter::compare_ptype(): PT_FLOAT32: "
"data1=%f, data2=%f\n", casted1, casted2);

return CMath::fequals<float32_t>(casted1, casted2, accuracy, tolerant);
break;
}
case PT_FLOAT64:
{
float64_t casted1=*((float64_t*)data1);
float64_t casted2=*((float64_t*)data2);

SG_SINFO("leaving TParameter::compare_ptype(): PT_FLOAT64: "
"data1=%f, data2=%f\n", casted1, casted2);

if (CMath::abs(casted1-casted2)>accuracy)
{
SG_SINFO("leaving TParameter::compare_ptype(): PT_FLOAT64: "
"data1=%f, data2=%f\n", casted1, casted2);
return false;
}
return CMath::fequals<float64_t>(casted1, casted2, accuracy, tolerant);
break;
}
case PT_FLOATMAX:
{
floatmax_t casted1=*((floatmax_t*)data1);
floatmax_t casted2=*((floatmax_t*)data2);
if (CMath::abs(casted1-casted2)>accuracy)
{
SG_SINFO("leaving TParameter::compare_ptype(): PT_FLOATMAX: "
"data1=%f, data2=%f\n", casted1, casted2);
return false;
}

SG_SINFO("leaving TParameter::compare_ptype(): PT_FLOATMAX: "
"data1=%f, data2=%f\n", casted1, casted2);

return CMath::fequals<floatmax_t>(casted1, casted2, accuracy, tolerant);
break;
}
case PT_COMPLEX128:
Expand Down Expand Up @@ -3671,10 +3668,10 @@ bool TParameter::copy_ptype(EPrimitiveType ptype, void* source, void* target)
}

bool TParameter::compare_stype(EStructType stype, EPrimitiveType ptype,
void* data1, void* data2, floatmax_t accuracy)
void* data1, void* data2, float64_t accuracy, bool tolerant)
{
SG_SDEBUG("entering TParameter::compare_stype()\n");

size_t size_ptype=TSGDataType::sizeof_ptype(ptype);

/* Avoid comparing NULL */
Expand All @@ -3697,7 +3694,7 @@ bool TParameter::compare_stype(EStructType stype, EPrimitiveType ptype,
case ST_NONE:
{
SG_SDEBUG("ST_NONE\n");
return TParameter::compare_ptype(ptype, data1, data2, accuracy);
return TParameter::compare_ptype(ptype, data1, data2, accuracy, tolerant);
break;
}
case ST_SPARSE:
Expand Down Expand Up @@ -3736,7 +3733,7 @@ bool TParameter::compare_stype(EStructType stype, EPrimitiveType ptype,
void* pointer2=&(cur2->entry)-char_offset+ptype_offset;

if (!TParameter::compare_ptype(ptype, pointer1,
pointer2, accuracy))
pointer2, accuracy, tolerant))
{
SG_SINFO("leaving TParameter::compare_stype(): Data of"
" sparse vector element is different\n");
Expand Down Expand Up @@ -3778,7 +3775,7 @@ bool TParameter::compare_stype(EStructType stype, EPrimitiveType ptype,
void* pointer2=str_ptr2->string+i*size_ptype;

if (!TParameter::compare_ptype(ptype, pointer1,
pointer2, accuracy))
pointer2, accuracy, tolerant))
{
SG_SINFO("leaving TParameter::compare_stype(): Data of"
" string element is different\n");
Expand Down
9 changes: 6 additions & 3 deletions src/shogun/base/Parameter.h
Expand Up @@ -82,9 +82,10 @@ struct TParameter
*
* @param other other instance to compare with
* @param accuracy accuracy for numerical comparison
* @param tolerant allows linient check on float equality (within accuracy)
* @return true if given parameter instance is equal, false otherwise
*/
bool equals(TParameter* other, float64_t accuracy=0.0);
bool equals(TParameter* other, float64_t accuracy=0.0, bool tolerant=false);

/** Given two pointers to a scalar element of a given primitive-type, this
* method compares the values up to a given accuracy.
Expand All @@ -96,10 +97,11 @@ struct TParameter
* @param data1 pointer 1
* @param data2 pointer 2
* @param accuracy accuracy to compare
* @param tolerant allows linient check on float equality (within accuracy)
* @return whether the data was equal
*/
static bool compare_ptype(EPrimitiveType ptype, void* data1, void* data2,
floatmax_t accuracy=0.0);
float64_t accuracy=0.0, bool tolerant=false);

/** Given two pointers to a string element of a given primitive-type, this
* method compares the values up to a given accuracy.
Expand All @@ -112,10 +114,11 @@ struct TParameter
* @param data1 pointer 1
* @param data2 pointer 2
* @param accuracy accuracy to compare
* @param tolerant allows linient check on float equality (within accuracy)
* @return whether the data was equal
*/
static bool compare_stype(EStructType stype, EPrimitiveType ptype,
void* data1, void* data2, floatmax_t accuracy=0.0);
void* data1, void* data2, float64_t accuracy=0.0, bool tolerant=false);

/** copy primitive type from source to target
*
Expand Down
4 changes: 2 additions & 2 deletions src/shogun/base/SGObject.cpp
Expand Up @@ -1192,7 +1192,7 @@ void CSGObject::build_gradient_parameter_dictionary(CMap<TParameter*, CSGObject*
}
}

bool CSGObject::equals(CSGObject* other, float64_t accuracy)
bool CSGObject::equals(CSGObject* other, float64_t accuracy, bool tolerant)
{
SG_DEBUG("entering %s::equals()\n", get_name());

Expand Down Expand Up @@ -1274,7 +1274,7 @@ bool CSGObject::equals(CSGObject* other, float64_t accuracy)
}

/* use equals method of TParameter from here */
if (!this_param->equals(other_param, accuracy))
if (!this_param->equals(other_param, accuracy, tolerant))
{
SG_INFO("leaving %s::equals(): parameters at position %d with name"
" \"%s\" differs from other object parameter with name "
Expand Down
3 changes: 2 additions & 1 deletion src/shogun/base/SGObject.h
Expand Up @@ -413,9 +413,10 @@ class CSGObject : public SGRefObject
*
* @param other object to compare with
* @param accuracy accuracy to use for comparison (optional)
* @param tolerant allows linient check on float equality (within accuracy)
* @return true if all parameters were equal, false if not
*/
virtual bool equals(CSGObject* other, float64_t accuracy=0.0);
virtual bool equals(CSGObject* other, float64_t accuracy=0.0, bool tolerant=false);

/** Creates a clone of the current object. This is done via recursively
* traversing all parameters, which corresponds to a deep copy.
Expand Down
18 changes: 12 additions & 6 deletions src/shogun/mathematics/Math.cpp
Expand Up @@ -20,6 +20,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <float.h>

#ifndef NAN
#include <stdlib.h>
Expand All @@ -44,12 +45,18 @@ int32_t CMath::LOGRANGE = 0; // range for logtable: log(1+exp(x)) -2

const float64_t CMath::NOT_A_NUMBER = NAN;
const float64_t CMath::INFTY = INFINITY; // infinity
const float64_t CMath::ALMOST_INFTY = +1e+20; //a large number
const float64_t CMath::ALMOST_NEG_INFTY = -1000;
const float64_t CMath::ALMOST_INFTY = +1e+300; //a large number
const float64_t CMath::ALMOST_NEG_INFTY = -1e+300;
const float64_t CMath::PI=M_PI;
const float64_t CMath::MACHINE_EPSILON=5E-16;
const float64_t CMath::MAX_REAL_NUMBER=1E300;
const float64_t CMath::MIN_REAL_NUMBER=1E-300;
const float64_t CMath::MACHINE_EPSILON=DBL_EPSILON;
const float64_t CMath::MAX_REAL_NUMBER=DBL_MAX;
const float64_t CMath::MIN_REAL_NUMBER=DBL_MIN;
const float32_t CMath::F_MAX_VAL32=FLT_MAX;
const float32_t CMath::F_MIN_NORM_VAL32=FLT_MIN;
const float64_t CMath::F_MAX_VAL64=DBL_MAX;
const float64_t CMath::F_MIN_NORM_VAL64=DBL_MIN;
const float32_t CMath::F_MIN_VAL32=(FLT_MIN * FLT_EPSILON);
const float64_t CMath::F_MIN_VAL64=(DBL_MIN * DBL_EPSILON);

#ifdef USE_LOGCACHE
float64_t* CMath::logtable = NULL;
Expand Down Expand Up @@ -207,7 +214,6 @@ void CMath::linspace(float64_t* output, float64_t start, float64_t end, int32_t
output[n-1] = end;
}


int CMath::is_nan(double f)
{
#ifndef HAVE_STD_ISNAN
Expand Down
79 changes: 76 additions & 3 deletions src/shogun/mathematics/Math.h
Expand Up @@ -146,7 +146,7 @@ class CMath : public CSGObject
/**@name min/max/abs functions.
*/
//@{

///return the minimum of two integers
//
template <class T>
Expand Down Expand Up @@ -187,7 +187,7 @@ class CMath : public CSGObject
else
return -a;
}

///return the absolute value of a complex number
static inline float64_t abs(complex128_t a)
{
Expand All @@ -199,7 +199,70 @@ class CMath : public CSGObject

/**@name misc functions */
//@{


/** Compares the value of two floats based on eps only
* @param a first value to compare
* @param b second value to compare
* @param eps threshold for values to be equal/different
* @return true if values are equal within eps accuracy, false if not.
*/
template <class T>
static inline bool fequals_abs(const T& a, const T& b,
const float64_t eps)
{
const T diff = CMath::abs<T>((a-b));
return (diff < eps);
}

/** Compares the value of two floats (handles special cases, such as NaN, Inf etc.)
* Note: returns true if a == b == NAN
* Implementation inspired by http://floating-point-gui.de/errors/comparison/
* @param a first value to compare
* @param b second value to compare
* @param eps threshold for values to be equal/different
* @param tolerant allows linient check on float equality (within accuracy)
* @return true if values are equal within eps accuracy, false if not.
*/
template <class T>
static inline bool fequals(const T& a, const T& b,
const float64_t eps, bool tolerant=false)
{
const T absA = CMath::abs<T>(a);
const T absB = CMath::abs<T>(b);
const T diff = CMath::abs<T>((a-b));
T comp;

// Handle this separately since NAN is unordered
if (CMath::is_nan((float64_t)a) && CMath::is_nan((float64_t)b))
return true;

// Required for JSON Serialization Tests
if (tolerant)
return CMath::fequals_abs<T>(a, b, eps);

// handles float32_t and float64_t separately
if (sizeof(T) == 4)
comp = CMath::F_MIN_NORM_VAL32;

else
comp = CMath::F_MIN_NORM_VAL64;

if (a==b)
return true;

// both a and b are 0 and relative error is less meaningful
else if ( (a==0) || (b==0) || (diff < comp) )
return (diff<(eps * comp));

// use max(relative error, diff) to handle large eps
else
{
T check = ((diff/(absA + absB)) > diff)?
(diff/(absA + absB)):diff;
return (check < eps);
}
}

static inline float64_t round(float64_t d)
{
return ::floor(d+0.5);
Expand Down Expand Up @@ -1342,6 +1405,16 @@ class CMath : public CSGObject
/* largest and smallest possible float64_t */
static const float64_t MAX_REAL_NUMBER;
static const float64_t MIN_REAL_NUMBER;

/* Floating point Limits, Normalized */
static const float32_t F_MAX_VAL32;
static const float32_t F_MIN_NORM_VAL32;
static const float64_t F_MAX_VAL64;
static const float64_t F_MIN_NORM_VAL64;

/* Floating point limits, Denormalized */
static const float32_t F_MIN_VAL32;
static const float64_t F_MIN_VAL64;

protected:
/// range for logtable: log(1+exp(x)) -LOGRANGE <= x <= 0
Expand Down
4 changes: 2 additions & 2 deletions tests/integration/python_modular/tester.py
Expand Up @@ -59,7 +59,7 @@ def compare(a, b, tolerance, sgtolerance):
if pickle.dumps(a) == pickle.dumps(b):
result = True
else:
result = a.equals(b, sgtolerance)
result = a.equals(b, sgtolerance, True)

# print debug output in case of failure
if not result:
Expand All @@ -68,7 +68,7 @@ def compare(a, b, tolerance, sgtolerance):
print("Equals failed with debug output")
old_loglevel=a.io.get_loglevel()
a.io.set_loglevel(modshogun.MSG_INFO)
a.equals(b, sgtolerance)
a.equals(b, sgtolerance, True)
a.io.set_loglevel(old_loglevel)

return result
Expand Down

0 comments on commit 577e90e

Please sign in to comment.