Skip to content

Commit

Permalink
A fix for #272
Browse files Browse the repository at this point in the history
  • Loading branch information
searchivairus committed Jan 16, 2018
1 parent 5bc234b commit e4d3084
Show file tree
Hide file tree
Showing 11 changed files with 220 additions and 53 deletions.
10 changes: 7 additions & 3 deletions similarity_search/include/distcomp.h
Original file line number Diff line number Diff line change
Expand Up @@ -198,15 +198,19 @@ template <typename T> T LPGenericDistanceOptim(const T* x, const T* y, const int
* estimators for image classification”. In: Computer Vision and Pattern Recognition (CVPR), 2012 IEEE
* Conference on, pages 2989–2996
*/
template <typename T> T alpha_beta_divergence(const T* x, const T* y, const int length, float alpha, float beta);
template <typename T> T alphaBetaDivergence(const T *x, const T *y, const int length, float alpha, float beta);
template <typename T> T alphaBetaDivergenceFast(const T *x, const T *y, const int length, float alpha, float beta);

// A proxy function for alpha-beta divergence that may be used during indexing
template <typename T> T alpha_beta_divergence_proxy(const T* x, const T* y, const int length, float alpha, float beta);
template <typename T> T alphaBetaDivergenceProxy(const T *x, const T *y, const int length, float alpha, float beta);
template <typename T> T alphaBetaDivergenceFastProxy(const T *x, const T *y, const int length, float alpha, float beta);
/*
* Renyi divergence.
* Rényi, Alfréd (1961). "On measures of information and entropy".
* Proceedings of the fourth Berkeley Symposium on Mathematics, Statistics and Probability 1960. pp. 547–561.
*/
template <typename T> T renyi_divergence(const T* x, const T* y, const int length, float alpha);
template <typename T> T renyiDivergence(const T *x, const T *y, const int length, float alpha);
template <typename T> T renyiDivergenceFast(const T *x, const T *y, const int length, float alpha);


/*
Expand Down
6 changes: 4 additions & 2 deletions similarity_search/include/factory/init_spaces.h
Original file line number Diff line number Diff line change
Expand Up @@ -141,8 +141,10 @@ inline void initSpaces() {
REGISTER_SPACE_CREATOR(float, SPACE_AB_DIVERG, CreateAlphaBetaDiverg)
REGISTER_SPACE_CREATOR(double, SPACE_AB_DIVERG, CreateAlphaBetaDiverg)

REGISTER_SPACE_CREATOR(float, SPACE_RENYI_DIVERG, CreateRenyiDiverg)
REGISTER_SPACE_CREATOR(double, SPACE_RENYI_DIVERG, CreateRenyiDiverg)
REGISTER_SPACE_CREATOR(float, SPACE_RENYI_DIVERG_SLOW, CreateRenyiDivergSlow)
REGISTER_SPACE_CREATOR(double, SPACE_RENYI_DIVERG_SLOW, CreateRenyiDivergSlow)
REGISTER_SPACE_CREATOR(float, SPACE_RENYI_DIVERG_FAST, CreateRenyiDivergFast)
REGISTER_SPACE_CREATOR(double, SPACE_RENYI_DIVERG_FAST, CreateRenyiDivergFast)

}

Expand Down
18 changes: 16 additions & 2 deletions similarity_search/include/factory/space/space_renyi_diverg.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
namespace similarity {

template <typename dist_t>
Space<dist_t>* CreateRenyiDiverg(const AnyParams& AllParams) {
Space<dist_t>* CreateRenyiDivergSlow(const AnyParams& AllParams) {
AnyParamManager pmgr(AllParams);

float alpha = 0.5;
Expand All @@ -35,7 +35,21 @@ Space<dist_t>* CreateRenyiDiverg(const AnyParams& AllParams) {
CHECK_MSG(std::fabs(alpha - 1) > 2*std::numeric_limits<float>::min() && alpha > 0,
"alpha should be > 0 and != 1");

return new SpaceRenyiDiverg<dist_t>(alpha);
return new SpaceRenyiDivergSlow<dist_t>(alpha);
}

template <typename dist_t>
Space<dist_t>* CreateRenyiDivergFast(const AnyParams& AllParams) {
AnyParamManager pmgr(AllParams);

float alpha = 0.5;

pmgr.GetParamOptional("alpha", alpha, alpha);

CHECK_MSG(std::fabs(alpha - 1) > 2*std::numeric_limits<float>::min() && alpha > 0,
"alpha should be > 0 and != 1");

return new SpaceRenyiDivergFast<dist_t>(alpha);
}

/*
Expand Down
15 changes: 9 additions & 6 deletions similarity_search/include/pow.h
Original file line number Diff line number Diff line change
Expand Up @@ -204,12 +204,12 @@ class PowerProxyObject {
* @param maxDig a maximum number of binary digits to consider (should be <= 31).
*/
PowerProxyObject(const T p, const unsigned maxDig = 18) {
CHECK_MSG(p >= 0, "The exponent should be non-negative");

pOrig_ = p;
isNeg_ = p < 0;
p_ = (isNeg_) ? -p : p;
maxK_ = 1u << maxDig;
unsigned pfm = static_cast<unsigned>(std::floor(maxK_ * p));
unsigned pfm = static_cast<unsigned>(std::floor(maxK_ * p_));

p_ = p;
isOptim_ = (fabs(maxK_*p_ - pfm) <= 2 * std::numeric_limits<T>::min());
intPow_ = pfm >> maxDig;
fractPow_ = pfm - (intPow_ << maxDig);
Expand All @@ -220,16 +220,19 @@ class PowerProxyObject {
* Compute pow(base, p_) possibly efficiently. We expect base to be
* non-negative!
*/
T inline pow(const T base) {
T inline pow(T base) {
if (isOptim_) {
if (isNeg_) base = 1/base; // Negative power
T mult1 = intPow_ ? EfficientPow(base, intPow_) : 1;
T mult2 = fractPow_ ? EfficientFractPowUtil(base, fractPow_, maxK_) : 1;
return mult1 * mult2;
} else {
return std::pow(base, p_);
return std::pow(base, pOrig_);
}
}
private:
bool isNeg_;
T pOrig_;
T p_;
unsigned maxK_;
bool isOptim_;
Expand Down
31 changes: 23 additions & 8 deletions similarity_search/include/space/space_renyi_diverg.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,28 +30,43 @@
#include "space_vector.h"
#include "distcomp.h"

#define SPACE_RENYI_DIVERG "renyi_diverg"
#define SPACE_RENYI_DIVERG_SLOW "renyidiv_slow"
#define SPACE_RENYI_DIVERG_FAST "renyidiv_fast"

namespace similarity {



/*
* Renyi divergence.
* Renyi divergences.
*
*/

template <typename dist_t>
class SpaceRenyiDiverg : public VectorSpaceSimpleStorage<dist_t> {
class SpaceRenyiDivergSlow : public VectorSpaceSimpleStorage<dist_t> {
public:
explicit SpaceRenyiDiverg(float alpha) : alpha_(alpha) {}
virtual ~SpaceRenyiDiverg() {}
explicit SpaceRenyiDivergSlow(float alpha) : alpha_(alpha) {}
virtual ~SpaceRenyiDivergSlow() {}

virtual std::string StrDesc() const;
virtual std::string StrDesc() const override;
protected:
virtual dist_t HiddenDistance(const Object* obj1, const Object* obj2) const;
virtual dist_t HiddenDistance(const Object* obj1, const Object* obj2) const override;
private:
DISABLE_COPY_AND_ASSIGN(SpaceRenyiDiverg);
DISABLE_COPY_AND_ASSIGN(SpaceRenyiDivergSlow);
float alpha_;
};

template <typename dist_t>
class SpaceRenyiDivergFast : public VectorSpaceSimpleStorage<dist_t> {
public:
explicit SpaceRenyiDivergFast(float alpha) : alpha_(alpha) {}
virtual ~SpaceRenyiDivergFast() {}

virtual std::string StrDesc() const override;
protected:
virtual dist_t HiddenDistance(const Object* obj1, const Object* obj2) const override;
private:
DISABLE_COPY_AND_ASSIGN(SpaceRenyiDivergFast);
float alpha_;
};

Expand Down
16 changes: 8 additions & 8 deletions similarity_search/include/space/space_sparse_scalar_fast.h
Original file line number Diff line number Diff line change
Expand Up @@ -75,14 +75,14 @@ class SpaceDotProdPivotIndexBase: public PivotIndex<float> {
class SpaceSparseCosineSimilarityFast : public SpaceSparseVectorInter<float> {
public:
explicit SpaceSparseCosineSimilarityFast(){}
virtual std::string StrDesc() const {
virtual std::string StrDesc() const override {
return SPACE_SPARSE_COSINE_SIMILARITY_FAST;
}
virtual PivotIndex<float>* CreatePivotIndex(const ObjectVector& pivots, size_t hashTrickDim = 0) const override {
return new PivotIndexLocal(*this, pivots, hashTrickDim);
}
protected:
virtual float HiddenDistance(const Object* obj1, const Object* obj2) const;
virtual float HiddenDistance(const Object* obj1, const Object* obj2) const override;

class PivotIndexLocal : public SpaceDotProdPivotIndexBase {
public:
Expand All @@ -102,15 +102,15 @@ class SpaceSparseCosineSimilarityFast : public SpaceSparseVectorInter<float> {
class SpaceSparseAngularDistanceFast : public SpaceSparseVectorInter<float> {
public:
explicit SpaceSparseAngularDistanceFast(){}
virtual std::string StrDesc() const {
virtual std::string StrDesc() const override {
return SPACE_SPARSE_ANGULAR_DISTANCE_FAST;
}

virtual PivotIndex<float>* CreatePivotIndex(const ObjectVector& pivots, size_t hashTrickDim = 0) const override {
return new PivotIndexLocal(*this, pivots, hashTrickDim);
}
protected:
virtual float HiddenDistance(const Object* obj1, const Object* obj2) const;
virtual float HiddenDistance(const Object* obj1, const Object* obj2) const override;

class PivotIndexLocal : public SpaceDotProdPivotIndexBase {
public:
Expand All @@ -131,15 +131,15 @@ class SpaceSparseAngularDistanceFast : public SpaceSparseVectorInter<float> {
class SpaceSparseNegativeScalarProductFast : public SpaceSparseVectorInter<float> {
public:
explicit SpaceSparseNegativeScalarProductFast(){}
virtual std::string StrDesc() const {
virtual std::string StrDesc() const override {
return SPACE_SPARSE_NEGATIVE_SCALAR_FAST;
}

virtual PivotIndex<float>* CreatePivotIndex(const ObjectVector& pivots, size_t hashTrickDim = 0) const override {
return new PivotIndexLocal(*this, pivots, hashTrickDim);
}
protected:
virtual float HiddenDistance(const Object* obj1, const Object* obj2) const;
virtual float HiddenDistance(const Object* obj1, const Object* obj2) const override;

class PivotIndexLocal : public SpaceDotProdPivotIndexBase {
public:
Expand All @@ -159,15 +159,15 @@ class SpaceSparseNegativeScalarProductFast : public SpaceSparseVectorInter<float
class SpaceSparseQueryNormNegativeScalarProductFast : public SpaceSparseVectorInter<float> {
public:
explicit SpaceSparseQueryNormNegativeScalarProductFast(){}
virtual std::string StrDesc() const {
virtual std::string StrDesc() const override {
return SPACE_SPARSE_QUERY_NORM_NEGATIVE_SCALAR_FAST;
}

virtual PivotIndex<float>* CreatePivotIndex(const ObjectVector& pivots, size_t hashTrickDim = 0) const override {
return new PivotIndexLocal(*this, pivots, hashTrickDim);
}
protected:
virtual float HiddenDistance(const Object* obj1, const Object* obj2) const;
virtual float HiddenDistance(const Object* obj1, const Object* obj2) const override;

class PivotIndexLocal : public SpaceDotProdPivotIndexBase {
public:
Expand Down
73 changes: 59 additions & 14 deletions similarity_search/src/distcomp_diverg.cc
Original file line number Diff line number Diff line change
Expand Up @@ -22,37 +22,65 @@
#include "distcomp.h"
#include "logging.h"
#include "utils.h"
#include "pow.h"

namespace similarity {

using namespace std;

template <typename T> T alpha_beta_divergence(const T* x, const T* y, const int length, float alpha, float beta) {
template <typename T> T alphaBetaDivergence(const T *x, const T *y, const int length, float alpha, float beta) {
T res = 0;
float alpha1 = alpha + 1;
float alphaPlus1 = alpha + 1;
for (int i = 0; i < length; ++i) {
res += pow(x[i], alpha1)*pow(y[i], beta);
res += pow(x[i], alphaPlus1)*pow(y[i], beta);
}
return res;
}

template float alpha_beta_divergence(const float* x, const float* y, const int length, float alpha, float beta);
template double alpha_beta_divergence(const double* x, const double* y, const int length, float alpha, float beta);
template float alphaBetaDivergence(const float* x, const float* y, const int length, float alpha, float beta);
template double alphaBetaDivergence(const double* x, const double* y, const int length, float alpha, float beta);

template <typename T> T alpha_beta_divergence_proxy(const T* x, const T* y, const int length, float alpha, float beta) {
template <typename T> T alphaBetaDivergenceFast(const T *x, const T *y, const int length, float alpha, float beta) {
T res = 0;
float alpha1 = alpha + 1;
PowerProxyObject<T> powalphaPlus1(alpha + 1), powBeta(beta);

for (int i = 0; i < length; ++i) {
res += powalphaPlus1.pow(x[i])*powBeta.pow(y[i]);
}
return res;
}

template float alphaBetaDivergenceFast(const float* x, const float* y, const int length, float alpha, float beta);
template double alphaBetaDivergenceFast(const double* x, const double* y, const int length, float alpha, float beta);

template <typename T> T alphaBetaDivergenceProxy(const T *x, const T *y, const int length, float alpha, float beta) {
T res = 0;
float alphaPlus1 = alpha + 1;
for (int i = 0; i < length; ++i) {
res += (pow(x[i], alphaPlus1)*pow(y[i], beta) +
pow(y[i], alphaPlus1)*pow(x[i], beta)) * 0.5;
}
return res;
}

template float alphaBetaDivergenceProxy(const float* x, const float* y, const int length, float alpha, float beta);
template double alphaBetaDivergenceProxy(const double* x, const double* y, const int length, float alpha, float beta);

template <typename T> T alphaBetaDivergenceFastProxy(const T *x, const T *y, const int length, float alpha, float beta) {
PowerProxyObject<T> powalphaPlus1(alpha + 1), powBeta(beta);
T res = 0;

for (int i = 0; i < length; ++i) {
res += (pow(x[i], alpha1)*pow(y[i], beta) +
pow(y[i], alpha1)*pow(x[i], beta)) * 0.5;
res += powalphaPlus1.pow(x[i])* powBeta.pow(y[i]) +
powalphaPlus1.pow(y[i])* powBeta.pow(x[i]) * 0.5;
}
return res;
}

template float alpha_beta_divergence_proxy(const float* x, const float* y, const int length, float alpha, float beta);
template double alpha_beta_divergence_proxy(const double* x, const double* y, const int length, float alpha, float beta);
template float alphaBetaDivergenceFastProxy(const float* x, const float* y, const int length, float alpha, float beta);
template double alphaBetaDivergenceFastProxy(const double* x, const double* y, const int length, float alpha, float beta);

template <typename T> T renyi_divergence(const T* x, const T* y, const int length, float alpha) {
template <typename T> T renyiDivergence(const T *x, const T *y, const int length, float alpha) {
T sum = 0;
T eps = -1e-6;
float t = alpha-1;
Expand All @@ -65,7 +93,24 @@ template <typename T> T renyi_divergence(const T* x, const T* y, const int lengt
return max<T>(0, res);
}

template float renyi_divergence(const float* x, const float* y, const int length, float alpha);
template double renyi_divergence(const double* x, const double* y, const int length, float alpha);
template float renyiDivergence(const float* x, const float* y, const int length, float alpha);
template double renyiDivergence(const double* x, const double* y, const int length, float alpha);

template <typename T> T renyiDivergenceFast(const T *x, const T *y, const int length, float alpha) {
float t = alpha-1;
PowerProxyObject<T> powAlphaMinusOne(t);
T sum = 0;
T eps = -1e-6;
for (int i = 0; i < length; ++i) {
sum += x[i]*powAlphaMinusOne.pow(x[i]/y[i]);
}
float res = 1/t * log(sum);
CHECK_MSG(res >= eps, "Expected a non-negative result, but got " + ConvertToString(res) + " for alpha=" + ConvertToString(alpha));
// Might be slightly negative due to rounding errors
return max<T>(0, res);
}

template float renyiDivergenceFast(const float* x, const float* y, const int length, float alpha);
template double renyiDivergenceFast(const double* x, const double* y, const int length, float alpha);

}
4 changes: 2 additions & 2 deletions similarity_search/src/space/space_ab_diverg.cc
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ dist_t SpaceAlphaBetaDiverg<dist_t>::HiddenDistance(const Object* obj1, const Ob
const dist_t* y = reinterpret_cast<const dist_t*>(obj2->data());
const size_t length = obj1->datalength() / sizeof(dist_t);

return alpha_beta_divergence(x, y, length, alpha_, beta_);
return alphaBetaDivergence(x, y, length, alpha_, beta_);
}

template <typename dist_t>
Expand All @@ -44,7 +44,7 @@ dist_t SpaceAlphaBetaDiverg<dist_t>::ProxyDistance(const Object* obj1, const Obj
const dist_t* y = reinterpret_cast<const dist_t*>(obj2->data());
const size_t length = obj1->datalength() / sizeof(dist_t);

return alpha_beta_divergence_proxy(x, y, length, alpha_, beta_);
return alphaBetaDivergenceProxy(x, y, length, alpha_, beta_);
}

template <typename dist_t>
Expand Down
Loading

0 comments on commit e4d3084

Please sign in to comment.