AlphaFold3 / flax_model /alphafold3 /parsers /cpp /msa_conversion_pybind.cc
OneScience's picture
Upload folder using huggingface_hub
35cdf53 verified
Raw
History Blame Contribute Delete
5.45 kB
// Copyright 2024 DeepMind Technologies Limited
//
// AlphaFold 3 source code is licensed under CC BY-NC-SA 4.0. To view a copy of
// this license, visit https://creativecommons.org/licenses/by-nc-sa/4.0/
//
// To request access to the AlphaFold 3 model parameters, follow the process set
// out at https://github.com/google-deepmind/alphafold3. You may only use these
// if received directly from Google. Use is subject to terms of use available at
// https://github.com/google-deepmind/alphafold3/blob/main/WEIGHTS_TERMS_OF_USE.md
#include <algorithm>
#include <cstddef>
#include <stdexcept>
#include <string>
#include <vector>
#include "absl/strings/ascii.h"
#include "absl/strings/str_format.h"
#include "absl/strings/string_view.h"
#include "pybind11/pybind11.h"
#include "pybind11/stl.h"
namespace {
namespace py = pybind11;
std::vector<std::string> ConvertA3MToStockholm(
std::vector<absl::string_view> a3m_sequences) {
std::vector<std::string> stockholm_sequences(a3m_sequences.size());
auto max_length_element =
std::max_element(a3m_sequences.begin(), a3m_sequences.end(),
[](absl::string_view lhs, absl::string_view rhs) {
return lhs.size() < rhs.size();
});
for (auto& out : stockholm_sequences) {
out.reserve(max_length_element->size());
}
// While any sequence has remaining columns.
while (std::any_of(a3m_sequences.begin(), a3m_sequences.end(),
[](absl::string_view in) { return !in.empty(); })) {
if (std::any_of(a3m_sequences.begin(), a3m_sequences.end(),
[](absl::string_view in) {
return !in.empty() && absl::ascii_islower(in.front());
})) {
// Insertion(s) found at column.
for (std::size_t i = 0; i < a3m_sequences.size(); ++i) {
absl::string_view& in = a3m_sequences[i];
std::string& out = stockholm_sequences[i];
if (!in.empty() && absl::ascii_islower(in.front())) {
// Consume insertion.
out.push_back(absl::ascii_toupper(in.front()));
in.remove_prefix(1);
} else {
// Row requires padding.
out.push_back('-');
}
}
} else {
// No insertions found.
for (std::size_t i = 0; i < a3m_sequences.size(); ++i) {
absl::string_view& in = a3m_sequences[i];
std::string& out = stockholm_sequences[i];
if (!in.empty()) {
// Consume entire column.
out.push_back(in.front());
in.remove_prefix(1);
} else {
// One alignment is shorter than the others. Should not happen with
// valid A3M input.
throw std::invalid_argument(absl::StrFormat(
"a3m rows have inconsistent lengths; row %d has no columns left "
"but not all rows are exhausted",
i));
}
}
}
}
return stockholm_sequences;
}
std::string AlignSequenceToGaplessQuery(absl::string_view sequence,
absl::string_view query_sequence) {
if (sequence.size() != query_sequence.size()) {
throw py::value_error(
absl::StrFormat("The sequence (%d) and the query sequence (%d) don't "
"have the same length.",
sequence.size(), query_sequence.size()));
}
std::string output;
for (std::size_t residue_index = 0, sequence_length = sequence.size();
residue_index < sequence_length; ++residue_index) {
const char query_residue = query_sequence[residue_index];
const char residue = sequence[residue_index];
if (query_residue != '-') {
// No gap in the query, so the residue is aligned.
output += residue;
} else if (residue == '-') {
// Gap in both sequence and query, simply skip.
continue;
} else {
// Gap only in the query, so this must be an inserted residue.
output += absl::ascii_tolower(residue);
}
}
return output;
}
constexpr char kConvertA3mToStockholm[] = R"(
Converts a list of sequences in a3m format to stockholm format sequences.
As an example if the input is:
abCD
CgD
fCDa
Then the output will be:
ABC-D-
--CGD-
F-C-DA
Args:
a3m_sequences: A list of strings in a3m format.
Returns
A list of strings converted to stockholm format.
)";
constexpr char kAlignSequenceToGaplessQuery[] = R"(
Aligns a sequence to a gapless query sequence.
This is useful when converting Stockholm MSA to A3M MSA. Example:
Seq : AB--E
Query: A--DE
Output: Ab-E.
Args:
sequence: A string containing to be aligned.
query_sequence: A string containing the reference sequence to align to.
Returns
The input sequence with gaps dropped where both the `sequence` and
`query_sequence` have gaps, and sequence elements non-capitalized where the
`query_sequence` has a gap, but the `sequence` does not.
)";
} // namespace
namespace alphafold3 {
void RegisterModuleMsaConversion(pybind11::module m) {
m.def("convert_a3m_to_stockholm", &ConvertA3MToStockholm,
py::arg("a3m_sequences"), py::call_guard<py::gil_scoped_release>(),
py::doc(kConvertA3mToStockholm + 1));
m.def("align_sequence_to_gapless_query", &AlignSequenceToGaplessQuery,
py::arg("sequence"), py::arg("query_sequence"),
py::call_guard<py::gil_scoped_release>(),
py::doc(kAlignSequenceToGaplessQuery + 1));
}
} // namespace alphafold3