import numpy as np
from .abstract_hash import AbstractHash
from scipy.special import ndtr # for collision_probability

class L2Hash(AbstractHash):
	def __init__(self, r:float, **kwargs):
		self.r = r
		super().__init__(**kwargs)
		# set up the gaussian random projection vectors

		np.random.seed(self.seed)
		self.W = np.random.normal(size = (self.N,self.d))
		self.b = np.random.uniform(low = 0,high = self.r,size = self.N)

	def _hash(self,x):
		return np.floor( (np.squeeze(np.dot(self.W,x)) + self.b)/self.r )

	def _hashMulti(self, X):
		h = np.dot(self.W,X.T) + self.b[:,np.newaxis]
		h /= self.r
		return np.floor(h)

	def kernel(self, x, y):
		try:
			c = np.linalg.norm(x-y)
			p = 1 - 2*ndtr(-self.r/c) - 2.0/(np.sqrt(2*np.pi)*(self.r/c)) * (1 - np.exp(-0.5 * (self.r**2)/(c**2)))
			return p
		except:
			return 1
