class AbstractHash:
	def __init__(self, N:int, d:int, seed:int = 42, **kwargs):
		self.d = d # dimensionality of the data
		self.N = N # number of hashes
		self.seed = seed # random seed

	def _hash(self, x):
		# hash x -> array of N hash codes
		raise NotImplementedError()

	def _hashMulti(self, X):
		# hash X (m x d) -> array of (m x N) hash codes
		raise NotImplementedError()

	def hashModel(self, theta):
		return self._hash(theta)

	def hashData(self, x):
		return self._hash(x)

	def hashModelMulti(self, theta):
		return self._hashMulti(theta)

	def hashDataMulti(self, X):
		return self._hashMulti(X)

	def kernel(self, x, y): 
		raise NotImplementedError()
