diff --git a/plugins/mindstudio-insight-plugins/ModelVis/Cargo.lock b/plugins/mindstudio-insight-plugins/ModelVis/Cargo.lock index 0b55074943a4f23f6c49e9017fba6702197eb7d3..30c6e925a2439fe7991011b1638241804da1ca63 100644 --- a/plugins/mindstudio-insight-plugins/ModelVis/Cargo.lock +++ b/plugins/mindstudio-insight-plugins/ModelVis/Cargo.lock @@ -76,15 +76,6 @@ version = "1.0.98" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487" -[[package]] -name = "ash" -version = "0.38.0+1.3.281" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bb44936d800fea8f016d7f2311c6a4f97aebd5dc86f09906139ec848cf3a46f" -dependencies = [ - "libloading 0.8.7", -] - [[package]] name = "ashpd" version = "0.11.0" @@ -513,25 +504,6 @@ dependencies = [ "crossbeam-utils", ] -[[package]] -name = "crossbeam-deque" -version = "0.8.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" -dependencies = [ - "crossbeam-epoch", - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-epoch" -version = "0.9.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" -dependencies = [ - "crossbeam-utils", -] - [[package]] name = "crossbeam-utils" version = "0.8.21" @@ -860,13 +832,6 @@ dependencies = [ "windows-sys 0.59.0", ] -[[package]] -name = "error" -version = "0.1.0" -dependencies = [ - "serde", -] - [[package]] name = "event-listener" version = "5.4.0" @@ -913,14 +878,6 @@ dependencies = [ "rustc_version", ] -[[package]] -name = "file-ext" -version = "0.1.0" -dependencies = [ - "libc", - "windows 0.61.1", -] - [[package]] name = "fixedbitset" version = "0.5.7" @@ -979,6 +936,18 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "fsg" +version = "0.1.0" +dependencies = [ + "anyhow", + "parser", + "rustc-hash", + "serde", + "serde_json", + "smartstring", +] + [[package]] name = "futf" version = "0.1.5" @@ -1515,7 +1484,7 @@ dependencies = [ "js-sys", "log", "wasm-bindgen", - "windows-core 0.61.1", + "windows-core", ] [[package]] @@ -1835,7 +1804,6 @@ dependencies = [ "ahash", "anyhow", "mimalloc", - "perf", "smallvec 2.0.0-alpha.11", ] @@ -1865,7 +1833,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6e9ec52138abedcc58dc17a7c6c0c00a2bdb4f3427c7f63fa97fd0d859155caf" dependencies = [ "gtk-sys", - "libloading 0.7.4", + "libloading", "once_cell", ] @@ -1885,16 +1853,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "libloading" -version = "0.8.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a793df0d7afeac54f95b471d3af7f0d4fb975699f972341a4b76988d49cdf0c" -dependencies = [ - "cfg-if", - "windows-targets 0.53.0", -] - [[package]] name = "libmimalloc-sys" version = "0.1.42" @@ -2102,15 +2060,6 @@ version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb" -[[package]] -name = "ntapi" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8a3895c6391c39d7fe7ebc444a87eb2991b2a0bc718fdabd071eec617fc68e4" -dependencies = [ - "winapi", -] - [[package]] name = "num-conv" version = "0.1.0" @@ -2480,7 +2429,7 @@ dependencies = [ "protobuf", "ryu", "serde", - "smartstring 1.0.1", + "smartstring", "thiserror 2.0.12", ] @@ -2496,14 +2445,6 @@ version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" -[[package]] -name = "perf" -version = "0.0.1" -dependencies = [ - "quote", - "syn 2.0.101", -] - [[package]] name = "petgraph" version = "0.7.1" @@ -3011,26 +2952,6 @@ version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "20675572f6f24e9e76ef639bc5552774ed45f1c30e2951e1e99c59888861c539" -[[package]] -name = "rayon" -version = "1.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" -dependencies = [ - "either", - "rayon-core", -] - -[[package]] -name = "rayon-core" -version = "1.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" -dependencies = [ - "crossbeam-deque", - "crossbeam-utils", -] - [[package]] name = "redox_syscall" version = "0.5.12" @@ -3486,13 +3407,6 @@ dependencies = [ "serde", ] -[[package]] -name = "smartstring" -version = "1.0.0" -dependencies = [ - "serde", -] - [[package]] name = "smartstring" version = "1.0.1" @@ -3606,18 +3520,6 @@ version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" -[[package]] -name = "subgraph" -version = "0.1.0" -dependencies = [ - "anyhow", - "parser", - "rustc-hash", - "serde", - "serde_json", - "smartstring 1.0.1", -] - [[package]] name = "swift-rs" version = "1.0.7" @@ -3671,28 +3573,6 @@ dependencies = [ "syn 2.0.101", ] -[[package]] -name = "sys-info" -version = "0.1.0" -dependencies = [ - "ash", - "sysinfo", -] - -[[package]] -name = "sysinfo" -version = "0.33.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fc858248ea01b66f19d8e8a6d55f41deaf91e9d495246fd01368d99935c6c01" -dependencies = [ - "core-foundation-sys", - "libc", - "memchr", - "ntapi", - "rayon", - "windows 0.57.0", -] - [[package]] name = "system-deps" version = "6.2.2" @@ -3739,8 +3619,8 @@ dependencies = [ "tao-macros", "unicode-segmentation", "url", - "windows 0.61.1", - "windows-core 0.61.1", + "windows", + "windows-core", "windows-version", "x11-dl", ] @@ -3810,7 +3690,7 @@ dependencies = [ "webkit2gtk", "webview2-com", "window-vibrancy", - "windows 0.61.1", + "windows", ] [[package]] @@ -3974,7 +3854,7 @@ dependencies = [ "tauri-utils", "thiserror 2.0.12", "url", - "windows 0.61.1", + "windows", ] [[package]] @@ -4000,7 +3880,7 @@ dependencies = [ "url", "webkit2gtk", "webview2-com", - "windows 0.61.1", + "windows", "wry", ] @@ -4077,17 +3957,6 @@ dependencies = [ "utf-8", ] -[[package]] -name = "test-layout" -version = "0.0.1" -dependencies = [ - "layout", - "parser", - "serde", - "serde_json", - "smartstring 1.0.1", -] - [[package]] name = "thin-slice" version = "0.1.1" @@ -4494,12 +4363,12 @@ version = "0.1.0" dependencies = [ "ahash", "anyhow", + "fsg", "layout", "parser", "serde", "serde_json", - "smartstring 1.0.1", - "subgraph", + "smartstring", "tauri", "tauri-build", "tauri-plugin-dialog", @@ -4713,10 +4582,10 @@ checksum = "b542b5cfbd9618c46c2784e4d41ba218c336ac70d44c55e47b251033e7d85601" dependencies = [ "webview2-com-macros", "webview2-com-sys", - "windows 0.61.1", - "windows-core 0.61.1", - "windows-implement 0.60.0", - "windows-interface 0.59.1", + "windows", + "windows-core", + "windows-implement", + "windows-interface", ] [[package]] @@ -4737,8 +4606,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ae2d11c4a686e4409659d7891791254cf9286d3cfe0eef54df1523533d22295" dependencies = [ "thiserror 2.0.12", - "windows 0.61.1", - "windows-core 0.61.1", + "windows", + "windows-core", ] [[package]] @@ -4787,16 +4656,6 @@ dependencies = [ "windows-version", ] -[[package]] -name = "windows" -version = "0.57.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12342cb4d8e3b046f3d80effd474a7a02447231330ef77d71daa6fbc40681143" -dependencies = [ - "windows-core 0.57.0", - "windows-targets 0.52.6", -] - [[package]] name = "windows" version = "0.61.1" @@ -4804,7 +4663,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c5ee8f3d025738cb02bad7868bbb5f8a6327501e870bf51f1b455b0a2454a419" dependencies = [ "windows-collections", - "windows-core 0.61.1", + "windows-core", "windows-future", "windows-link", "windows-numerics", @@ -4816,19 +4675,7 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3beeceb5e5cfd9eb1d76b381630e82c4241ccd0d27f1a39ed41b2760b255c5e8" dependencies = [ - "windows-core 0.61.1", -] - -[[package]] -name = "windows-core" -version = "0.57.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2ed2439a290666cd67ecce2b0ffaad89c2a56b976b736e6ece670297897832d" -dependencies = [ - "windows-implement 0.57.0", - "windows-interface 0.57.0", - "windows-result 0.1.2", - "windows-targets 0.52.6", + "windows-core", ] [[package]] @@ -4837,10 +4684,10 @@ version = "0.61.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "46ec44dc15085cea82cf9c78f85a9114c463a369786585ad2882d1ff0b0acf40" dependencies = [ - "windows-implement 0.60.0", - "windows-interface 0.59.1", + "windows-implement", + "windows-interface", "windows-link", - "windows-result 0.3.3", + "windows-result", "windows-strings 0.4.1", ] @@ -4850,22 +4697,11 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc6a41e98427b19fe4b73c550f060b59fa592d7d686537eebf9385621bfbad8e" dependencies = [ - "windows-core 0.61.1", + "windows-core", "windows-link", "windows-threading", ] -[[package]] -name = "windows-implement" -version = "0.57.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9107ddc059d5b6fbfbffdfa7a7fe3e22a226def0b2608f72e9d552763d3e1ad7" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.101", -] - [[package]] name = "windows-implement" version = "0.60.0" @@ -4877,17 +4713,6 @@ dependencies = [ "syn 2.0.101", ] -[[package]] -name = "windows-interface" -version = "0.57.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29bee4b38ea3cde66011baa44dba677c432a78593e202392d1e9070cf2a7fca7" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.101", -] - [[package]] name = "windows-interface" version = "0.59.1" @@ -4911,7 +4736,7 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9150af68066c4c5c07ddc0ce30421554771e528bde427614c61038bc2c92c2b1" dependencies = [ - "windows-core 0.61.1", + "windows-core", "windows-link", ] @@ -4921,20 +4746,11 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4286ad90ddb45071efd1a66dfa43eb02dd0dfbae1545ad6cc3c51cf34d7e8ba3" dependencies = [ - "windows-result 0.3.3", + "windows-result", "windows-strings 0.3.1", "windows-targets 0.53.0", ] -[[package]] -name = "windows-result" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e383302e8ec8515204254685643de10811af0ed97ea37210dc26fb0032647f8" -dependencies = [ - "windows-targets 0.52.6", -] - [[package]] name = "windows-result" version = "0.3.3" @@ -5339,8 +5155,8 @@ dependencies = [ "webkit2gtk", "webkit2gtk-sys", "webview2-com", - "windows 0.61.1", - "windows-core 0.61.1", + "windows", + "windows-core", "windows-version", "x11-dl", ] diff --git a/plugins/mindstudio-insight-plugins/ModelVis/app/src-tauri/src/commands.rs b/plugins/mindstudio-insight-plugins/ModelVis/app/src-tauri/src/commands.rs index e2dea5c9d3335981c8fee1188fc55b16a3678148..ab5f7458b814554925c65c6c90054abad1e0b1cb 100644 --- a/plugins/mindstudio-insight-plugins/ModelVis/app/src-tauri/src/commands.rs +++ b/plugins/mindstudio-insight-plugins/ModelVis/app/src-tauri/src/commands.rs @@ -1,12 +1,12 @@ use std::{env::home_dir, fs::{create_dir, File}, io, io::{BufReader, BufWriter}, path::Path, time::Instant}; use std::path::PathBuf; use ahash::{HashMap, HashMapExt}; -use anyhow::Result; +use anyhow::{anyhow, Result}; use layout::{layout, Graph, GraphEdge, GraphNode, Key, KeyCodecExt}; use parser::{parse_bin, Model, StdString}; use serde::{de::DeserializeOwned, Deserialize, Serialize}; use smartstring::alias::String; -use fsg::{result::JSONResult, fsgs_bin}; +use fsg::{result::JSONResult, fsgs_model}; use tauri::{path::BaseDirectory, AppHandle, Emitter, Manager, Result as InvokeResult}; use tauri::async_runtime::spawn_blocking; use tauri_plugin_shell::ShellExt; @@ -388,8 +388,41 @@ fn read_from<'a, T: DeserializeOwned, P: AsRef>(path: P) -> T { } #[tauri::command] -pub fn mine_fsg(path: &str, min_sup: usize, min: usize, max: usize) -> InvokeResult> { - wrap(fsgs_bin(path, min_sup, min, max)) +pub fn mine_fsg(path: &str, name: &str, min_sup: usize, min: usize, max: usize) -> InvokeResult> { + let mut model = parse_bin(&path)?; + let single_graph = if model.name == name { + Model { + name: model.name.clone(), + nodes: model.nodes, + edges: model.edges, + parameters: model.parameters, + subgraphes: HashMap::new(), + } + } else { + recursive_get_single_graph(&mut model, name, 0)? + }; + wrap(fsgs_model(&single_graph, min_sup, min, max)) +} +fn recursive_get_single_graph(model: &mut Model, name: &str, depth: usize) -> Result { + if depth >= 10 { + return Err(anyhow!("Over depth 10!")); + } + if let Some(target) = model.subgraphes.get_mut(name) { + return Ok(Model { + name: target.name.clone(), + nodes: std::mem::take(&mut target.nodes), + edges: std::mem::take(&mut target.edges), + parameters: std::mem::take(&mut target.parameters), + subgraphes: HashMap::new(), + }); + } + for (_, subgraph) in model.subgraphes.iter_mut() { + if let Ok(target) = recursive_get_single_graph(subgraph, name, depth + 1) { + return Ok(target); + } + } + + Err(anyhow!("Subgraph with name '{}' not found", name)) } fn wrap(src: Result) -> InvokeResult { diff --git a/plugins/mindstudio-insight-plugins/ModelVis/rust/fsg/README.md b/plugins/mindstudio-insight-plugins/ModelVis/rust/fsg/README.md index 71234b08188345c371806ab53c1bef4ce97f5bc3..08c0c4151ef8d623bf7f6462d1a6787ccbb9e593 100644 --- a/plugins/mindstudio-insight-plugins/ModelVis/rust/fsg/README.md +++ b/plugins/mindstudio-insight-plugins/ModelVis/rust/fsg/README.md @@ -92,7 +92,7 @@ pub struct Graph { ```rust // 使用示例 fn main() { - println!("gSpan Subgraph Mining"); + println!("gSpan FSG Mining"); println!("---------------------"); let gspan_mining = GSpanMining; diff --git a/plugins/mindstudio-insight-plugins/ModelVis/rust/fsg/src/gspan/gspan.rs b/plugins/mindstudio-insight-plugins/ModelVis/rust/fsg/src/gspan/gspan.rs index 710161e9f3f0ecf2bf232cd494b27942b73b0118..6a59e114228d1cc982a3aa094ab2d1e7f1da44e7 100644 --- a/plugins/mindstudio-insight-plugins/ModelVis/rust/fsg/src/gspan/gspan.rs +++ b/plugins/mindstudio-insight-plugins/ModelVis/rust/fsg/src/gspan/gspan.rs @@ -1,19 +1,14 @@ /* * Copyright (c), Huawei Technologies Co., Ltd. 2025-2025. All rights reserved. */ -use std::{ - collections::BTreeMap - - , - usize, -}; +use std::collections::BTreeMap; use rustc_hash::FxHashSet; use smartstring::alias::String; use crate::gspan::{ misc::{ - get_backward, get_forward_edges, get_forward_pure, get_forward_rm_path, inner_support, + get_backward, get_forward_edges, get_forward_pure, get_forward_rm_path, is_inner_support_greater, support, }, models::{ @@ -41,12 +36,17 @@ impl GSpan { max_pat_max: usize, directed: bool, ) -> GSpan { - GSpan { trans: graphs, min_sup, inner_min_sup, max_pat_min, max_pat_max, directed } + GSpan { + trans: graphs, + min_sup, + inner_min_sup, + max_pat_min, + max_pat_max, + directed, + } } - pub fn run( - &self, - ) -> (usize, MaxDFSCodeGraphResult) { + pub fn run(&self) -> (usize, MaxDFSCodeGraphResult) { // 0. Prepare the Result let mut result = MaxDFSCodeGraphResult::default(); result.set_config( @@ -56,12 +56,12 @@ impl GSpan { self.max_pat_max, ); - // 1. Find single node frequent subgraph, if requested + // 1. Find single node frequent fsg, if requested let mut single_vertex_graph_map: BTreeMap< usize, - BTreeMap, usize)>, + BTreeMap, usize)>, > = BTreeMap::new(); - let mut single_vertex_label_frequent_map: BTreeMap = BTreeMap::new(); // 一个 graph 内重复的 vertex 的频繁度只记录一次 + let mut single_vertex_label_frequent_map: BTreeMap = BTreeMap::new(); // 一个 graph 内重复的 vertex 的频繁度只记录一次 if self.max_pat_min <= 1 { self.find_frequent_single_vertex( &mut single_vertex_graph_map, @@ -69,18 +69,12 @@ impl GSpan { ); } - // 2. Report the single vertex subgraphs + // 2. Report the single vertex fsgs let mut next_gid: usize = 0; - self.print_frequent_single_vertex( - &mut single_vertex_graph_map, - &mut single_vertex_label_frequent_map, - &mut next_gid, - ); - // 3. Subgraphs > Vertices // root: [from_label][e_label][to_label] -> Projected - let mut root: BTreeMap>> = + let mut root: BTreeMap>> = BTreeMap::new(); for g in &self.trans { for from in &g.vertices { @@ -89,33 +83,28 @@ impl GSpan { continue; } for edge in &edges { - let key_1 = from.label.clone(); + let key_1 = from.label; let root_1 = root.entry(key_1).or_default(); let key_2 = edge.e_label.clone(); let root_2 = root_1.entry(key_2).or_default(); - let key_3 = g.find_vertex(&edge.to).unwrap().label.clone(); + let key_3 = g.get_vertex(edge.to).unwrap().label; let root_3 = root_2.entry(key_3).or_insert(Projected::new()); root_3.push(g.id, edge, None); } } } let mut dfs_code = DFSCode::new(); - for (from_label_key, from_label_value) in root.iter() { + for (&from_label_key, from_label_value) in root.iter() { for (e_label_key, e_label_value) in from_label_value.iter() { - for (to_label_key, to_label_value) in e_label_value.iter() { + for (&to_label_key, to_label_value) in e_label_value.iter() { dfs_code.push( 0, 1, - from_label_key.clone(), + from_label_key, e_label_key.clone(), - to_label_key.clone(), - ); - self.sub_mining( - to_label_value, - &mut dfs_code, - &mut next_gid, - &mut result, + to_label_key, ); + self.sub_mining(to_label_value, &mut dfs_code, &mut next_gid, &mut result); dfs_code.pop_with_set_result(to_label_value, &mut result); } } @@ -125,64 +114,29 @@ impl GSpan { fn find_frequent_single_vertex( &self, - single_vertex_graph_map: &mut BTreeMap, usize)>>, - single_vertex_label_frequent_map: &mut BTreeMap, + single_vertex_graph_map: &mut BTreeMap, usize)>>, + single_vertex_label_frequent_map: &mut BTreeMap, ) { for graph in &self.trans { for vertex in &graph.vertices { - let key = &vertex.label; + let key = vertex.label; let d = single_vertex_graph_map.entry(graph.id).or_default(); - if d.get(key).is_none() { + if d.get(&key).is_none() { single_vertex_label_frequent_map - .entry(key.clone()) + .entry(key) .and_modify(|f| *f += 1) .or_insert(1); } - d.entry(key.clone()) + d.entry(key) .and_modify(|v| { - v.0.insert(vertex.name.clone()); + v.0.insert(vertex.name); v.1 += 1; }) - .or_insert(([vertex.name.clone()].iter().cloned().collect(), 1)); + .or_insert(([vertex.name].iter().copied().collect(), 1)); } } } - fn print_frequent_single_vertex( - &self, - single_vertex_graph_map: &BTreeMap, usize)>>, - single_vertex_label_frequent_map: &BTreeMap, - next_gid: &mut usize, - ) { - for (frequent_label, sup) in single_vertex_label_frequent_map.iter() { - // 判断图之间的支持度 - if sup < &self.min_sup { - continue; - } - - let mapped: Vec<(FxHashSet, usize)> = single_vertex_graph_map - .iter() - .map(|entry| { - entry.1.get(frequent_label).unwrap_or(&(FxHashSet::default(), 0)).clone() - }) - .collect(); - - // 计算图内部最小、最大支持度 - let mut min = usize::MAX; - let mut max = usize::MIN; - for (_, v) in mapped.iter() { - min = min.min(*v); - max = max.max(*v); - } - - if max < self.inner_min_sup { - continue; - } - - *next_gid += 1; - } - } - fn sub_mining( &self, projected: &Projected, @@ -199,11 +153,11 @@ impl GSpan { * mingt be its (n+1)-extension-graphs, hence we enumerate them all. */ let min_rm_path = dfs_code.build_rm_path(); - let min_label = dfs_code.get_dfs(0).from_label.clone(); - let max_to_code = dfs_code.get_dfs(*min_rm_path.get(0).unwrap()).to.clone(); + let min_label = dfs_code.get_dfs(0).from_label; + let max_to_code = dfs_code.get_dfs(min_rm_path[0]).to; let (new_fwd_root, new_bck_root) = - self.generate_next_root(projected, dfs_code, &min_rm_path, &min_label, max_to_code); + self.generate_next_root(projected, dfs_code, &min_rm_path, min_label, max_to_code); // Test all extended substructures.. // .. backward @@ -212,9 +166,9 @@ impl GSpan { dfs_code.push( max_to_code, *to_key, - Vertex::NIL_V_LABEL.into(), + Vertex::NIL_V_LABEL, e_label_key.clone(), - Vertex::NIL_V_LABEL.into(), + Vertex::NIL_V_LABEL, ); self.sub_mining(e_label_value, dfs_code, next_gid, result); dfs_code.pop_with_set_result(e_label_value, result); @@ -223,13 +177,13 @@ impl GSpan { // .. forward for (from_key, from_value) in new_fwd_root.iter().rev() { for (e_label_key, e_label_value) in from_value.iter() { - for (to_label_key, to_label_value) in e_label_value.iter() { + for (&to_label_key, to_label_value) in e_label_value.iter() { dfs_code.push( *from_key, max_to_code + 1, - Vertex::NIL_V_LABEL.into(), + Vertex::NIL_V_LABEL, e_label_key.clone(), - to_label_key.clone(), + to_label_key, ); self.sub_mining(to_label_value, dfs_code, next_gid, result); dfs_code.pop_with_set_result(to_label_value, result); @@ -243,14 +197,14 @@ impl GSpan { projected: &'a Projected<'a>, dfs_code: &DFSCode, min_rm_path: &Vec, - min_label: &str, + min_label: usize, max_to_code: usize, ) -> ( - BTreeMap>>>, + BTreeMap>>>, BTreeMap>>, ) { // [from][e_label][to_label] -> Projected - let mut new_fwd_root: BTreeMap>> = + let mut new_fwd_root: BTreeMap>> = BTreeMap::new(); // [to][e_label] -> Projected let mut new_bck_root: BTreeMap> = BTreeMap::new(); @@ -264,12 +218,12 @@ impl GSpan { for i in (0..min_rm_path.len()).rev() { let e = get_backward( self.trans.get(gid).unwrap(), - history.histories.get(*min_rm_path.get(i).unwrap()).unwrap(), - history.histories.get(*min_rm_path.get(0).unwrap()).unwrap(), + history.histories.get(min_rm_path[i]).unwrap(), + history.histories.get(min_rm_path[0]).unwrap(), &history, ); if let Some(e) = e { - let key_1 = dfs_code.get_dfs(*min_rm_path.get(i).unwrap()).from; + let key_1 = dfs_code.get_dfs(min_rm_path[i]).from; let root_1 = new_bck_root.entry(key_1).or_default(); let key_2: &String = &e.e_label; let root_2 = root_1.entry(key_2.clone()).or_insert(Projected::new()); @@ -278,28 +232,27 @@ impl GSpan { } // pure forward let edges: Vec<&Edge> = get_forward_pure( - self.trans.get(gid).unwrap(), - history.histories.get(*min_rm_path.get(0).unwrap()).unwrap(), - &min_label, + &self.trans[gid], + history.histories[min_rm_path[0]], + min_label, &history, ); if !edges.is_empty() { for it in &edges { let root_1 = new_fwd_root.entry(max_to_code).or_default(); - let key_2: &String = &it.e_label; + let key_2 = &it.e_label; let root_2 = root_1.entry(key_2.clone()).or_default(); - let key_3: &String = - &self.trans.get(gid).unwrap().find_vertex(&it.to).unwrap().label; - let root_3 = root_2.entry(key_3.clone()).or_insert(Projected::new()); + let key_3 = self.trans[gid].get_vertex(it.to).unwrap().label; + let root_3 = root_2.entry(key_3).or_insert(Projected::new()); root_3.push(gid, it, Some(&a_projected)); } } // backtracked forward for a_rm_path in min_rm_path { let edges: Vec<&Edge> = get_forward_rm_path( - self.trans.get(gid).unwrap(), - history.histories.get(*a_rm_path).unwrap(), - &min_label, + &self.trans[gid], + history.histories[*a_rm_path], + min_label, &history, ); if edges.is_empty() { @@ -308,11 +261,10 @@ impl GSpan { for it in &edges { let key_1 = dfs_code.get_dfs(*a_rm_path).from; let root_1 = new_fwd_root.entry(key_1).or_default(); - let key_2: &String = &it.e_label; + let key_2 = &it.e_label; let root_2 = root_1.entry(key_2.clone()).or_default(); - let key_3: &String = - &self.trans.get(gid).unwrap().find_vertex(&it.to).unwrap().label; - let root_3 = root_2.entry(key_3.clone()).or_insert(Projected::new()); + let key_3 = self.trans[gid].get_vertex(it.to).unwrap().label; + let root_3 = root_2.entry(key_3).or_insert(Projected::new()); root_3.push(gid, it, Some(&a_projected)); } } @@ -332,8 +284,7 @@ impl GSpan { return true; } // Check if the pattern is frequent enough, within graphs - let (min_inner_sup, max_inner_sup) = inner_support(projected); - if max_inner_sup < self.inner_min_sup { + if !is_inner_support_greater(projected, self.inner_min_sup) { return true; } // Check if the pattern is not min @@ -350,7 +301,7 @@ impl GSpan { if self.max_pat_max >= self.max_pat_min && dfs_code.count_node() > self.max_pat_max { return true; } - + *next_gid += 1; false @@ -371,18 +322,18 @@ impl GSpan { // [from_label][e_label][to_label] -> Projected // BTreeMap 在 Rust 中会自动根据键进行排序 - let mut root: BTreeMap>> = + let mut root: BTreeMap>> = BTreeMap::new(); for from in &graph_is_min.vertices { let edges: Vec<&Edge> = get_forward_edges(&graph_is_min, from); for it in &edges { - let key_1 = &it.from_label; - let root_1 = root.entry(key_1.clone()).or_default(); + let key_1 = it.from_label; + let root_1 = root.entry(key_1).or_default(); let key_2 = &it.e_label; let root_2 = root_1.entry(key_2.clone()).or_default(); - let key_3 = &it.to_label; - let root_3 = root_2.entry(key_3.clone()).or_insert(Projected::new()); + let key_3 = it.to_label; + let root_3 = root_2.entry(key_3).or_insert(Projected::new()); // 创建初始化子图:一个 Edge 就是一个最小子图 root_3.push(graph_is_min.id, it, None); } @@ -398,12 +349,17 @@ impl GSpan { dfs_code_is_min.push( 0, 1, - from_label_map_entry.0.clone(), + *from_label_map_entry.0, e_label_map_entry.0.clone(), - to_label_map_entry.0.clone(), + *to_label_map_entry.0, ); - self.is_min_dfscode(to_label_map_value, dfs_code, &mut dfs_code_is_min, &graph_is_min) + self.is_min_dfscode( + to_label_map_value, + dfs_code, + &mut dfs_code_is_min, + &graph_is_min, + ) } /** @@ -419,7 +375,9 @@ impl GSpan { graph_is_min: &Graph, ) -> bool { let min_rm_path = dfs_code_is_min.build_rm_path(); - let max_to_code = dfs_code_is_min.get_dfs(*min_rm_path.get(0).unwrap()).to.clone(); + let max_to_code = dfs_code_is_min + .get_dfs(min_rm_path[0]) + .to; { // backward 情况下是否最小: [e_label] -> Projected @@ -431,12 +389,15 @@ impl GSpan { dfs_code_is_min.push( max_to_code, new_to, - Vertex::NIL_V_LABEL.into(), + Vertex::NIL_V_LABEL, e_label_map_entry.key().clone(), - Vertex::NIL_V_LABEL.into(), + Vertex::NIL_V_LABEL, ); let len = dfs_code_is_min.dfs_vec.len(); - if dfs_code.get_dfs(len - 1).ne(dfs_code_is_min.get_dfs(len - 1)) { + if dfs_code + .get_dfs(len - 1) + .ne(dfs_code_is_min.get_dfs(len - 1)) + { return false; } return self.is_min_dfscode( @@ -455,7 +416,7 @@ impl GSpan { dfs_code_is_min, graph_is_min, &min_rm_path, - &max_to_code, + max_to_code, ); if let Some(root) = root { @@ -464,13 +425,16 @@ impl GSpan { dfs_code_is_min.push( new_from, max_to_code + 1, - Vertex::NIL_V_LABEL.into(), + Vertex::NIL_V_LABEL, e_label_map_key.into(), to_label_map_key.into(), ); let len: usize = dfs_code_is_min.dfs_vec.len(); - if dfs_code.get_dfs(len - 1).ne(dfs_code_is_min.get_dfs(len - 1)) { + if dfs_code + .get_dfs(len - 1) + .ne(dfs_code_is_min.get_dfs(len - 1)) + { return false; } return self.is_min_dfscode( @@ -498,7 +462,7 @@ impl GSpan { for i in (1..min_rm_path.len()).rev() { root = self.generate_e_p_map(projected, graph_is_min, &min_rm_path, i); if root.is_some() { - new_to = dfs_code_is_min.get_dfs(*min_rm_path.get(i).unwrap()).from; + new_to = dfs_code_is_min.get_dfs(min_rm_path[i]).from; break; } } @@ -511,34 +475,36 @@ impl GSpan { dfs_code_is_min: &mut DFSCode, graph_is_min: &'a Graph, min_rm_path: &Vec, - max_to_code: &usize, - ) -> (Option>>>, usize) { - let min_label = dfs_code_is_min.get_dfs(0).from_label.clone(); + max_to_code: usize, + ) -> ( + Option>>>, + usize, + ) { + let min_label = dfs_code_is_min.get_dfs(0).from_label; let mut new_from: usize = 0; - let mut root: Option>> = self + let mut root: Option>> = self .generate_e_to_p_map(projected, graph_is_min, |history| { - let last_rm_path_edge = - history.histories.get(*min_rm_path.get(0).unwrap()).unwrap(); - get_forward_pure(graph_is_min, last_rm_path_edge, &min_label, &history) + let last_rm_path_edge = history.histories[min_rm_path[0]]; + get_forward_pure(graph_is_min, last_rm_path_edge, min_label, &history) }); if root.is_some() { - new_from = max_to_code.clone(); + new_from = max_to_code; } else { // min_rm_path 是从大到小的 dfs_vec 索引 for i in 0..min_rm_path.len() { root = self.generate_e_to_p_map(projected, graph_is_min, |history| { - let cur_rm_path_edge = - history.histories.get(*min_rm_path.get(i).unwrap()).unwrap(); - get_forward_rm_path(graph_is_min, cur_rm_path_edge, &min_label, &history) + let cur_rm_path_edge = history.histories[min_rm_path[i]]; + get_forward_rm_path(graph_is_min, cur_rm_path_edge, min_label, &history) }); if root.is_some() { - new_from = dfs_code_is_min.get_dfs(*min_rm_path.get(i).unwrap()).from; + new_from = dfs_code_is_min.get_dfs(min_rm_path[i]).from; break; } } } + (root, new_from) } @@ -559,8 +525,8 @@ impl GSpan { // 获取最尾边重点到当前边起点的反向边 let backward_edge = get_backward( graph_is_min, - history.histories.get(*min_rm_path.get(i).unwrap()).unwrap(), // 路径当前边 - history.histories.get(*min_rm_path.get(0).unwrap()).unwrap(), // 路径最尾边 + history.histories[min_rm_path[i]], // 路径当前边 + history.histories[min_rm_path[0]], // 路径最尾边 &history, ); if let Some(backward_edge) = backward_edge { @@ -578,12 +544,12 @@ impl GSpan { projected: &'a Projected, graph_is_min: &'a Graph, generate_edges: F, - ) -> Option>>> + ) -> Option>>> where F: Fn(&History) -> Vec<&'a Edge>, { // [e_label][to_label] -> Projected - let mut root: BTreeMap> = BTreeMap::new(); + let mut root: BTreeMap> = BTreeMap::new(); for cur in projected.projections.iter() { let history: History = History::build(cur); @@ -592,8 +558,8 @@ impl GSpan { for it in edges { let key_1 = it.e_label.clone(); let root_1 = root.entry(key_1).or_default(); - let key_2 = graph_is_min.vertex_name_label_map.get(&it.to).unwrap(); - let root_2 = root_1.entry(key_2.clone()).or_insert(Projected::new()); + let key_2 = graph_is_min.key_opkey[&it.to]; + let root_2 = root_1.entry(key_2).or_insert(Projected::new()); root_2.push(0, it, Some(cur)); } } @@ -603,12 +569,16 @@ impl GSpan { fn get_first_entry_of_e_to_p<'a>( &self, - root: &'a BTreeMap>, - ) -> (&'a str, &'a str, &'a Projected<'a>) { + root: &'a BTreeMap>, + ) -> (&'a str, usize, &'a Projected<'a>) { let e_label_map_entry = root.first_key_value().unwrap(); let e_label_map_value = e_label_map_entry.1; let to_label_map_entry = e_label_map_value.first_key_value().unwrap(); let to_label_map_value = to_label_map_entry.1; - (e_label_map_entry.0, to_label_map_entry.0, to_label_map_value) + ( + e_label_map_entry.0, + *to_label_map_entry.0, + to_label_map_value, + ) } } diff --git a/plugins/mindstudio-insight-plugins/ModelVis/rust/fsg/src/gspan/misc.rs b/plugins/mindstudio-insight-plugins/ModelVis/rust/fsg/src/gspan/misc.rs index c05071b3306d96962a49b5a3be4cb00784cebf45..fe4f70303e6bdf28580eff776cc1e18d7c8c9c10 100644 --- a/plugins/mindstudio-insight-plugins/ModelVis/rust/fsg/src/gspan/misc.rs +++ b/plugins/mindstudio-insight-plugins/ModelVis/rust/fsg/src/gspan/misc.rs @@ -1,7 +1,7 @@ /* * Copyright (c), Huawei Technologies Co., Ltd. 2025-2025. All rights reserved. */ -use std::collections::HashMap; +use std::collections::{HashMap, HashSet}; use rustc_hash::FxHashSet; use smartstring::alias::String; @@ -26,23 +26,64 @@ pub fn support(projected: &Projected) -> usize { size } +// 简单判断某个子图模式在单个图中的支持度是否大于 x +// 计算 projected 内的 PrevDFS 的实值个数,即 projected 中所表示的子图模式出现过的相同图的数量 +// CORE:特殊处理,要去掉节点完全相同的投影情况 +pub fn is_inner_support_greater(projected: &Projected, x: usize) -> bool { + let mut count_map = HashMap::::new(); + + let mut unify_vertices_set: FxHashSet = HashSet::default(); + for cur in projected.projections.iter() { + let mut vertices_str_list: Vec = cur + .get_vertex_names() + .iter() + .map(|f| format!("{}/{}", &f.0, &f.1).into()) + .collect(); + vertices_str_list.sort(); + let vertices_str = vertices_str_list.into_iter().collect::(); + // 如果存在 + if unify_vertices_set.contains(&vertices_str) { + continue; + } + + unify_vertices_set.insert(vertices_str); + count_map + .entry(cur.gid) + .and_modify(|v| *v += 1) + .or_insert(1); + if count_map.values().any(|num| *num >= x) { + return true; + } + } + + false +} + // 计算某个子图模式在单个图中的支持度 // 计算 projected 内的 PrevDFS 的实值个数,即 projected 中所表示的子图模式出现过的相同图的数量 // CORE:特殊处理,要去掉节点完全相同的投影情况 pub fn inner_support(projected: &Projected) -> (usize, usize) { let mut count_map = HashMap::::new(); - let mut unify_vertices_list: Vec> = vec![]; + let mut unify_vertices_set: FxHashSet = HashSet::default(); for cur in projected.projections.iter() { - let set: FxHashSet = - cur.get_vertex_names().iter().map(|f| format!("{}/{}", &f.0, &f.1).into()).collect(); + let mut vertices_str_list: Vec = cur + .get_vertex_names() + .iter() + .map(|f| format!("{}/{}", &f.0, &f.1).into()) + .collect(); + vertices_str_list.sort(); + let vertices_str = vertices_str_list.into_iter().collect::(); // 如果存在 - if unify_vertices_list.contains(&set) { + if unify_vertices_set.contains(&vertices_str) { continue; } - unify_vertices_list.push(set); - count_map.entry(cur.gid).and_modify(|v| *v += 1).or_insert(1); + unify_vertices_set.insert(vertices_str); + count_map + .entry(cur.gid) + .and_modify(|v| *v += 1) + .or_insert(1); } let mut min = usize::MAX; @@ -59,7 +100,7 @@ pub fn inner_support(projected: &Projected) -> (usize, usize) { pub fn get_forward_edges<'a>(g: &Graph, v: &'a Vertex) -> Vec<&'a Edge> { let mut result: Vec<&Edge> = Vec::with_capacity(8); for edge in &v.edges { - if v.label <= g.vertex_name_label_map.get(&edge.to).unwrap().clone() { + if v.label <= g.key_opkey[&edge.to] { result.push(edge); } } @@ -75,38 +116,35 @@ pub fn get_backward<'a, 'b>( e2: &'a Edge, history: &'b History, ) -> Option<&'a Edge> { - if e1 == e2 { + if *e1 == *e2 { return None; } // 遍历从e2的终点出发的所有边 - for edge in &g.find_vertex(&e2.to).unwrap().edges { + for edge in &g.get_vertex(e2.to)?.edges { if history.has_edge(&edge.id) || edge.to != e1.from { continue; } // 找到一个边的终点是e1的起点 if e1.e_label < edge.e_label || (e1.e_label == edge.e_label - && g.vertex_name_label_map.get(&e1.to).unwrap() - <= g.vertex_name_label_map.get(&e2.to).unwrap()) + && g.key_opkey[&e1.to] + <= g.key_opkey[&e2.to]) { return Some(&edge); } } - return None; + None } -// 获取图中最右下节点引出的所有 Forward 边 pub fn get_forward_pure<'a, 'b>( g: &'a Graph, e: &'b Edge, - min_label: &str, + min_label: usize, history: &'b History, ) -> Vec<&'a Edge> { let mut result: Vec<&Edge> = Vec::with_capacity(8); - for edge in &g.find_vertex(&e.to).unwrap().edges { - if min_label > g.vertex_name_label_map.get(&edge.to).unwrap().as_str() - || history.has_vertex(&edge.to) - { + for edge in &g.get_vertex(e.to).unwrap().edges { + if min_label > g.key_opkey[&edge.to] || history.has_vertex(&edge.to) { continue; } result.push(&edge); @@ -118,14 +156,14 @@ pub fn get_forward_pure<'a, 'b>( pub fn get_forward_rm_path<'a, 'b>( g: &'a Graph, e: &'b Edge, - min_label: &str, + min_label: usize, history: &'b History, ) -> Vec<&'a Edge> { let mut result: Vec<&Edge> = Vec::with_capacity(8); - let to_label = g.vertex_name_label_map.get(&e.to).unwrap().as_str(); + let to_label = g.key_opkey[&e.to]; - for edge in &g.find_vertex(&e.from).unwrap().edges { - let to_label_2 = g.vertex_name_label_map.get(&edge.to).unwrap().as_str(); + for edge in &g.get_vertex(e.from).unwrap().edges { + let to_label_2 = g.key_opkey[&edge.to]; if e.to == edge.to || min_label > to_label_2 || history.has_vertex(&edge.to) { continue; } diff --git a/plugins/mindstudio-insight-plugins/ModelVis/rust/fsg/src/gspan/models/dfs.rs b/plugins/mindstudio-insight-plugins/ModelVis/rust/fsg/src/gspan/models/dfs.rs index eac379db002b66ccaa4fa7303159081c115591a8..4881f75370d44acaaa1628352fc11901f21cfb0b 100644 --- a/plugins/mindstudio-insight-plugins/ModelVis/rust/fsg/src/gspan/models/dfs.rs +++ b/plugins/mindstudio-insight-plugins/ModelVis/rust/fsg/src/gspan/models/dfs.rs @@ -11,18 +11,18 @@ use smartstring::alias::String; pub struct DFS { pub from: usize, pub to: usize, - pub from_label: String, + pub from_label: usize, pub e_label: String, - pub to_label: String, + pub to_label: usize, } impl DFS { pub fn from( from: usize, to: usize, - from_label: String, + from_label: usize, e_label: String, - to_label: String, + to_label: usize, ) -> DFS { DFS { from, to, from_label, e_label, to_label } } diff --git a/plugins/mindstudio-insight-plugins/ModelVis/rust/fsg/src/gspan/models/dfs_code.rs b/plugins/mindstudio-insight-plugins/ModelVis/rust/fsg/src/gspan/models/dfs_code.rs index 673dbf136b34b6e1f941ce1a2679926e0c5f2b99..26dad76e4706d46c8f96716f6118f00b65ad2420 100644 --- a/plugins/mindstudio-insight-plugins/ModelVis/rust/fsg/src/gspan/models/dfs_code.rs +++ b/plugins/mindstudio-insight-plugins/ModelVis/rust/fsg/src/gspan/models/dfs_code.rs @@ -1,9 +1,8 @@ /* * Copyright (c), Huawei Technologies Co., Ltd. 2025-2025. All rights reserved. */ -use std::collections::HashSet; -use std::fmt::format; use smartstring::alias::String; +use std::collections::HashSet; use super::projected::Projected; use crate::gspan::{ @@ -24,19 +23,23 @@ pub struct DFSCode { impl DFSCode { pub fn new() -> DFSCode { - DFSCode { is_push_result: false, dfs_vec: Vec::with_capacity(32) } + DFSCode { + is_push_result: false, + dfs_vec: Vec::with_capacity(32), + } } pub fn push( &mut self, from: usize, to: usize, - from_label: String, + from_label: usize, e_label: String, - to_label: String, + to_label: usize, ) { self.is_push_result = false; - self.dfs_vec.push(DFS::from(from, to, from_label, e_label, to_label)); + self.dfs_vec + .push(DFS::from(from, to, from_label, e_label, to_label)); } pub fn pop_with_set_result( @@ -46,10 +49,10 @@ impl DFSCode { ) -> Option { if !self.is_push_result { // 记录尽可能远的深度搜索的结果 - + self.is_push_result = result.add_value(self, projected); } - return self.dfs_vec.pop(); + self.dfs_vec.pop() } pub fn get_dfs(&self, index: usize) -> &DFS { @@ -58,19 +61,17 @@ impl DFSCode { pub fn to_graph(&self, graph_id: usize, directed: bool) -> Graph { let mut g = Graph::new(graph_id, directed); - let mut edge_data = Vec::<(String, String, Option)>::with_capacity(8); + let mut edge_data = Vec::<(usize, usize, Option)>::with_capacity(8); for it in &self.dfs_vec { - let from_name = String::from(format!("{}", it.from)); - if it.from_label != "" && !g.vertex_name_label_map.contains_key(&from_name) { - g.insert_vertex(&from_name, &it.from_label); + if it.from_label != usize::MAX && !g.key_opkey.contains_key(&it.from) { + g.insert_vertex(it.from, it.from_label); } - let to_name = String::from(format!("{}", it.to)); - if it.to_label != "" && !g.vertex_name_label_map.contains_key(&to_name) { - g.insert_vertex(&to_name, &it.to_label); + if it.to_label != usize::MAX && !g.key_opkey.contains_key(&it.to) { + g.insert_vertex(it.to, it.to_label); } // build_edge - edge_data.push((from_name, to_name, Some(it.e_label.clone()))); + edge_data.push((it.from, it.to, Some(it.e_label.clone()))); } g.build_edge(edge_data); g @@ -82,7 +83,7 @@ impl DFSCode { let mut rm_path: Vec = Vec::new(); let mut old_from = usize::MAX; for i in (0..self.dfs_vec.len()).rev() { - let dfs = self.dfs_vec.get(i).unwrap(); + let dfs = &self.dfs_vec[i]; if dfs.from < dfs.to && (rm_path.is_empty() || old_from == dfs.to) { rm_path.push(i); old_from = dfs.from; diff --git a/plugins/mindstudio-insight-plugins/ModelVis/rust/fsg/src/gspan/models/edge.rs b/plugins/mindstudio-insight-plugins/ModelVis/rust/fsg/src/gspan/models/edge.rs index 5d6d483b16a11e38e1227eabcc16ae278f8123f4..1bdf52ed6e474410a64732c72d7440f954a2474e 100644 --- a/plugins/mindstudio-insight-plugins/ModelVis/rust/fsg/src/gspan/models/edge.rs +++ b/plugins/mindstudio-insight-plugins/ModelVis/rust/fsg/src/gspan/models/edge.rs @@ -4,13 +4,13 @@ use std::sync::atomic::{AtomicUsize, Ordering}; use smartstring::alias::String; -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Eq, PartialEq)] pub struct Edge { pub id: usize, - pub from: String, - pub to: String, - pub from_label: String, - pub to_label: String, + pub from: usize, + pub to: usize, + pub from_label: usize, + pub to_label: usize, pub e_label: String, } @@ -18,10 +18,10 @@ impl Edge { pub const NIL_E_LABEL: &'static str = ""; pub fn new( - from: String, - to: String, - from_label: String, - to_label: String, + from: usize, + to: usize, + from_label: usize, + to_label: usize, e_label: Option, ) -> Edge { static COUNTER: AtomicUsize = AtomicUsize::new(1); @@ -38,11 +38,3 @@ impl Edge { } } } - -impl PartialEq for Edge { - fn eq(&self, other: &Self) -> bool { - self.from_label == other.from_label - && self.to_label == other.to_label - && self.e_label == other.e_label - } -} diff --git a/plugins/mindstudio-insight-plugins/ModelVis/rust/fsg/src/gspan/models/graph.rs b/plugins/mindstudio-insight-plugins/ModelVis/rust/fsg/src/gspan/models/graph.rs index c396933d2aea2be7ec66350eb3090507ab56e265..723445627ef0cdd2de3710bcf8b1f6092314771b 100644 --- a/plugins/mindstudio-insight-plugins/ModelVis/rust/fsg/src/gspan/models/graph.rs +++ b/plugins/mindstudio-insight-plugins/ModelVis/rust/fsg/src/gspan/models/graph.rs @@ -3,21 +3,19 @@ */ use std::collections::HashMap; +use crate::context::Context; +use crate::gspan::models::{edge::Edge, vertex::Vertex}; +use parser::Model; use smartstring::alias::String; -use crate::{ - gspan::models::{edge::Edge, vertex::Vertex}, - io::{model_graph::ModelGraph, node::Node}, -}; - #[derive(Debug, Clone)] pub struct Graph { pub id: usize, pub name: String, pub edge_size: usize, - pub directed: bool, + pub directed: bool, // 默认为 false,没有方向的情况下,边(a,b)两个节点a,b都应该记录边(a,b)和(b,a) pub vertices: Vec, - pub vertex_name_label_map: HashMap, + pub key_opkey: HashMap, } impl Graph { @@ -28,73 +26,104 @@ impl Graph { edge_size: 0, directed, vertices: Vec::with_capacity(32), - vertex_name_label_map: HashMap::new(), + key_opkey: HashMap::new(), } } - pub fn insert_vertex(&mut self, name: &str, label: &str) { - self.vertex_name_label_map.insert(name.into(), label.into()); - let vertex = Vertex::new(name.into(), Some(label.into())); + pub fn insert_vertex(&mut self, name: usize, label: usize) { + self.key_opkey.insert(name, label); + let vertex = Vertex::new(name, label); self.vertices.push(vertex); } - pub fn build_edge(&mut self, data: Vec<(String, String, Option)>) { + pub fn build_edge(&mut self, data: Vec<(usize, usize, Option)>) { for (from, to, e_label) in data { + // 默认要 from 节点添加 (from, to) 的边 if let Some(f_vertex) = self.vertices.iter_mut().find(|x| x.name == from) { - if let Some(to_label) = self.vertex_name_label_map.get(&to) { + if let Some(to_label) = self.key_opkey.get(&to) { let edge = - Edge::new(from, to, f_vertex.label.clone(), to_label.clone(), e_label); + Edge::new(from, to, f_vertex.label.clone(), to_label.clone(), e_label.clone()); f_vertex.push(edge); self.edge_size += 1; - } else { - println!("Error: build_edge => {} 不存在 to_label.", to); } - } else { - println!("Error: build_edge => {} 不存在 vertex.", from); + } + if !self.directed { + // 无向图,要 to 节点添加 (to, from) 的边 + if let Some(t_vertex) = self.vertices.iter_mut().find(|x| x.name == to) { + if let Some(from_label) = self.key_opkey.get(&from) { + let edge = + Edge::new(to, from, from_label.clone(), t_vertex.label.clone(), e_label); + t_vertex.push(edge); + // 不必重复添加 edge_size + } + } } } } } impl Graph { - pub fn find_vertex(&self, name: &str) -> Option<&Vertex> { + pub fn get_vertex(&self, name: usize) -> Option<&Vertex> { self.vertices.iter().find(|x| x.name == name) } - fn push_node(&mut self, node: &Node) { - let vertex = Vertex::from(node); - self.vertex_name_label_map.insert(vertex.name.clone(), vertex.label.clone()); + fn get_vertex_mut(&mut self, name: usize) -> Option<&mut Vertex> { + self.vertices.iter_mut().find(|x| x.name == name) + } + + fn add_vertex(&mut self, name: usize, optype: usize) { + let vertex = Vertex::new(name, optype); self.vertices.push(vertex); } - fn build_edges_for_nodes(&mut self, edges: Vec<(String, String)>) { + fn build_edges(&mut self, edges: &Vec<(String, String)>, ctx: &Context) { for (from, to) in edges { - if let Some(f_vertex) = self.vertices.iter_mut().find(|x| x.name == from) { - if let Some(to_label) = self.vertex_name_label_map.get(&to) { + // 默认要 from 节点添加 (from, to) 的边 + if let Some(f_vertex) = self.get_vertex_mut(ctx.name_key[from.as_str()]) { + if let Some(&to_label) = ctx.name_opkey.get(to.as_str()) { let edge = Edge::new( - from, - to, - f_vertex.label.clone(), - to_label.clone(), + ctx.name_key[from.as_str()], + ctx.name_key[to.as_str()], + f_vertex.label, + to_label, Some(Edge::NIL_E_LABEL.into()), ); f_vertex.push(edge); self.edge_size += 1; } } + if !self.directed { + // 无向图,要 to 节点添加 (to, from) 的边 + if let Some(t_vertex) = self.get_vertex_mut(ctx.name_key[to.as_str()]) { + if let Some(&from_label) = ctx.name_opkey.get(from.as_str()) { + let edge = Edge::new( + ctx.name_key[to.as_str()], + ctx.name_key[from.as_str()], + from_label, + t_vertex.label, + Some(Edge::NIL_E_LABEL.into()), + ); + t_vertex.push(edge); + // 不必重复添加 edge_size + } + } + } } } } impl Graph { - pub fn from_model_graph(model_graph: ModelGraph, directed: bool) -> Graph { - let node_map = model_graph.nodes; + pub fn from_model_graph(raw: &Model, ctx: &mut Context, directed: bool) -> Graph { let mut graph = Graph::new(0, directed); - graph.name = model_graph.name; - for (_, val) in &node_map { - graph.push_node(val); + graph.name = raw.name.clone(); + for (id, val) in &raw.nodes { + let key = ctx.name_key[id.as_str()]; + let opkey = ctx.op_opkey[val.opType.as_str()]; + graph.key_opkey.insert(key, opkey); + graph.add_vertex(key, opkey); } - graph.build_edges_for_nodes(model_graph.edges); - return graph; + graph.build_edges(&raw.edges, ctx); + + graph } } diff --git a/plugins/mindstudio-insight-plugins/ModelVis/rust/fsg/src/gspan/models/history.rs b/plugins/mindstudio-insight-plugins/ModelVis/rust/fsg/src/gspan/models/history.rs index c022dbaebdfdc04ee473947a93c6bb2bd0a18c50..2c577d91246511dcab8577ed8ba36f6e15ee84cf 100644 --- a/plugins/mindstudio-insight-plugins/ModelVis/rust/fsg/src/gspan/models/history.rs +++ b/plugins/mindstudio-insight-plugins/ModelVis/rust/fsg/src/gspan/models/history.rs @@ -2,7 +2,6 @@ * Copyright (c), Huawei Technologies Co., Ltd. 2025-2025. All rights reserved. */ use rustc_hash::FxHashSet; -use smartstring::alias::String; use crate::gspan::models::{edge::Edge, prev_dfs::PrevDFS}; @@ -14,7 +13,7 @@ use crate::gspan::models::{edge::Edge, prev_dfs::PrevDFS}; pub struct History<'a> { pub histories: Vec<&'a Edge>, pub edges: FxHashSet, - pub vertices: FxHashSet, + pub vertices: FxHashSet, } impl<'a> History<'a> { @@ -28,8 +27,8 @@ impl<'a> History<'a> { loop { history.histories.push(e.edge); history.edges.insert(e.edge.id); - history.vertices.insert(e.edge.from.clone()); - history.vertices.insert(e.edge.to.clone()); + history.vertices.insert(e.edge.from); + history.vertices.insert(e.edge.to); if e.prev.is_none() { break; } @@ -43,7 +42,7 @@ impl<'a> History<'a> { self.edges.contains(&id) } - pub fn has_vertex(&self, name: &str) -> bool { + pub fn has_vertex(&self, name: &usize) -> bool { self.vertices.contains(name) } } diff --git a/plugins/mindstudio-insight-plugins/ModelVis/rust/fsg/src/gspan/models/prev_dfs.rs b/plugins/mindstudio-insight-plugins/ModelVis/rust/fsg/src/gspan/models/prev_dfs.rs index 3f0d1031c644f31db9ae6fb2505f8fe3a1e5e263..bec4c64efef7bc287c8c000e709ee91e04ded802 100644 --- a/plugins/mindstudio-insight-plugins/ModelVis/rust/fsg/src/gspan/models/prev_dfs.rs +++ b/plugins/mindstudio-insight-plugins/ModelVis/rust/fsg/src/gspan/models/prev_dfs.rs @@ -2,7 +2,6 @@ * Copyright (c), Huawei Technologies Co., Ltd. 2025-2025. All rights reserved. */ use rustc_hash::FxHashSet; -use smartstring::alias::String; use crate::gspan::models::edge::Edge; @@ -34,14 +33,14 @@ impl<'a> PrevDFS<'a> { } } - pub fn get_vertex_names(&self) -> FxHashSet<(usize, String)> { - let mut names: FxHashSet<(usize, String)> = FxHashSet::default(); + pub fn get_vertex_names(&self) -> FxHashSet<(usize, usize)> { + let mut names: FxHashSet<(usize, usize)> = FxHashSet::default(); let mut cur = self; loop { - names.insert((cur.gid.clone(), cur.edge.from.clone())); - names.insert((cur.gid.clone(), cur.edge.to.clone())); + names.insert((cur.gid.clone(), cur.edge.from)); + names.insert((cur.gid.clone(), cur.edge.to)); if let Some(prev) = &cur.prev { cur = **prev; diff --git a/plugins/mindstudio-insight-plugins/ModelVis/rust/fsg/src/gspan/models/projected.rs b/plugins/mindstudio-insight-plugins/ModelVis/rust/fsg/src/gspan/models/projected.rs index 76674aa72c3399cbfa5b56c413be449293edb58b..7a5116a7ca649e68d60ca4660b0452d889f68417 100644 --- a/plugins/mindstudio-insight-plugins/ModelVis/rust/fsg/src/gspan/models/projected.rs +++ b/plugins/mindstudio-insight-plugins/ModelVis/rust/fsg/src/gspan/models/projected.rs @@ -2,7 +2,6 @@ * Copyright (c), Huawei Technologies Co., Ltd. 2025-2025. All rights reserved. */ use rustc_hash::FxHashSet; -use smartstring::alias::String; use crate::gspan::models::{edge::Edge, prev_dfs::PrevDFS}; // PrevDFS 链表节点的集合 @@ -27,7 +26,7 @@ impl<'a> Projected<'a> { self.projections.push(Box::new(new_pdfs)); } - pub fn to_vertex_names_list(&self) -> Vec> { + pub fn to_vertex_names_list(&self) -> Vec> { self.projections.iter().map(|p| p.get_vertex_names()).collect() } diff --git a/plugins/mindstudio-insight-plugins/ModelVis/rust/fsg/src/gspan/models/vertex.rs b/plugins/mindstudio-insight-plugins/ModelVis/rust/fsg/src/gspan/models/vertex.rs index e633757ce04ab8f7a9cc889ac4729c10c4a22c47..4d144c076386b6bc7c1deeb35ae98bb1c07ef38f 100644 --- a/plugins/mindstudio-insight-plugins/ModelVis/rust/fsg/src/gspan/models/vertex.rs +++ b/plugins/mindstudio-insight-plugins/ModelVis/rust/fsg/src/gspan/models/vertex.rs @@ -1,26 +1,22 @@ /* * Copyright (c), Huawei Technologies Co., Ltd. 2025-2025. All rights reserved. */ -use crate::{gspan::models::edge::Edge, io::node::Node}; -use smartstring::alias::String; +use crate::gspan::models::edge::Edge; #[derive(Debug, Clone)] pub struct Vertex { - pub name: String, - pub label: String, + pub name: usize, + pub label: usize, pub edges: Vec, } impl Vertex { - pub const NIL_V_LABEL: &str = ""; + pub const NIL_V_LABEL: usize = usize::MAX; - pub fn new(name: String, label: Option) -> Vertex { + pub fn new(name: usize, label: usize) -> Vertex { Vertex { name, - label: match label { - None => String::new(), - Some(label) => label, - }, + label, edges: Vec::with_capacity(8), } } @@ -28,10 +24,6 @@ impl Vertex { pub fn push(&mut self, edge: Edge) { self.edges.push(edge); } - - pub fn from(node: &Node) -> Vertex { - Vertex::new(node.name.clone(), Some(node.opType.clone())) - } } impl PartialEq for Vertex { diff --git a/plugins/mindstudio-insight-plugins/ModelVis/rust/fsg/src/gspan/result.rs b/plugins/mindstudio-insight-plugins/ModelVis/rust/fsg/src/gspan/result.rs index d2c33e7d62ea1e242280f7cd9aa661b2113d912c..457a65c2fdecdd9a8266c61640f065d7aeee4b8f 100644 --- a/plugins/mindstudio-insight-plugins/ModelVis/rust/fsg/src/gspan/result.rs +++ b/plugins/mindstudio-insight-plugins/ModelVis/rust/fsg/src/gspan/result.rs @@ -4,11 +4,10 @@ use smartstring::alias::String; use crate::{ - gspan::{ - misc::{inner_support, support}, + context::Context, gspan::{ + misc::{is_inner_support_greater, support}, models::{dfs_code::DFSCode, projected::Projected}, - }, - io::output::{Instance, NodeId, Structure}, + }, io::output::{Instance, NodeId, Structure} }; use rustc_hash::FxHashSet; use serde::{Deserialize, Serialize}; @@ -30,7 +29,7 @@ pub struct MaxDFSCodeGraphResult { inner_min_sup: usize, max_pat_min: usize, // Minimum number of vertices max_pat_max: usize, // Maximum number of vertices - value: Vec<(DFSCode, Vec>)>, + value: Vec<(DFSCode, Vec>)>, } impl MaxDFSCodeGraphResult { @@ -54,8 +53,7 @@ impl MaxDFSCodeGraphResult { return false; } // Check if the pattern is frequent enough, inner graph - let (_min_inner_sup, max_inner_sup) = inner_support(projected); - if max_inner_sup < self.inner_min_sup { + if !is_inner_support_greater(projected, self.inner_min_sup) { return false; } // Check if the dfs_code vertices.len in [max_pat_min, max_pat_max] @@ -66,13 +64,12 @@ impl MaxDFSCodeGraphResult { return false; } let item = (dfs_code.clone(), projected.to_vertex_names_list()); - let edges_list = projected.to_edges_list(); self.value.push(item); true } - pub fn get_result(&self) -> Vec { + pub fn get_result(&self, ctx: &Context) -> Vec { self.value .iter() .map(|v| { @@ -81,7 +78,7 @@ impl MaxDFSCodeGraphResult { if let Some(graph_id) = first.iter().next().map(|(gid, _)| *gid) { let g = v.0.to_graph(graph_id, false); optype_struct = g.vertices.iter() - .map(|v| v.label.clone()).collect::>().join(",").into(); + .map(|v| ctx.opkey_op[&v.label].clone()).collect::>().join(",").into(); } } let instances = @@ -89,7 +86,7 @@ impl MaxDFSCodeGraphResult { .map(|set| { let node_ids = set .iter() - .map(|p| NodeId { gid: p.0, nid: p.1.clone() }) + .map(|p| NodeId { gid: p.0, nid: ctx.key_name[&p.1].clone() }) .collect::>(); return Instance { node_num: node_ids.len(), node_ids, edges: vec![] }; }) diff --git a/plugins/mindstudio-insight-plugins/ModelVis/rust/fsg/src/io/context.rs b/plugins/mindstudio-insight-plugins/ModelVis/rust/fsg/src/io/context.rs new file mode 100644 index 0000000000000000000000000000000000000000..a09ffe67f2322c500839586784036c5712a48ead --- /dev/null +++ b/plugins/mindstudio-insight-plugins/ModelVis/rust/fsg/src/io/context.rs @@ -0,0 +1,113 @@ +/* + * Copyright (c), Huawei Technologies Co., Ltd. 2025-2025. All rights reserved. + */ +use serde::{Deserialize, Serialize}; +use smartstring::alias::String; +use std::collections::{HashMap, VecDeque}; +use parser::Model; + +#[derive(Debug, Serialize, Deserialize)] +pub struct Context { + key_counter: usize, + op_key_counter: usize, + pub name_key: HashMap, + pub key_name: HashMap, + pub op_opkey: HashMap, + pub opkey_op: HashMap, + pub name_opkey: HashMap, // name 唯一, op 可重复 +} + +/// 对给定的有向图 Model 进行拓扑排序 +/// 返回按拓扑顺序排列的节点名列表 +/// 如果图中存在环,返回错误 +fn topological_sort(model: &Model) -> Result, &'static str> { + let mut in_degree: HashMap<&String, usize> = HashMap::new(); + + // 初始化所有节点的入度为 0 + for node_id in model.nodes.keys() { + in_degree.insert(node_id, 0); + } + + // 计算每个节点的入度 + for (_, to) in &model.edges { + if model.nodes.contains_key(to) { + *in_degree.entry(to).or_insert(0) += 1; + } + } + + // 使用 VecDeque 存放入度为 0 的节点 + let mut queue: VecDeque<&String> = VecDeque::new(); + for (node_id, °ree) in &in_degree { + if degree == 0 { + queue.push_back(*node_id); + } + } + + let mut sorted = Vec::new(); + + while let Some(node_id) = queue.pop_front() { + sorted.push(node_id.clone()); + + // 遍历该节点的所有出边 + for (from, to) in &model.edges { + if from == node_id && model.nodes.contains_key(to) { + let in_deg = in_degree.get_mut(to).unwrap(); + *in_deg -= 1; + if *in_deg == 0 { + queue.push_back(to); + } + } + } + } + + // 检查是否所有节点都被排序(防止环) + if sorted.len() == model.nodes.len() { + Ok(sorted) + } else { + Err("Cycle detected in the graph") + } +} + +impl Context { + pub fn new() -> Self { + Self { + key_counter: 0, + op_key_counter: 0, + name_key: HashMap::new(), + key_name: HashMap::new(), + op_opkey: HashMap::new(), + opkey_op: HashMap::new(), + name_opkey: HashMap::new(), + } + } + + pub fn generate_context(&mut self, model: &Model) { + // Model 是有向无环图,因此使用拓扑排序 + match topological_sort(&model) { + Ok(vec) => { + for id in &vec { + let val = model.nodes.get(id).unwrap(); + let key = self.key_counter; + self.name_key.insert(id.clone(), key); + self.key_name.insert(key, id.clone()); + self.key_counter += 1; + + let opkey = self.op_key_counter; + if !self.op_opkey.contains_key(&val.opType) { + self.op_opkey.insert(val.opType.clone(), opkey); + self.opkey_op.insert(opkey, val.opType.clone()); + self.op_key_counter += 1; + } + self.name_opkey.insert(id.clone(), self.op_opkey[&val.opType]); + } + } + Err(err) => { + println!("{}", err); + } + } + } + + pub fn is_available(&self) -> bool { + self.key_counter > 0 || self.op_key_counter > 0 + } +} \ No newline at end of file diff --git a/plugins/mindstudio-insight-plugins/ModelVis/rust/fsg/src/io/mod.rs b/plugins/mindstudio-insight-plugins/ModelVis/rust/fsg/src/io/mod.rs index 07c96e70a866a16b7a2470d530018d7c28b45d12..16f416e25443fd85f0bb47b4c0c5b7b6345b22f8 100644 --- a/plugins/mindstudio-insight-plugins/ModelVis/rust/fsg/src/io/mod.rs +++ b/plugins/mindstudio-insight-plugins/ModelVis/rust/fsg/src/io/mod.rs @@ -1,6 +1,5 @@ /* * Copyright (c), Huawei Technologies Co., Ltd. 2025-2025. All rights reserved. */ -pub mod model_graph; -pub mod node; pub mod output; +pub mod context; diff --git a/plugins/mindstudio-insight-plugins/ModelVis/rust/fsg/src/io/model_graph.rs b/plugins/mindstudio-insight-plugins/ModelVis/rust/fsg/src/io/model_graph.rs deleted file mode 100644 index 8ed5db0d405beb8ff24153af3a821a5836f05012..0000000000000000000000000000000000000000 --- a/plugins/mindstudio-insight-plugins/ModelVis/rust/fsg/src/io/model_graph.rs +++ /dev/null @@ -1,17 +0,0 @@ -/* - * Copyright (c), Huawei Technologies Co., Ltd. 2025-2025. All rights reserved. - */ -use std::collections::HashMap; - -use smartstring::alias::String; -use serde::{Deserialize, Serialize}; - -use crate::io::node::Node; - -#[derive(Serialize, Deserialize, Clone)] -pub struct ModelGraph { - pub name: String, - pub nodes: HashMap, - pub edges: Vec<(String, String)>, - pub parameters: HashMap, -} diff --git a/plugins/mindstudio-insight-plugins/ModelVis/rust/fsg/src/io/node.rs b/plugins/mindstudio-insight-plugins/ModelVis/rust/fsg/src/io/node.rs deleted file mode 100644 index 9cce1cc429f0183bcda2043a36341ff05db6fad5..0000000000000000000000000000000000000000 --- a/plugins/mindstudio-insight-plugins/ModelVis/rust/fsg/src/io/node.rs +++ /dev/null @@ -1,13 +0,0 @@ -/* - * Copyright (c), Huawei Technologies Co., Ltd. 2025-2025. All rights reserved. - */ -use serde::{Deserialize, Serialize}; -use smartstring::alias::String; - -#[derive(Serialize, Deserialize, Debug, Clone)] -#[allow(non_snake_case)] -pub struct Node { - pub name: String, - pub opType: String, - pub input: Vec, -} diff --git a/plugins/mindstudio-insight-plugins/ModelVis/rust/fsg/src/lib.rs b/plugins/mindstudio-insight-plugins/ModelVis/rust/fsg/src/lib.rs index 0d23f33e601a221d553553f2239da4d47cc0c224..a2bc765b75c0902704ba34743ef9bc2a3d824e49 100644 --- a/plugins/mindstudio-insight-plugins/ModelVis/rust/fsg/src/lib.rs +++ b/plugins/mindstudio-insight-plugins/ModelVis/rust/fsg/src/lib.rs @@ -10,50 +10,58 @@ pub use gspan::*; pub mod io; pub use io::*; -use parser::{parse_bin, Model, Node}; +use parser::{parse_bin, Model}; +use crate::io::context::Context; use crate::{ - io::{model_graph::ModelGraph, node::Node as ModelNode}, models::graph::Graph, result::JSONResult, }; use crate::gspan::gspan::GSpan; -impl From for ModelGraph { - fn from(model: Model) -> Self { - ModelGraph { - name: model.name.into(), - nodes: model.nodes.into_iter().map(|(k, v)| (k.into(), v.into())).collect(), - edges: model.edges.into_iter().map(|(k, v)| (k.into(), v.into())).collect(), - parameters: model.parameters.into_iter().map(|(k, v)| (k.into(), v.into())).collect(), - } - } +fn get_context(model: &Model) -> Context { + let mut ctx = Context::new(); + ctx.generate_context(model); + ctx } -impl From for ModelNode { - fn from(node: Node) -> Self { - ModelNode { - name: node.name.into(), - opType: node.opType.into(), - input: node.input.into_iter().map(|s| s.into()).collect(), - } +pub fn fsgs_bin( + path: &str, + min_inner_support: usize, + min_vertices: usize, + max_vertices: usize, +) -> Result> { + let model = parse_bin(path)?; + + let mut context = get_context(&model); + if !context.is_available() { + return Ok(vec![]); } + let graph = Graph::from_model_graph(&model, &mut context, true); + + let gspan = GSpan::new(vec![graph], 1, min_inner_support, min_vertices, max_vertices, true); + + let (_, result) = gspan.run(); + + Ok(result.get_result(&context)) } -pub fn fsgs_bin( - path: &str, +pub fn fsgs_model( + model: &Model, min_inner_support: usize, min_vertices: usize, max_vertices: usize, ) -> Result> { - let raw = parse_bin(path)?; - let model_graph = ModelGraph::from(raw); + let mut context = get_context(model); + if !context.is_available() { + return Ok(vec![]); + } - let graph = Graph::from_model_graph(model_graph, true); + let graph = Graph::from_model_graph(model, &mut context, true); let gspan = GSpan::new(vec![graph], 1, min_inner_support, min_vertices, max_vertices, true); let (_, result) = gspan.run(); - Ok(result.get_result()) + Ok(result.get_result(&context)) } diff --git a/plugins/mindstudio-insight-plugins/ModelVis/rust/fsg/src/main.rs b/plugins/mindstudio-insight-plugins/ModelVis/rust/fsg/src/main.rs new file mode 100644 index 0000000000000000000000000000000000000000..24c36d648707d562723318157b95998612cdcb76 --- /dev/null +++ b/plugins/mindstudio-insight-plugins/ModelVis/rust/fsg/src/main.rs @@ -0,0 +1,16 @@ +use std::env; + +use fsg::{fsgs_bin}; + +fn main() { + // 获取当前工作目录 + let current_dir = env::current_dir().expect("Failed to get current directory"); + let filename = current_dir.join(r#"rust\fsg\tests\pbtxt\subgraph.pbtxt"#); + let path = filename.to_str().expect("Failed to convert path to string"); + match fsgs_bin(path, 2, 2, 7) { + Ok(fsgs) => { + println!("{}", fsgs.len()); + } + Err(err) => panic!("Error occurred while parsing ONNX model: {}", err), + } +}