returns samples according to the KDE
		
			Parameters
			----------
				sample_inices: list of ints
					Indices into the training data used as centers for the samples
				
				num_samples: int
					if samples_indices is None, this specifies how many samples
					are drawn.

def sample(self, sample_indices=None, num_samples=1):
		""" returns samples according to the KDE
		
			Parameters
			----------
				sample_inices: list of ints
					Indices into the training data used as centers for the samples
				
				num_samples: int
					if samples_indices is None, this specifies how many samples
					are drawn.
				
		"""
		if sample_indices is None:
			sample_indices = np.random.choice(self.data.shape[0], size=num_samples)
		samples = self.data[sample_indices]

		possible_steps = np.arange(-self.num_values+1,self.num_values)
		idx = (np.abs(possible_steps) < 1e-2)
		
		ps = 0.5*(1-self.bw) * np.power(self.bw, np.abs(possible_steps))
		ps[idx] = (1-self.bw)
		ps /= ps.sum()
		
		delta = np.zeros_like(samples)
		oob_idx = np.arange(samples.shape[0])

		while len(oob_idx) > 0:
			samples[oob_idx] -= delta[oob_idx]		# revert move
			delta[oob_idx] = np.random.choice(possible_steps, size=len(oob_idx), p=ps)
			samples[oob_idx] += delta[oob_idx]
			#import pdb; pdb.set_trace()
			oob_idx = oob_idx[np.argwhere(np.logical_or(samples[oob_idx] > self.num_values-0.9, samples[oob_idx] < -0.1)).flatten()]
		return(np.rint(samples))