///|
/// Lightweight lineage graph for tracing production transformations.
pub struct LineageNode {
id : String
operation : String
input_count : Int
output_count : Int
score : Double
}
///|
pub struct LineageGraph {
name : String
nodes : Array[LineageNode]
edges : Array[Array[Int]]
}
///|
pub fn lineage_graph(name : String) -> LineageGraph {
{ name, nodes: [], edges: [] }
}
///|
pub fn lineage_add_node(
graph : LineageGraph,
id : String,
operation : String,
input_count : Int,
output_count : Int,
score : Double,
) -> Int {
let index = graph.nodes.length()
graph.nodes.push({ id, operation, input_count, output_count, score })
index
}
///|
pub fn lineage_add_edge(graph : LineageGraph, from : Int, to : Int) -> Unit {
graph.edges.push([from, to])
}
///|
pub fn lineage_node_count(graph : LineageGraph) -> Int {
graph.nodes.length()
}
///|
pub fn lineage_edge_count(graph : LineageGraph) -> Int {
graph.edges.length()
}
///|
pub fn lineage_operations(graph : LineageGraph) -> Array[String] {
let result = []
for node in graph.nodes {
result.push(node.operation)
}
result
}
///|
pub fn lineage_scores(graph : LineageGraph) -> Array[Double] {
let result = []
for node in graph.nodes {
result.push(node.score)
}
result
}
///|
pub fn lineage_quality(graph : LineageGraph) -> Double {
if graph.nodes.length() == 0 {
1.0
} else {
mean(lineage_scores(graph))
}
}
///|
pub fn lineage_valid(graph : LineageGraph) -> Bool {
for edge in graph.edges {
if edge.length() != 2 ||
edge[0] < 0 ||
edge[1] < 0 ||
edge[0] >= graph.nodes.length() ||
edge[1] >= graph.nodes.length() {
return false
}
}
true
}
///|
pub fn lineage_terminal(graph : LineageGraph) -> Int {
if graph.nodes.length() == 0 {
-1
} else {
graph.nodes.length() - 1
}
}
///|
pub fn lineage_lines(graph : LineageGraph) -> Array[String] {
let lines = [
"name=" + graph.name,
"nodes=" + graph.nodes.length().to_string(),
"edges=" + graph.edges.length().to_string(),
"quality=" + lineage_quality(graph).to_string(),
]
for node in graph.nodes {
lines.push(
node.id +
"|" +
node.operation +
"|" +
node.input_count.to_string() +
"|" +
node.output_count.to_string() +
"|" +
node.score.to_string(),
)
}
lines
}
///|
pub fn lineage_string(graph : LineageGraph) -> String {
lineage_lines(graph).join("\n")
}
///|
pub fn lineage_summary(graph : LineageGraph) -> Array[Double] {
[
graph.nodes.length().to_double(),
graph.edges.length().to_double(),
lineage_quality(graph),
if lineage_valid(graph) {
1.0
} else {
0.0
},
lineage_terminal(graph).to_double(),
]
}