use std::fmt::Write as FmtWrite;
use anyhow::{Context, Result};
use fixedbitset::FixedBitSet;
use ndarray::Array2;
use crate::data::splits_blocks::SplitsBlock;
use crate::phylo::phylo_splits_graph::{GraphEdge, PhyloSplitsGraph};
pub mod network_writer;
pub mod nexus_writer;
fn fmt_f(x: f64) -> String {
let mut s = format!("{:.7}", x);
while s.contains('.') && s.ends_with('0') {
s.pop();
}
if s.ends_with('.') {
s.pop();
}
if s.is_empty() {
s.push('0');
}
s
}
fn trim_float(x: f64, digits: usize) -> String {
let mut s = format!("{:.1$}", x, digits);
while s.ends_with('0') && s.contains('.') {
s.pop();
}
if s.ends_with('.') {
s.pop();
}
if s.is_empty() {
s.push('0');
}
s
}
fn bitset_to_string(bs: &FixedBitSet) -> String {
let mut out = String::new();
let mut first = true;
for t in bs.ones() {
if t == 0 {
continue;
}
if !first {
out.push(' ');
}
first = false;
out.push_str(&t.to_string());
}
out
}
fn bitset_to_vec(bs: &FixedBitSet) -> Vec<usize> {
bs.ones().collect()
}
fn escape_label(s: &str) -> String {
s.replace('\'', "''")
}
fn write_title_and_link<W: FmtWrite>(
mut w: W,
title: Option<&str>,
link: Option<&str>,
) -> Result<()> {
if let Some(t) = title {
writeln!(w, "TITLE '{}';", escape_label(t))?;
}
if let Some(l) = link {
writeln!(w, "LINK '{}';", escape_label(l))?;
}
Ok(())
}
pub type SplitsRecord = (String, f64, f64, Vec<usize>, Vec<usize>);
pub struct Nexus {
pub labels: Vec<String>,
pub distance_matrix: Array2<f64>,
pub splits: SplitsBlock,
pub graph: PhyloSplitsGraph,
}
impl Nexus {
pub fn new(
labels: Vec<String>,
distance_matrix: Array2<f64>,
splits: SplitsBlock,
graph: PhyloSplitsGraph,
) -> Self {
Nexus {
labels,
distance_matrix,
splits,
graph,
}
}
pub fn get_labels(&self) -> &[String] {
&self.labels
}
pub fn num_labels(&self) -> usize {
self.labels.len()
}
pub fn distance_matrix(&self) -> &Array2<f64> {
&self.distance_matrix
}
pub fn splits(&self) -> &SplitsBlock {
&self.splits
}
pub fn num_splits(&self) -> usize {
self.splits.nsplits()
}
pub fn graph(&self) -> &PhyloSplitsGraph {
&self.graph
}
pub fn get_splits_records(&self) -> Vec<SplitsRecord> {
self.splits
.get_splits()
.iter()
.map(|s| {
(
s.label().unwrap_or("").to_string(),
s.weight,
s.confidence,
bitset_to_vec(s.get_a()),
bitset_to_vec(s.get_b()),
)
})
.collect()
}
pub fn get_node_translations(&self) -> Result<Vec<(usize, String)>> {
self.graph
.get_node_translations(&self.labels)
.context("Failed to get node translations")
}
pub fn get_node_positions(&self) -> Result<Vec<(usize, f64, f64)>> {
self.graph
.get_node_positions()
.context("Failed to get node positions")
}
pub fn get_graph_edges(&self) -> Result<Vec<GraphEdge>> {
self.graph
.get_graph_edges()
.context("Failed to get graph edges")
}
}