docs: def _computeUnnormalizedLogWeights(self, u_n):
          """
          Return unnormalized log weights.
  
          REQUIRED ARGUMENTS
            u_n (N np float64 array) - reduced potential energies at single state
  
          OPTIONAL ARGUMENTS
  
          RETURN VALUES
            log_w_n (N array) - unnormalized log weights of each of a number of states
  
          REFERENCE
            'log weights' here refers to \log [ \sum_{k=1}^K N_k exp[f_k - (u_k(x_n) - u(x_n)] ]
          """
  
          if (self.use_embedded_helper_code):
              # Use embedded C++ optimizations.
              import _pymbar
              # necessary for helper code to interpret type of u_kn
              u_n = np.array(u_n, dtype=np.float64)
              log_w_n = _pymbar.computeUnnormalizedLogWeightsCpp(
                  self.K, self.N, self.K_nonzero, self.states_with_samples, self.N_k, self.f_k, self.u_kn, u_n)
          else:
              try:
                  from scipy import weave
                  # Allocate storage for return values.
                  log_w_n = np.zeros([self.N], dtype=np.float64)
                  # Copy useful class members to local variables.
                  K = self.K
                  f_k = self.f_k
                  N = self.N
                  N_k = self.N_k
                  u_kn = self.u_kn
                  # Weave inline C++ code.
                  code = """
          double log_terms[%(K)d]; // temporary storage for log terms
          for (int n = 0; n < N; n++) {
              double max_log_term = 0.0;
              bool first_nonzero = true;
              for (int k = 0; k < K; k++) {
                // skip empty states
                if (N_K1(k) == 0) continue;
                double log_term = log(N_K1(k)) + F_K1(k) - U_KN2(k,n) + U_N1(n);
                log_terms[k] = log_term;
                if (first_nonzero || (log_term > max_log_term)) {
                  max_log_term = log_term;
                  first_nonzero = false;
                }
              }
  
              double term_sum = 0.0;
              for (int k = 0; k < K; k++) {
                // skip empty states
                if (N_K1(k) == 0) continue;
                term_sum += exp(log_terms[k] - max_log_term);
              }
              double log_term_sum = log(term_sum) + max_log_term;
              LOG_W_N1(n) = - log_term_sum;
          }
          """ % vars()
                  # Execute inline C code with weave.
                  info = weave.inline(
                      code, ['K', 'N', 'N_k', 'u_n', 'u_kn', 'f_k', 'log_w_n'], headers=['<math.h>', '<stdlib.h>'], verbose=2)
              except:
                  # Compute unnormalized log weights in pure Python.
                  log_w_n = np.zeros([self.N], dtype=np.float64)
                  for n in range(0, self.N):
                      log_w_n[n] = - _logsum(np.log(self.N_k[self.states_with_samples]) +
                                             self.f_k[self.states_with_samples] -
                                             (self.u_kn[self.states_with_samples, n] - u_n[n]))
  
          return log_w_n