GraphMetrics

Struct GraphMetrics 

Source
pub struct GraphMetrics { /* private fields */ }
Expand description

Statistical metrics for a dependency graph.

§Examples

use ascii_dag::layout::generic::metrics::GraphMetrics;

let get_deps = |&id: &usize| match id {
    1 => vec![],
    2 => vec![1],
    3 => vec![1, 2],
    _ => vec![],
};

let items = [1, 2, 3];
let metrics = GraphMetrics::compute(&items, get_deps);

println!("Nodes: {}", metrics.node_count());
println!("Max depth: {}", metrics.max_depth());
println!("Avg dependencies: {:.2}", metrics.avg_dependencies());

Implementations§

Source§

impl GraphMetrics

Source

pub fn compute<Id, F>(items: &[Id], get_dependencies: F) -> Self
where Id: Clone + Eq + Hash, F: Fn(&Id) -> Vec<Id> + Clone,

Compute metrics for a graph.

§Examples
use ascii_dag::layout::generic::metrics::GraphMetrics;

let get_deps = |&id: &usize| match id {
    1 => vec![],
    2 => vec![1],
    3 => vec![2],
    _ => vec![],
};

let items = [1, 2, 3];
let metrics = GraphMetrics::compute(&items, get_deps);
assert_eq!(metrics.node_count(), 3);
Examples found in repository?
examples/dependency_analysis.rs (line 176)
155fn example_metrics_dashboard() {
156    println!("3. Dependency Graph Metrics");
157    println!("   Statistical analysis of the dependency structure\n");
158
159    // Build system example
160    let get_deps = |file: &&str| match *file {
161        "app.exe" => vec!["main.o", "utils.o", "io.o"],
162        "main.o" => vec!["main.c", "types.h"],
163        "utils.o" => vec!["utils.c", "types.h"],
164        "io.o" => vec!["io.c", "types.h"],
165        "main.c" => vec![],
166        "utils.c" => vec![],
167        "io.c" => vec![],
168        "types.h" => vec![],
169        _ => vec![],
170    };
171
172    let files = [
173        "app.exe", "main.o", "utils.o", "io.o", "main.c", "utils.c", "io.c", "types.h",
174    ];
175
176    let metrics = GraphMetrics::compute(&files, get_deps);
177
178    println!("   📈 Graph Statistics:");
179    println!("      Total files: {}", metrics.node_count());
180    println!("      Total dependencies: {}", metrics.edge_count());
181    println!("      Root files (sources): {}", metrics.root_count());
182    println!("      Leaf files (outputs): {}", metrics.leaf_count());
183    println!("      Max depth: {}", metrics.max_depth());
184    println!("      Max impact: {} files", metrics.max_descendants());
185    println!("      Avg dependencies: {:.2}", metrics.avg_dependencies());
186    println!("      Density: {:.2}%", metrics.density() * 100.0);
187    println!();
188
189    println!("   🔍 Graph Properties:");
190    println!("      Is tree: {}", metrics.is_tree());
191    println!("      Is forest: {}", metrics.is_forest());
192    println!("      Is sparse: {}", metrics.is_sparse());
193    println!("      Is dense: {}", metrics.is_dense());
194    println!();
195
196    // Visualize with DAG
197    println!("   📊 Visualization:");
198    let mut dag = DAG::new();
199    dag.add_node(1, "types.h");
200    dag.add_node(2, "main.c");
201    dag.add_node(3, "main.o");
202    dag.add_node(4, "app.exe");
203    dag.add_edge(2, 3);
204    dag.add_edge(1, 3);
205    dag.add_edge(3, 4);
206
207    println!("{}", dag.render());
208
209    // Find the most impactful file
210    let mut max_impact = 0;
211    let mut most_impactful = "";
212    for file in &files {
213        let impact = compute_descendants_fn(&files, file, get_deps).len();
214        if impact > max_impact {
215            max_impact = impact;
216            most_impactful = file;
217        }
218    }
219
220    println!(
221        "   ⚡ Most impactful file: '{}' (affects {} other files)",
222        most_impactful, max_impact
223    );
224    println!();
225}
Source

pub fn node_count(&self) -> usize

Total number of nodes in the graph.

Examples found in repository?
examples/dependency_analysis.rs (line 179)
155fn example_metrics_dashboard() {
156    println!("3. Dependency Graph Metrics");
157    println!("   Statistical analysis of the dependency structure\n");
158
159    // Build system example
160    let get_deps = |file: &&str| match *file {
161        "app.exe" => vec!["main.o", "utils.o", "io.o"],
162        "main.o" => vec!["main.c", "types.h"],
163        "utils.o" => vec!["utils.c", "types.h"],
164        "io.o" => vec!["io.c", "types.h"],
165        "main.c" => vec![],
166        "utils.c" => vec![],
167        "io.c" => vec![],
168        "types.h" => vec![],
169        _ => vec![],
170    };
171
172    let files = [
173        "app.exe", "main.o", "utils.o", "io.o", "main.c", "utils.c", "io.c", "types.h",
174    ];
175
176    let metrics = GraphMetrics::compute(&files, get_deps);
177
178    println!("   📈 Graph Statistics:");
179    println!("      Total files: {}", metrics.node_count());
180    println!("      Total dependencies: {}", metrics.edge_count());
181    println!("      Root files (sources): {}", metrics.root_count());
182    println!("      Leaf files (outputs): {}", metrics.leaf_count());
183    println!("      Max depth: {}", metrics.max_depth());
184    println!("      Max impact: {} files", metrics.max_descendants());
185    println!("      Avg dependencies: {:.2}", metrics.avg_dependencies());
186    println!("      Density: {:.2}%", metrics.density() * 100.0);
187    println!();
188
189    println!("   🔍 Graph Properties:");
190    println!("      Is tree: {}", metrics.is_tree());
191    println!("      Is forest: {}", metrics.is_forest());
192    println!("      Is sparse: {}", metrics.is_sparse());
193    println!("      Is dense: {}", metrics.is_dense());
194    println!();
195
196    // Visualize with DAG
197    println!("   📊 Visualization:");
198    let mut dag = DAG::new();
199    dag.add_node(1, "types.h");
200    dag.add_node(2, "main.c");
201    dag.add_node(3, "main.o");
202    dag.add_node(4, "app.exe");
203    dag.add_edge(2, 3);
204    dag.add_edge(1, 3);
205    dag.add_edge(3, 4);
206
207    println!("{}", dag.render());
208
209    // Find the most impactful file
210    let mut max_impact = 0;
211    let mut most_impactful = "";
212    for file in &files {
213        let impact = compute_descendants_fn(&files, file, get_deps).len();
214        if impact > max_impact {
215            max_impact = impact;
216            most_impactful = file;
217        }
218    }
219
220    println!(
221        "   ⚡ Most impactful file: '{}' (affects {} other files)",
222        most_impactful, max_impact
223    );
224    println!();
225}
Source

pub fn edge_count(&self) -> usize

Total number of edges (dependencies) in the graph.

Examples found in repository?
examples/dependency_analysis.rs (line 180)
155fn example_metrics_dashboard() {
156    println!("3. Dependency Graph Metrics");
157    println!("   Statistical analysis of the dependency structure\n");
158
159    // Build system example
160    let get_deps = |file: &&str| match *file {
161        "app.exe" => vec!["main.o", "utils.o", "io.o"],
162        "main.o" => vec!["main.c", "types.h"],
163        "utils.o" => vec!["utils.c", "types.h"],
164        "io.o" => vec!["io.c", "types.h"],
165        "main.c" => vec![],
166        "utils.c" => vec![],
167        "io.c" => vec![],
168        "types.h" => vec![],
169        _ => vec![],
170    };
171
172    let files = [
173        "app.exe", "main.o", "utils.o", "io.o", "main.c", "utils.c", "io.c", "types.h",
174    ];
175
176    let metrics = GraphMetrics::compute(&files, get_deps);
177
178    println!("   📈 Graph Statistics:");
179    println!("      Total files: {}", metrics.node_count());
180    println!("      Total dependencies: {}", metrics.edge_count());
181    println!("      Root files (sources): {}", metrics.root_count());
182    println!("      Leaf files (outputs): {}", metrics.leaf_count());
183    println!("      Max depth: {}", metrics.max_depth());
184    println!("      Max impact: {} files", metrics.max_descendants());
185    println!("      Avg dependencies: {:.2}", metrics.avg_dependencies());
186    println!("      Density: {:.2}%", metrics.density() * 100.0);
187    println!();
188
189    println!("   🔍 Graph Properties:");
190    println!("      Is tree: {}", metrics.is_tree());
191    println!("      Is forest: {}", metrics.is_forest());
192    println!("      Is sparse: {}", metrics.is_sparse());
193    println!("      Is dense: {}", metrics.is_dense());
194    println!();
195
196    // Visualize with DAG
197    println!("   📊 Visualization:");
198    let mut dag = DAG::new();
199    dag.add_node(1, "types.h");
200    dag.add_node(2, "main.c");
201    dag.add_node(3, "main.o");
202    dag.add_node(4, "app.exe");
203    dag.add_edge(2, 3);
204    dag.add_edge(1, 3);
205    dag.add_edge(3, 4);
206
207    println!("{}", dag.render());
208
209    // Find the most impactful file
210    let mut max_impact = 0;
211    let mut most_impactful = "";
212    for file in &files {
213        let impact = compute_descendants_fn(&files, file, get_deps).len();
214        if impact > max_impact {
215            max_impact = impact;
216            most_impactful = file;
217        }
218    }
219
220    println!(
221        "   ⚡ Most impactful file: '{}' (affects {} other files)",
222        most_impactful, max_impact
223    );
224    println!();
225}
Source

pub fn root_count(&self) -> usize

Number of root nodes (nodes with no dependencies).

Examples found in repository?
examples/dependency_analysis.rs (line 181)
155fn example_metrics_dashboard() {
156    println!("3. Dependency Graph Metrics");
157    println!("   Statistical analysis of the dependency structure\n");
158
159    // Build system example
160    let get_deps = |file: &&str| match *file {
161        "app.exe" => vec!["main.o", "utils.o", "io.o"],
162        "main.o" => vec!["main.c", "types.h"],
163        "utils.o" => vec!["utils.c", "types.h"],
164        "io.o" => vec!["io.c", "types.h"],
165        "main.c" => vec![],
166        "utils.c" => vec![],
167        "io.c" => vec![],
168        "types.h" => vec![],
169        _ => vec![],
170    };
171
172    let files = [
173        "app.exe", "main.o", "utils.o", "io.o", "main.c", "utils.c", "io.c", "types.h",
174    ];
175
176    let metrics = GraphMetrics::compute(&files, get_deps);
177
178    println!("   📈 Graph Statistics:");
179    println!("      Total files: {}", metrics.node_count());
180    println!("      Total dependencies: {}", metrics.edge_count());
181    println!("      Root files (sources): {}", metrics.root_count());
182    println!("      Leaf files (outputs): {}", metrics.leaf_count());
183    println!("      Max depth: {}", metrics.max_depth());
184    println!("      Max impact: {} files", metrics.max_descendants());
185    println!("      Avg dependencies: {:.2}", metrics.avg_dependencies());
186    println!("      Density: {:.2}%", metrics.density() * 100.0);
187    println!();
188
189    println!("   🔍 Graph Properties:");
190    println!("      Is tree: {}", metrics.is_tree());
191    println!("      Is forest: {}", metrics.is_forest());
192    println!("      Is sparse: {}", metrics.is_sparse());
193    println!("      Is dense: {}", metrics.is_dense());
194    println!();
195
196    // Visualize with DAG
197    println!("   📊 Visualization:");
198    let mut dag = DAG::new();
199    dag.add_node(1, "types.h");
200    dag.add_node(2, "main.c");
201    dag.add_node(3, "main.o");
202    dag.add_node(4, "app.exe");
203    dag.add_edge(2, 3);
204    dag.add_edge(1, 3);
205    dag.add_edge(3, 4);
206
207    println!("{}", dag.render());
208
209    // Find the most impactful file
210    let mut max_impact = 0;
211    let mut most_impactful = "";
212    for file in &files {
213        let impact = compute_descendants_fn(&files, file, get_deps).len();
214        if impact > max_impact {
215            max_impact = impact;
216            most_impactful = file;
217        }
218    }
219
220    println!(
221        "   ⚡ Most impactful file: '{}' (affects {} other files)",
222        most_impactful, max_impact
223    );
224    println!();
225}
Source

pub fn leaf_count(&self) -> usize

Number of leaf nodes (nodes that nothing depends on).

Examples found in repository?
examples/dependency_analysis.rs (line 182)
155fn example_metrics_dashboard() {
156    println!("3. Dependency Graph Metrics");
157    println!("   Statistical analysis of the dependency structure\n");
158
159    // Build system example
160    let get_deps = |file: &&str| match *file {
161        "app.exe" => vec!["main.o", "utils.o", "io.o"],
162        "main.o" => vec!["main.c", "types.h"],
163        "utils.o" => vec!["utils.c", "types.h"],
164        "io.o" => vec!["io.c", "types.h"],
165        "main.c" => vec![],
166        "utils.c" => vec![],
167        "io.c" => vec![],
168        "types.h" => vec![],
169        _ => vec![],
170    };
171
172    let files = [
173        "app.exe", "main.o", "utils.o", "io.o", "main.c", "utils.c", "io.c", "types.h",
174    ];
175
176    let metrics = GraphMetrics::compute(&files, get_deps);
177
178    println!("   📈 Graph Statistics:");
179    println!("      Total files: {}", metrics.node_count());
180    println!("      Total dependencies: {}", metrics.edge_count());
181    println!("      Root files (sources): {}", metrics.root_count());
182    println!("      Leaf files (outputs): {}", metrics.leaf_count());
183    println!("      Max depth: {}", metrics.max_depth());
184    println!("      Max impact: {} files", metrics.max_descendants());
185    println!("      Avg dependencies: {:.2}", metrics.avg_dependencies());
186    println!("      Density: {:.2}%", metrics.density() * 100.0);
187    println!();
188
189    println!("   🔍 Graph Properties:");
190    println!("      Is tree: {}", metrics.is_tree());
191    println!("      Is forest: {}", metrics.is_forest());
192    println!("      Is sparse: {}", metrics.is_sparse());
193    println!("      Is dense: {}", metrics.is_dense());
194    println!();
195
196    // Visualize with DAG
197    println!("   📊 Visualization:");
198    let mut dag = DAG::new();
199    dag.add_node(1, "types.h");
200    dag.add_node(2, "main.c");
201    dag.add_node(3, "main.o");
202    dag.add_node(4, "app.exe");
203    dag.add_edge(2, 3);
204    dag.add_edge(1, 3);
205    dag.add_edge(3, 4);
206
207    println!("{}", dag.render());
208
209    // Find the most impactful file
210    let mut max_impact = 0;
211    let mut most_impactful = "";
212    for file in &files {
213        let impact = compute_descendants_fn(&files, file, get_deps).len();
214        if impact > max_impact {
215            max_impact = impact;
216            most_impactful = file;
217        }
218    }
219
220    println!(
221        "   ⚡ Most impactful file: '{}' (affects {} other files)",
222        most_impactful, max_impact
223    );
224    println!();
225}
Source

pub fn max_depth(&self) -> usize

Maximum depth (longest dependency chain from a root).

Examples found in repository?
examples/dependency_analysis.rs (line 183)
155fn example_metrics_dashboard() {
156    println!("3. Dependency Graph Metrics");
157    println!("   Statistical analysis of the dependency structure\n");
158
159    // Build system example
160    let get_deps = |file: &&str| match *file {
161        "app.exe" => vec!["main.o", "utils.o", "io.o"],
162        "main.o" => vec!["main.c", "types.h"],
163        "utils.o" => vec!["utils.c", "types.h"],
164        "io.o" => vec!["io.c", "types.h"],
165        "main.c" => vec![],
166        "utils.c" => vec![],
167        "io.c" => vec![],
168        "types.h" => vec![],
169        _ => vec![],
170    };
171
172    let files = [
173        "app.exe", "main.o", "utils.o", "io.o", "main.c", "utils.c", "io.c", "types.h",
174    ];
175
176    let metrics = GraphMetrics::compute(&files, get_deps);
177
178    println!("   📈 Graph Statistics:");
179    println!("      Total files: {}", metrics.node_count());
180    println!("      Total dependencies: {}", metrics.edge_count());
181    println!("      Root files (sources): {}", metrics.root_count());
182    println!("      Leaf files (outputs): {}", metrics.leaf_count());
183    println!("      Max depth: {}", metrics.max_depth());
184    println!("      Max impact: {} files", metrics.max_descendants());
185    println!("      Avg dependencies: {:.2}", metrics.avg_dependencies());
186    println!("      Density: {:.2}%", metrics.density() * 100.0);
187    println!();
188
189    println!("   🔍 Graph Properties:");
190    println!("      Is tree: {}", metrics.is_tree());
191    println!("      Is forest: {}", metrics.is_forest());
192    println!("      Is sparse: {}", metrics.is_sparse());
193    println!("      Is dense: {}", metrics.is_dense());
194    println!();
195
196    // Visualize with DAG
197    println!("   📊 Visualization:");
198    let mut dag = DAG::new();
199    dag.add_node(1, "types.h");
200    dag.add_node(2, "main.c");
201    dag.add_node(3, "main.o");
202    dag.add_node(4, "app.exe");
203    dag.add_edge(2, 3);
204    dag.add_edge(1, 3);
205    dag.add_edge(3, 4);
206
207    println!("{}", dag.render());
208
209    // Find the most impactful file
210    let mut max_impact = 0;
211    let mut most_impactful = "";
212    for file in &files {
213        let impact = compute_descendants_fn(&files, file, get_deps).len();
214        if impact > max_impact {
215            max_impact = impact;
216            most_impactful = file;
217        }
218    }
219
220    println!(
221        "   ⚡ Most impactful file: '{}' (affects {} other files)",
222        most_impactful, max_impact
223    );
224    println!();
225}
Source

pub fn max_descendants(&self) -> usize

Maximum number of descendants any single node has.

This represents the “blast radius” of the most impactful node.

Examples found in repository?
examples/dependency_analysis.rs (line 184)
155fn example_metrics_dashboard() {
156    println!("3. Dependency Graph Metrics");
157    println!("   Statistical analysis of the dependency structure\n");
158
159    // Build system example
160    let get_deps = |file: &&str| match *file {
161        "app.exe" => vec!["main.o", "utils.o", "io.o"],
162        "main.o" => vec!["main.c", "types.h"],
163        "utils.o" => vec!["utils.c", "types.h"],
164        "io.o" => vec!["io.c", "types.h"],
165        "main.c" => vec![],
166        "utils.c" => vec![],
167        "io.c" => vec![],
168        "types.h" => vec![],
169        _ => vec![],
170    };
171
172    let files = [
173        "app.exe", "main.o", "utils.o", "io.o", "main.c", "utils.c", "io.c", "types.h",
174    ];
175
176    let metrics = GraphMetrics::compute(&files, get_deps);
177
178    println!("   📈 Graph Statistics:");
179    println!("      Total files: {}", metrics.node_count());
180    println!("      Total dependencies: {}", metrics.edge_count());
181    println!("      Root files (sources): {}", metrics.root_count());
182    println!("      Leaf files (outputs): {}", metrics.leaf_count());
183    println!("      Max depth: {}", metrics.max_depth());
184    println!("      Max impact: {} files", metrics.max_descendants());
185    println!("      Avg dependencies: {:.2}", metrics.avg_dependencies());
186    println!("      Density: {:.2}%", metrics.density() * 100.0);
187    println!();
188
189    println!("   🔍 Graph Properties:");
190    println!("      Is tree: {}", metrics.is_tree());
191    println!("      Is forest: {}", metrics.is_forest());
192    println!("      Is sparse: {}", metrics.is_sparse());
193    println!("      Is dense: {}", metrics.is_dense());
194    println!();
195
196    // Visualize with DAG
197    println!("   📊 Visualization:");
198    let mut dag = DAG::new();
199    dag.add_node(1, "types.h");
200    dag.add_node(2, "main.c");
201    dag.add_node(3, "main.o");
202    dag.add_node(4, "app.exe");
203    dag.add_edge(2, 3);
204    dag.add_edge(1, 3);
205    dag.add_edge(3, 4);
206
207    println!("{}", dag.render());
208
209    // Find the most impactful file
210    let mut max_impact = 0;
211    let mut most_impactful = "";
212    for file in &files {
213        let impact = compute_descendants_fn(&files, file, get_deps).len();
214        if impact > max_impact {
215            max_impact = impact;
216            most_impactful = file;
217        }
218    }
219
220    println!(
221        "   ⚡ Most impactful file: '{}' (affects {} other files)",
222        most_impactful, max_impact
223    );
224    println!();
225}
Source

pub fn avg_dependencies(&self) -> f64

Average number of dependencies per node.

Examples found in repository?
examples/dependency_analysis.rs (line 185)
155fn example_metrics_dashboard() {
156    println!("3. Dependency Graph Metrics");
157    println!("   Statistical analysis of the dependency structure\n");
158
159    // Build system example
160    let get_deps = |file: &&str| match *file {
161        "app.exe" => vec!["main.o", "utils.o", "io.o"],
162        "main.o" => vec!["main.c", "types.h"],
163        "utils.o" => vec!["utils.c", "types.h"],
164        "io.o" => vec!["io.c", "types.h"],
165        "main.c" => vec![],
166        "utils.c" => vec![],
167        "io.c" => vec![],
168        "types.h" => vec![],
169        _ => vec![],
170    };
171
172    let files = [
173        "app.exe", "main.o", "utils.o", "io.o", "main.c", "utils.c", "io.c", "types.h",
174    ];
175
176    let metrics = GraphMetrics::compute(&files, get_deps);
177
178    println!("   📈 Graph Statistics:");
179    println!("      Total files: {}", metrics.node_count());
180    println!("      Total dependencies: {}", metrics.edge_count());
181    println!("      Root files (sources): {}", metrics.root_count());
182    println!("      Leaf files (outputs): {}", metrics.leaf_count());
183    println!("      Max depth: {}", metrics.max_depth());
184    println!("      Max impact: {} files", metrics.max_descendants());
185    println!("      Avg dependencies: {:.2}", metrics.avg_dependencies());
186    println!("      Density: {:.2}%", metrics.density() * 100.0);
187    println!();
188
189    println!("   🔍 Graph Properties:");
190    println!("      Is tree: {}", metrics.is_tree());
191    println!("      Is forest: {}", metrics.is_forest());
192    println!("      Is sparse: {}", metrics.is_sparse());
193    println!("      Is dense: {}", metrics.is_dense());
194    println!();
195
196    // Visualize with DAG
197    println!("   📊 Visualization:");
198    let mut dag = DAG::new();
199    dag.add_node(1, "types.h");
200    dag.add_node(2, "main.c");
201    dag.add_node(3, "main.o");
202    dag.add_node(4, "app.exe");
203    dag.add_edge(2, 3);
204    dag.add_edge(1, 3);
205    dag.add_edge(3, 4);
206
207    println!("{}", dag.render());
208
209    // Find the most impactful file
210    let mut max_impact = 0;
211    let mut most_impactful = "";
212    for file in &files {
213        let impact = compute_descendants_fn(&files, file, get_deps).len();
214        if impact > max_impact {
215            max_impact = impact;
216            most_impactful = file;
217        }
218    }
219
220    println!(
221        "   ⚡ Most impactful file: '{}' (affects {} other files)",
222        most_impactful, max_impact
223    );
224    println!();
225}
Source

pub fn density(&self) -> f64

Graph density (ratio of actual edges to possible edges).

Returns a value between 0.0 (no edges) and 1.0 (complete graph).

Examples found in repository?
examples/dependency_analysis.rs (line 186)
155fn example_metrics_dashboard() {
156    println!("3. Dependency Graph Metrics");
157    println!("   Statistical analysis of the dependency structure\n");
158
159    // Build system example
160    let get_deps = |file: &&str| match *file {
161        "app.exe" => vec!["main.o", "utils.o", "io.o"],
162        "main.o" => vec!["main.c", "types.h"],
163        "utils.o" => vec!["utils.c", "types.h"],
164        "io.o" => vec!["io.c", "types.h"],
165        "main.c" => vec![],
166        "utils.c" => vec![],
167        "io.c" => vec![],
168        "types.h" => vec![],
169        _ => vec![],
170    };
171
172    let files = [
173        "app.exe", "main.o", "utils.o", "io.o", "main.c", "utils.c", "io.c", "types.h",
174    ];
175
176    let metrics = GraphMetrics::compute(&files, get_deps);
177
178    println!("   📈 Graph Statistics:");
179    println!("      Total files: {}", metrics.node_count());
180    println!("      Total dependencies: {}", metrics.edge_count());
181    println!("      Root files (sources): {}", metrics.root_count());
182    println!("      Leaf files (outputs): {}", metrics.leaf_count());
183    println!("      Max depth: {}", metrics.max_depth());
184    println!("      Max impact: {} files", metrics.max_descendants());
185    println!("      Avg dependencies: {:.2}", metrics.avg_dependencies());
186    println!("      Density: {:.2}%", metrics.density() * 100.0);
187    println!();
188
189    println!("   🔍 Graph Properties:");
190    println!("      Is tree: {}", metrics.is_tree());
191    println!("      Is forest: {}", metrics.is_forest());
192    println!("      Is sparse: {}", metrics.is_sparse());
193    println!("      Is dense: {}", metrics.is_dense());
194    println!();
195
196    // Visualize with DAG
197    println!("   📊 Visualization:");
198    let mut dag = DAG::new();
199    dag.add_node(1, "types.h");
200    dag.add_node(2, "main.c");
201    dag.add_node(3, "main.o");
202    dag.add_node(4, "app.exe");
203    dag.add_edge(2, 3);
204    dag.add_edge(1, 3);
205    dag.add_edge(3, 4);
206
207    println!("{}", dag.render());
208
209    // Find the most impactful file
210    let mut max_impact = 0;
211    let mut most_impactful = "";
212    for file in &files {
213        let impact = compute_descendants_fn(&files, file, get_deps).len();
214        if impact > max_impact {
215            max_impact = impact;
216            most_impactful = file;
217        }
218    }
219
220    println!(
221        "   ⚡ Most impactful file: '{}' (affects {} other files)",
222        most_impactful, max_impact
223    );
224    println!();
225}
Source

pub fn is_tree(&self) -> bool

Check if this is a tree (single root, no multiple paths to same node).

Examples found in repository?
examples/dependency_analysis.rs (line 190)
155fn example_metrics_dashboard() {
156    println!("3. Dependency Graph Metrics");
157    println!("   Statistical analysis of the dependency structure\n");
158
159    // Build system example
160    let get_deps = |file: &&str| match *file {
161        "app.exe" => vec!["main.o", "utils.o", "io.o"],
162        "main.o" => vec!["main.c", "types.h"],
163        "utils.o" => vec!["utils.c", "types.h"],
164        "io.o" => vec!["io.c", "types.h"],
165        "main.c" => vec![],
166        "utils.c" => vec![],
167        "io.c" => vec![],
168        "types.h" => vec![],
169        _ => vec![],
170    };
171
172    let files = [
173        "app.exe", "main.o", "utils.o", "io.o", "main.c", "utils.c", "io.c", "types.h",
174    ];
175
176    let metrics = GraphMetrics::compute(&files, get_deps);
177
178    println!("   📈 Graph Statistics:");
179    println!("      Total files: {}", metrics.node_count());
180    println!("      Total dependencies: {}", metrics.edge_count());
181    println!("      Root files (sources): {}", metrics.root_count());
182    println!("      Leaf files (outputs): {}", metrics.leaf_count());
183    println!("      Max depth: {}", metrics.max_depth());
184    println!("      Max impact: {} files", metrics.max_descendants());
185    println!("      Avg dependencies: {:.2}", metrics.avg_dependencies());
186    println!("      Density: {:.2}%", metrics.density() * 100.0);
187    println!();
188
189    println!("   🔍 Graph Properties:");
190    println!("      Is tree: {}", metrics.is_tree());
191    println!("      Is forest: {}", metrics.is_forest());
192    println!("      Is sparse: {}", metrics.is_sparse());
193    println!("      Is dense: {}", metrics.is_dense());
194    println!();
195
196    // Visualize with DAG
197    println!("   📊 Visualization:");
198    let mut dag = DAG::new();
199    dag.add_node(1, "types.h");
200    dag.add_node(2, "main.c");
201    dag.add_node(3, "main.o");
202    dag.add_node(4, "app.exe");
203    dag.add_edge(2, 3);
204    dag.add_edge(1, 3);
205    dag.add_edge(3, 4);
206
207    println!("{}", dag.render());
208
209    // Find the most impactful file
210    let mut max_impact = 0;
211    let mut most_impactful = "";
212    for file in &files {
213        let impact = compute_descendants_fn(&files, file, get_deps).len();
214        if impact > max_impact {
215            max_impact = impact;
216            most_impactful = file;
217        }
218    }
219
220    println!(
221        "   ⚡ Most impactful file: '{}' (affects {} other files)",
222        most_impactful, max_impact
223    );
224    println!();
225}
Source

pub fn is_forest(&self) -> bool

Check if this is a forest (multiple trees, no cycles).

Examples found in repository?
examples/dependency_analysis.rs (line 191)
155fn example_metrics_dashboard() {
156    println!("3. Dependency Graph Metrics");
157    println!("   Statistical analysis of the dependency structure\n");
158
159    // Build system example
160    let get_deps = |file: &&str| match *file {
161        "app.exe" => vec!["main.o", "utils.o", "io.o"],
162        "main.o" => vec!["main.c", "types.h"],
163        "utils.o" => vec!["utils.c", "types.h"],
164        "io.o" => vec!["io.c", "types.h"],
165        "main.c" => vec![],
166        "utils.c" => vec![],
167        "io.c" => vec![],
168        "types.h" => vec![],
169        _ => vec![],
170    };
171
172    let files = [
173        "app.exe", "main.o", "utils.o", "io.o", "main.c", "utils.c", "io.c", "types.h",
174    ];
175
176    let metrics = GraphMetrics::compute(&files, get_deps);
177
178    println!("   📈 Graph Statistics:");
179    println!("      Total files: {}", metrics.node_count());
180    println!("      Total dependencies: {}", metrics.edge_count());
181    println!("      Root files (sources): {}", metrics.root_count());
182    println!("      Leaf files (outputs): {}", metrics.leaf_count());
183    println!("      Max depth: {}", metrics.max_depth());
184    println!("      Max impact: {} files", metrics.max_descendants());
185    println!("      Avg dependencies: {:.2}", metrics.avg_dependencies());
186    println!("      Density: {:.2}%", metrics.density() * 100.0);
187    println!();
188
189    println!("   🔍 Graph Properties:");
190    println!("      Is tree: {}", metrics.is_tree());
191    println!("      Is forest: {}", metrics.is_forest());
192    println!("      Is sparse: {}", metrics.is_sparse());
193    println!("      Is dense: {}", metrics.is_dense());
194    println!();
195
196    // Visualize with DAG
197    println!("   📊 Visualization:");
198    let mut dag = DAG::new();
199    dag.add_node(1, "types.h");
200    dag.add_node(2, "main.c");
201    dag.add_node(3, "main.o");
202    dag.add_node(4, "app.exe");
203    dag.add_edge(2, 3);
204    dag.add_edge(1, 3);
205    dag.add_edge(3, 4);
206
207    println!("{}", dag.render());
208
209    // Find the most impactful file
210    let mut max_impact = 0;
211    let mut most_impactful = "";
212    for file in &files {
213        let impact = compute_descendants_fn(&files, file, get_deps).len();
214        if impact > max_impact {
215            max_impact = impact;
216            most_impactful = file;
217        }
218    }
219
220    println!(
221        "   ⚡ Most impactful file: '{}' (affects {} other files)",
222        most_impactful, max_impact
223    );
224    println!();
225}
Source

pub fn is_sparse(&self) -> bool

Check if the graph is sparse (few edges relative to nodes).

Examples found in repository?
examples/dependency_analysis.rs (line 192)
155fn example_metrics_dashboard() {
156    println!("3. Dependency Graph Metrics");
157    println!("   Statistical analysis of the dependency structure\n");
158
159    // Build system example
160    let get_deps = |file: &&str| match *file {
161        "app.exe" => vec!["main.o", "utils.o", "io.o"],
162        "main.o" => vec!["main.c", "types.h"],
163        "utils.o" => vec!["utils.c", "types.h"],
164        "io.o" => vec!["io.c", "types.h"],
165        "main.c" => vec![],
166        "utils.c" => vec![],
167        "io.c" => vec![],
168        "types.h" => vec![],
169        _ => vec![],
170    };
171
172    let files = [
173        "app.exe", "main.o", "utils.o", "io.o", "main.c", "utils.c", "io.c", "types.h",
174    ];
175
176    let metrics = GraphMetrics::compute(&files, get_deps);
177
178    println!("   📈 Graph Statistics:");
179    println!("      Total files: {}", metrics.node_count());
180    println!("      Total dependencies: {}", metrics.edge_count());
181    println!("      Root files (sources): {}", metrics.root_count());
182    println!("      Leaf files (outputs): {}", metrics.leaf_count());
183    println!("      Max depth: {}", metrics.max_depth());
184    println!("      Max impact: {} files", metrics.max_descendants());
185    println!("      Avg dependencies: {:.2}", metrics.avg_dependencies());
186    println!("      Density: {:.2}%", metrics.density() * 100.0);
187    println!();
188
189    println!("   🔍 Graph Properties:");
190    println!("      Is tree: {}", metrics.is_tree());
191    println!("      Is forest: {}", metrics.is_forest());
192    println!("      Is sparse: {}", metrics.is_sparse());
193    println!("      Is dense: {}", metrics.is_dense());
194    println!();
195
196    // Visualize with DAG
197    println!("   📊 Visualization:");
198    let mut dag = DAG::new();
199    dag.add_node(1, "types.h");
200    dag.add_node(2, "main.c");
201    dag.add_node(3, "main.o");
202    dag.add_node(4, "app.exe");
203    dag.add_edge(2, 3);
204    dag.add_edge(1, 3);
205    dag.add_edge(3, 4);
206
207    println!("{}", dag.render());
208
209    // Find the most impactful file
210    let mut max_impact = 0;
211    let mut most_impactful = "";
212    for file in &files {
213        let impact = compute_descendants_fn(&files, file, get_deps).len();
214        if impact > max_impact {
215            max_impact = impact;
216            most_impactful = file;
217        }
218    }
219
220    println!(
221        "   ⚡ Most impactful file: '{}' (affects {} other files)",
222        most_impactful, max_impact
223    );
224    println!();
225}
Source

pub fn is_dense(&self) -> bool

Check if the graph is dense (many edges relative to nodes).

Examples found in repository?
examples/dependency_analysis.rs (line 193)
155fn example_metrics_dashboard() {
156    println!("3. Dependency Graph Metrics");
157    println!("   Statistical analysis of the dependency structure\n");
158
159    // Build system example
160    let get_deps = |file: &&str| match *file {
161        "app.exe" => vec!["main.o", "utils.o", "io.o"],
162        "main.o" => vec!["main.c", "types.h"],
163        "utils.o" => vec!["utils.c", "types.h"],
164        "io.o" => vec!["io.c", "types.h"],
165        "main.c" => vec![],
166        "utils.c" => vec![],
167        "io.c" => vec![],
168        "types.h" => vec![],
169        _ => vec![],
170    };
171
172    let files = [
173        "app.exe", "main.o", "utils.o", "io.o", "main.c", "utils.c", "io.c", "types.h",
174    ];
175
176    let metrics = GraphMetrics::compute(&files, get_deps);
177
178    println!("   📈 Graph Statistics:");
179    println!("      Total files: {}", metrics.node_count());
180    println!("      Total dependencies: {}", metrics.edge_count());
181    println!("      Root files (sources): {}", metrics.root_count());
182    println!("      Leaf files (outputs): {}", metrics.leaf_count());
183    println!("      Max depth: {}", metrics.max_depth());
184    println!("      Max impact: {} files", metrics.max_descendants());
185    println!("      Avg dependencies: {:.2}", metrics.avg_dependencies());
186    println!("      Density: {:.2}%", metrics.density() * 100.0);
187    println!();
188
189    println!("   🔍 Graph Properties:");
190    println!("      Is tree: {}", metrics.is_tree());
191    println!("      Is forest: {}", metrics.is_forest());
192    println!("      Is sparse: {}", metrics.is_sparse());
193    println!("      Is dense: {}", metrics.is_dense());
194    println!();
195
196    // Visualize with DAG
197    println!("   📊 Visualization:");
198    let mut dag = DAG::new();
199    dag.add_node(1, "types.h");
200    dag.add_node(2, "main.c");
201    dag.add_node(3, "main.o");
202    dag.add_node(4, "app.exe");
203    dag.add_edge(2, 3);
204    dag.add_edge(1, 3);
205    dag.add_edge(3, 4);
206
207    println!("{}", dag.render());
208
209    // Find the most impactful file
210    let mut max_impact = 0;
211    let mut most_impactful = "";
212    for file in &files {
213        let impact = compute_descendants_fn(&files, file, get_deps).len();
214        if impact > max_impact {
215            max_impact = impact;
216            most_impactful = file;
217        }
218    }
219
220    println!(
221        "   ⚡ Most impactful file: '{}' (affects {} other files)",
222        most_impactful, max_impact
223    );
224    println!();
225}

Trait Implementations§

Source§

impl Clone for GraphMetrics

Source§

fn clone(&self) -> GraphMetrics

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for GraphMetrics

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.