code: def sample(self, sample_indices=None, num_samples=1):
  		
  		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))
docs: 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.