///|
fn integer_array_text(values : Array[Int32]) -> String {
let output = StringBuilder()
output.write_char('[')
for index = 0; index < values.length(); index = index + 1 {
if index > 0 {
output.write_string(", ")
}
output.write_string(values[index].to_string())
}
output.write_char(']')
output.to_string()
}
///|
fn main {
println("=== Biopython Bio.Align.msf Demo ===")
let alignment = @src.msf_parse(@src.msf_example_text()) catch {
MsfError(message) => abort("MSF parsing failed: " + message)
}
println("\n1. Parse interleaved MSF metadata and rows")
println(" " + alignment.summary())
println(" title: " + alignment.metadata.title)
for sequence in alignment.sequences {
println(
" " +
sequence.id +
": residues=" +
sequence.length.to_string() +
", weight=" +
sequence.weight.to_string() +
", checksum=" +
sequence.checksum.to_string(),
)
}
println("\n2. Build a Biopython-style coordinate path")
let path = alignment.coordinate_path()
for row = 0; row < alignment.num_sequences(); row = row + 1 {
println(
" " + alignment.sequences[row].id + ": " + integer_array_text(path[row]),
)
}
println(
" reference residue 4 -> query_one residue " +
alignment.map_position(0, 1, 4).unwrap_or(-1).to_string(),
)
println(
" reference residue 3 -> query_one residue " +
alignment.map_position(0, 1, 3).unwrap_or(-1).to_string() +
" (-1 denotes a gap)",
)
println("\n3. Calculate pair statistics and consensus")
let counts = alignment.pair_counts(0, 2) catch {
MsfError(message) => abort("pair counting failed: " + message)
}
println(
" aligned=" +
counts.aligned.to_string() +
", identities=" +
counts.identities.to_string() +
", mismatches=" +
counts.mismatches.to_string() +
", gap opens=" +
counts.gap_opens.to_string(),
)
let consensus = alignment.consensus(minimum_fraction=0.67) catch {
MsfError(message) => abort("consensus failed: " + message)
}
println(" consensus: " + consensus)
println(" occupancy at column 1: " + alignment.occupancy()[1].to_string())
println("\n4. Write canonical MSF and parse it again")
let canonical = @src.msf_write(
alignment,
block_width=12,
group_width=4,
gap_character="~",
) catch {
MsfError(message) => abort("MSF serialization failed: " + message)
}
let round_trip = @src.msf_parse(canonical) catch {
MsfError(message) => abort("round-trip parsing failed: " + message)
}
println(" output bytes: " + canonical.length().to_string())
println(" checksums valid: " + round_trip.checksums_valid().to_string())
println(
" aligned rows preserved: " +
(round_trip.sequences[1].aligned_sequence ==
alignment.sequences[1].aligned_sequence).to_string(),
)
println("\n5. Preserve third-party declared-width mismatches")
let mismatch_text = "!!AA_MULTIPLE_ALIGNMENT\n" +
"MSF: 2 Type: P Check: 0 ..\n" +
"Name: full Len: 4 Check: 0 Weight: 1.0\n" +
"Name: short Len: 2 Check: 0 Weight: 1.0\n" +
"//\n\nfull ACDE\nshort AC\n"
let mismatch = @src.msf_parse(mismatch_text) catch {
MsfError(message) => abort("length-mismatch parsing failed: " + message)
}
println(
" declared=" +
mismatch.metadata.declared_length.to_string() +
", actual=" +
mismatch.alignment_length().to_string() +
", mismatch=" +
mismatch.length_mismatch().to_string(),
)
}