code: def rematch_entry(envkernel, gamma = 0.1, threshold = 1e-6):
      
      n, m = envkernel.shape
      K = np.exp(-(1 - envkernel) / gamma)
  
      # initialisation
      u = np.ones((n,)) / n
      v = np.ones((m,)) / m
  
      en = np.ones((n,)) / float(n)
      em = np.ones((m,)) / float(m)
  
      Kp = (1 / en).reshape(-1, 1) * K
  
      # converge balancing vectors u and v
      itercount = 0
      error = 1
      while (error > threshold):
          uprev = u
          vprev = v
          v = np.divide(em, np.dot(K.T, u))
          u = np.divide(en, np.dot(K, v))
  
          # determine error every now and then
          if itercount % 5:
              error = np.sum((u - uprev) ** 2) / np.sum((u) ** 2) + np.sum((v - vprev) ** 2) / np.sum((v) ** 2)
          itercount += 1
  
      # using Tr(X.T Y) = Sum[ij](Xij * Yij)
      # P.T * C
      # P_ij = u_i * v_j * K_ij
      pity = np.multiply( np.multiply(K, u.reshape((-1,1))) , v)
  
      glosim = np.sum( np.multiply( pity, envkernel))
  
      return glosim
docs: Compute the global similarity between two structures A and B.
      It uses the Sinkhorn algorithm as reported in:
      Phys. Chem. Chem. Phys., 2016, 18, p. 13768
      Args:
          envkernel: NxM matrix of structure A with 
              N and structure B with M atoms
          gamma: parameter to control between best match gamma = 0
              and average kernel gamma = inf.