docs: def __crand(self):
          """
          conditional randomization
  
          for observation i with ni neighbors,  the candidate set cannot include
          i (we don't want i being a neighbor of i). we have to sample without
          replacement from a set of ids that doesn't include i. numpy doesn't
          directly support sampling wo replacement and it is expensive to
          implement this. instead we omit i from the original ids,  permute the
          ids and take the first ni elements of the permuted ids as the
          neighbors to i in each randomization.
  
          """
          lisas = np.zeros((self.n, self.permutations))
          n_1 = self.n - 1
          prange = list(range(self.permutations))
          k = self.w.max_neighbors + 1
          nn = self.n - 1
          rids = np.array([np.random.permutation(nn)[0:k] for i in prange])
          ids = np.arange(self.w.n)
          ido = self.w.id_order
          w = [self.w.weights[ido[i]] for i in ids]
          wc = [self.w.cardinalities[ido[i]] for i in ids]
  
          zx = self.zx
          zy = self.zy
          for i in range(self.w.n):
              idsi = ids[ids != i]
              np.random.shuffle(idsi)
              tmp = zy[idsi[rids[:, 0:wc[i]]]]
              lisas[i] = zx[i] * (w[i] * tmp).sum(1)
          self.rlisas = (n_1 / self.den) * lisas