Status ResolveQubitIds()

in tensorflow_quantum/core/src/program_resolution.cc [85:180]


Status ResolveQubitIds(Program* program, unsigned int* num_qubits,
                       std::vector<PauliSum>* p_sums /*=nullptr*/,
                       bool swap_endianness /*=false*/) {
  if (program->circuit().moments().empty()) {
    // (#679) Just ignore empty program.
    // Number of qubits in empty programs is zero.
    *num_qubits = 0;
    return Status::OK();
  }

  absl::flat_hash_set<std::pair<std::pair<int, int>, std::string>> id_set;
  for (const Moment& moment : program->circuit().moments()) {
    for (const Operation& operation : moment.operations()) {
      Status s;
      for (const Qubit& qubit : operation.qubits()) {
        s = RegisterQubits(qubit.id(), &id_set);
        if (!s.ok()) {
          return s;
        }
      }
      s = RegisterQubits(
          operation.args().at("control_qubits").arg_value().string_value(),
          &id_set);
      if (!s.ok()) {
        return s;
      }
    }
  }
  *num_qubits = id_set.size();

  // call to std::sort will do (r1 < r2) || ((r1 == r2) && c1 < c2)
  std::vector<std::pair<std::pair<int, int>, std::string>> ids(id_set.begin(),
                                                               id_set.end());
  std::sort(ids.begin(), ids.end());

  // reverse endian.
  if (swap_endianness) {
    std::reverse(ids.begin(), ids.end());
  }
  absl::flat_hash_map<std::string, std::string> id_to_index;
  for (size_t i = 0; i < ids.size(); i++) {
    id_to_index[ids[i].second] = absl::StrCat(i);
  }

  // Replace the Program Qubit ids with the indices.
  for (Moment& moment : *program->mutable_circuit()->mutable_moments()) {
    for (Operation& operation : *moment.mutable_operations()) {
      // Resolve qubit ids.
      for (Qubit& qubit : *operation.mutable_qubits()) {
        qubit.set_id(id_to_index.at(qubit.id()));
      }
      // reverse endian.
      if (swap_endianness) {
        std::reverse(operation.mutable_qubits()->begin(),
                     operation.mutable_qubits()->end());
      }
      // Resolve control qubit ids found in the control_qubits arg.
      absl::string_view control_qubits =
          operation.args().at("control_qubits").arg_value().string_value();
      // explicit empty value set in serializer.py.
      if (control_qubits.empty()) {
        continue;
      }
      std::vector<absl::string_view> control_ids =
          absl::StrSplit(control_qubits, ',');
      std::vector<std::string> control_indexs;
      control_indexs.reserve(control_ids.size());
      for (auto id : control_ids) {
        control_indexs.push_back(id_to_index.at(id));
      }
      operation.mutable_args()
          ->at("control_qubits")
          .mutable_arg_value()
          ->set_string_value(absl::StrJoin(control_indexs, ","));
    }
  }

  if (p_sums) {
    for (size_t i = 0; i < p_sums->size(); i++) {
      // Replace the PauliSum Qubit ids with the indices.
      for (PauliTerm& term : *(p_sums->at(i)).mutable_terms()) {
        for (PauliQubitPair& pair : *term.mutable_paulis()) {
          const auto result = id_to_index.find(pair.qubit_id());
          if (result == id_to_index.end()) {
            return Status(
                tensorflow::error::INVALID_ARGUMENT,
                "Found a Pauli sum operating on qubits not found in circuit.");
          }
          pair.set_qubit_id(result->second);
        }
      }
    }
  }

  return Status::OK();
}