diff --git a/axiom-profiler-GUI/src/configuration/data.rs b/axiom-profiler-GUI/src/configuration/data.rs
index ff7e02aa..bdd3e8d3 100644
--- a/axiom-profiler-GUI/src/configuration/data.rs
+++ b/axiom-profiler-GUI/src/configuration/data.rs
@@ -2,7 +2,7 @@ use fxhash::FxHashMap;
use smt_log_parser::{
display_with::{DisplayConfiguration, SymbolReplacement},
formatter::TermDisplayContext,
- NonMaxU32,
+ F64Ord, NonMaxU32,
};
use crate::screen::homepage::FileInfo;
@@ -47,6 +47,7 @@ impl ConfigurationProvider {
pub struct Configuration {
pub display: DisplayConfiguration,
pub term_display: TermDisplayContextFiles,
+ pub avg_weighing: F64Ord,
}
impl Configuration {
pub const fn default_display() -> DisplayConfiguration {
@@ -69,6 +70,7 @@ impl Default for Configuration {
Self {
display: Self::default_display(),
term_display: TermDisplayContextFiles::default(),
+ avg_weighing: F64Ord(1.0),
}
}
}
diff --git a/axiom-profiler-GUI/src/configuration/page.rs b/axiom-profiler-GUI/src/configuration/page.rs
index 1c1891c3..944fff79 100644
--- a/axiom-profiler-GUI/src/configuration/page.rs
+++ b/axiom-profiler-GUI/src/configuration/page.rs
@@ -1,6 +1,6 @@
use std::rc::Rc;
-use smt_log_parser::{display_with::SymbolReplacement, NonMaxU32};
+use smt_log_parser::{display_with::SymbolReplacement, F64Ord, NonMaxU32};
use wasm_bindgen::JsCast;
use yew::{
function_component, use_context, use_effect_with_deps, Callback, Event, Html, Properties,
@@ -129,6 +129,19 @@ pub fn Flags(props: &FlagsProps) -> Html {
);
use_effect_with_deps(move |deps| effect(deps), deps);
+ let (summary_weighing, effect, deps) = flag_widget!(
+ cfg,
+ default,
+ avg_weighing,
+ "Average weighing",
+ "When sorting by average, how much weight should be given to the total count. Currently only affects quantifier sorting on the summary screen. A weight of 0% means sorting exactly by the average, while N% means that anything with < N% of the total will be heavily down-ranked.", |
+ if F64Ord(0.0) => "0%",
+ if F64Ord(1.0) => "1%",
+ if F64Ord(10.0) => "10%",
+ if F64Ord(100.0) => "100%",
+ );
+ use_effect_with_deps(move |deps| effect(deps), deps);
+
yew::html! {
{"Configuration flags"}
@@ -136,6 +149,7 @@ pub fn Flags(props: &FlagsProps) -> Html {
{debug}
{replace_symbols}
{ast_depth_limit}
+ {summary_weighing}
}
diff --git a/axiom-profiler-GUI/src/screen/file/summary.rs b/axiom-profiler-GUI/src/screen/file/summary.rs
index 6570d731..3e5dc091 100644
--- a/axiom-profiler-GUI/src/screen/file/summary.rs
+++ b/axiom-profiler-GUI/src/screen/file/summary.rs
@@ -52,6 +52,7 @@ pub fn Summary(props: &SummaryProps) -> Html {
analysis: props.analysis.clone(),
term_display: term_display.clone(),
config: cfg.config.display,
+ avg_weighing: cfg.config.avg_weighing.0,
};
let graph = props.analysis.clone().map(|analysis| {
@@ -68,6 +69,7 @@ pub fn Summary(props: &SummaryProps) -> Html {
+
@@ -82,6 +84,7 @@ pub struct SummaryPropsInner {
pub analysis: Option,
pub term_display: Rc,
pub config: DisplayConfiguration,
+ pub avg_weighing: f64,
}
impl SummaryPropsInner {
@@ -138,13 +141,13 @@ pub fn MostQuants(props: &SummaryPropsInner) -> Html {
let summary = &props.parser.summary;
let colours = &props.parser.colour_map;
- let quants = summary.log_info.quants_iter();
- let quants = quants_ordered::<_, true>(&parser, colours, quants);
+ let quants = summary.log_info.quants_iter().map(|(q, c)| (q, (), c));
+ let quants = quants_ordered::<(), _, true>(&parser, colours, quants);
let quants = quants
.iter()
.take(DISPLAY_TOP_N)
.take_while(|(.., c)| *c > 0);
- let quants = quants.map(|(q, hue, c)| {
+ let quants = quants.map(|(q, hue, (), c)| {
let left = format_to_html(*c);
let right = html! { { format!("{q}") }
};
(left, right)
@@ -158,24 +161,63 @@ pub fn MostQuants(props: &SummaryPropsInner) -> Html {
#[function_component]
pub fn CostQuants(props: &SummaryPropsInner) -> Html {
props.analysis.as_ref().map(|analysis| {
+ let log_info = &props.parser.summary.log_info;
let parser = props.parser.parser.borrow();
let analysis = analysis.borrow();
let colours = &props.parser.colour_map;
+ let offset = log_info.match_.quantifiers as f64 * props.avg_weighing / 100.;
- let costs = analysis.quants.quants_costs().map(|(q, c)| (q, F64Ord(c)));
- let costs = quants_ordered::<_, true>(&parser, colours, costs);
+ let costs = analysis.quants.quants_costs().map(|(q, c)| {
+ let qis = log_info.quant_insts(q);
+ if qis == 0 {
+ (q, 0.0, F64Ord(0.0))
+ } else {
+ (q, c / qis as f64, F64Ord(c / (qis as f64 + offset)))
+ }
+ });
+ let costs = quants_ordered::<_, _, true>(&parser, colours, costs);
let costs = costs.iter().take(DISPLAY_TOP_N).take_while(|(.., c)| c.0 > 0.0);
- let costs = costs.map(|(q, hue, c)| {
- let left = format_to_html(c.0 as u64);
+ let costs = costs.map(|(q, hue, c, _)| {
+ let left = html!{{ format!("{c:.1}") }};
let right = html! { { format!("{q}") }
};
(left, right)
}).collect::>();
- html! {
+ html! {
}
}).unwrap_or_default()
}
+#[function_component]
+pub fn MultQuants(props: &SummaryPropsInner) -> Html {
+ props.analysis.as_ref().map(|analysis| {
+ let log_info = &props.parser.summary.log_info;
+ let parser = props.parser.parser.borrow();
+ let analysis = analysis.borrow();
+ let colours = &props.parser.colour_map;
+ let offset = log_info.match_.quantifiers as f64 * props.avg_weighing / 100.;
+
+ let mults = analysis.quants.quants_children().map(|(q, c)| {
+ let qis = log_info.quant_insts(q);
+ if qis == 0 {
+ (q, 0.0, F64Ord(0.0))
+ } else {
+ (q, c / qis as f64, F64Ord(c / (qis as f64 + offset)))
+ }
+ });
+ let mults = quants_ordered::<_, _, true>(&parser, colours, mults);
+ let mults = mults.iter().take(DISPLAY_TOP_N).take_while(|(.., c)| c.0 > 0.0);
+ let mults = mults.map(|(q, hue, c, _)| {
+ let left = html!{{ format!("{c:.1}") }};
+ let right = html! { { format!("{q}") }
};
+ (left, right)
+ }).collect::>();
+ html! {
+
+ }
+ }).unwrap_or_default()
+}
+
#[function_component]
pub fn CostLemmas(props: &SummaryPropsInner) -> Html {
props.analysis.as_ref().map(|analysis| {
@@ -213,17 +255,17 @@ fn format_to_html(f: F) -> Html {
html! {{ f.to_formatted_string(&Locale::en) }}
}
-fn quants_ordered<'a, T: Ord + Copy + Debug, const REVERSE: bool>(
+fn quants_ordered<'a, D, T: Ord + Copy + Debug, const REVERSE: bool>(
parser: &'a Z3Parser,
colour_map: &QuantIdxToColourMap,
- quants: impl Iterator- ,
-) -> Vec<(Cow<'a, str>, Option, T)> {
+ quants: impl Iterator
- ,
+) -> Vec<(Cow<'a, str>, Option, D, T)> {
let mut quants = quants
- .filter_map(|(q, c)| {
+ .filter_map(|(q, d, c)| {
let name = parser[q].kind.name(&parser.strings)?;
let hue = colour_map.get_rbg_hue(Some(q));
// log::info!("{name}: {hue:?} | {c:?}");
- Some((name, hue, c))
+ Some((name, hue, d, c))
})
.collect::>();
if REVERSE {
diff --git a/axiom-profiler-GUI/src/screen/inst_graph/filter/add_filter.rs b/axiom-profiler-GUI/src/screen/inst_graph/filter/add_filter.rs
index 7f15ac06..044206be 100644
--- a/axiom-profiler-GUI/src/screen/inst_graph/filter/add_filter.rs
+++ b/axiom-profiler-GUI/src/screen/inst_graph/filter/add_filter.rs
@@ -116,7 +116,7 @@ impl AddFilter<'_> {
mk_filter(
&nodes,
|&(n, _, _)| {
- raw.neighbors_directed(n, Direction::Outgoing)
+ raw.neighbors_directed(n, Direction::Outgoing, &self.graph.analysis.reach)
.count_hidden()
> 0
},
@@ -125,7 +125,7 @@ impl AddFilter<'_> {
mk_filter(
&nodes,
|&(n, _, _)| {
- raw.neighbors_directed(n, Direction::Incoming)
+ raw.neighbors_directed(n, Direction::Incoming, &self.graph.analysis.reach)
.count_hidden()
> 0
},
diff --git a/axiom-profiler-GUI/src/screen/inst_graph/filter/apply.rs b/axiom-profiler-GUI/src/screen/inst_graph/filter/apply.rs
index 5876f256..03c22e26 100644
--- a/axiom-profiler-GUI/src/screen/inst_graph/filter/apply.rs
+++ b/axiom-profiler-GUI/src/screen/inst_graph/filter/apply.rs
@@ -51,7 +51,10 @@ impl Filter {
}
MaxBranching(n) => graph.keep_first_n_children(n),
ShowNeighbours(nidx, direction) => {
- let nodes: Vec<_> = graph.raw.neighbors_directed(nidx, direction).collect();
+ let nodes: Vec<_> = graph
+ .raw
+ .neighbors_directed(nidx, direction, &graph.analysis.reach)
+ .collect();
let modified = graph.raw.set_visibility_many(false, nodes.iter().copied());
select = Some(nodes);
modified
diff --git a/smt-log-parser/src/analysis/dependencies.rs b/smt-log-parser/src/analysis/dependencies.rs
index 1a813818..f0e5d714 100644
--- a/smt-log-parser/src/analysis/dependencies.rs
+++ b/smt-log-parser/src/analysis/dependencies.rs
@@ -17,6 +17,9 @@ pub struct QuantPatInfo {
/// How much total cost did this quantifier + pattern accrue from individual
/// instantiations.
pub costs: f64,
+ /// How many other instantiations of other quantifiers is this quantifier
+ /// _directly_ responsible for.
+ pub children: f64,
/// How many times does an instantiation of this quantifier depend on an
/// instantiation of the other quantifier.
pub direct_deps: Vec,
@@ -49,6 +52,16 @@ impl QuantifierAnalysis {
let ginst = &inst_graph.raw[data.iidx];
qinfo.costs += ginst.cost;
+ for &child in ginst.children.insts.iter() {
+ let cq = parser.get_inst(child).match_.kind.quant_idx();
+ if cq.is_some_and(|q| q == qpat.quant) {
+ // Skip self references.
+ continue;
+ }
+ let parents = inst_graph.raw[child].parents.insts.len() as f64;
+ qinfo.children += 1.0 / parents;
+ }
+
let pat = parser.get_pattern(qpat);
let subpats = pat.map(|p| parser[p].child_ids.len()).unwrap_or_default();
for (i, blame) in data.match_.pattern_matches().enumerate() {
@@ -97,6 +110,13 @@ impl QuantifierAnalysis {
.map(|(quant, data)| (quant, data.iter_enumerated().map(|(_, d)| d.costs).sum()))
}
+ pub fn quants_children(&self) -> impl Iterator
- + '_ {
+ self.0
+ .0
+ .iter_enumerated()
+ .map(|(quant, data)| (quant, data.iter_enumerated().map(|(_, d)| d.children).sum()))
+ }
+
pub fn calculate_transitive(&self, mut steps: Option) -> TransQuantAnalaysis {
let mut initial: TiVec =
(0..self.0 .0.len()).map(|_| FxHashSet::default()).collect();
diff --git a/smt-log-parser/src/analysis/graph/analysis/mod.rs b/smt-log-parser/src/analysis/graph/analysis/mod.rs
index 4453ff24..bd1a8852 100644
--- a/smt-log-parser/src/analysis/graph/analysis/mod.rs
+++ b/smt-log-parser/src/analysis/graph/analysis/mod.rs
@@ -14,13 +14,14 @@ use mem_dbg::{MemDbg, MemSize};
use matching_loop::MlData;
-use crate::{F64Ord, Result, Z3Parser};
+use crate::{F64Ord, Result, TiVec, Z3Parser};
use self::{
cost::{DefaultCost, ProofCost},
depth::DefaultDepth,
next_nodes::NextInstsInit,
proof::ProofInitialiser,
+ reconnect::{BwdReachableAnalysis, ReachNonDisabled},
};
use super::{raw::RawInstGraph, InstGraph, RawNodeIndex};
@@ -28,6 +29,7 @@ use super::{raw::RawInstGraph, InstGraph, RawNodeIndex};
#[cfg_attr(feature = "mem_dbg", derive(MemSize, MemDbg))]
#[derive(Debug, Default)]
pub struct Analysis {
+ pub reach: TiVec,
// Highest to lowest
pub cost: OrderingAnalysis,
// Most to least
@@ -89,6 +91,7 @@ impl Analysis {
// Alloc `fwd_depth_min` vector
let fwd_depth_min = cost.duplicate()?;
Ok(Self {
+ reach: Default::default(),
cost,
children,
fwd_depth_min,
@@ -107,6 +110,9 @@ impl InstGraph {
}
pub fn initialise_default(&mut self, parser: &Z3Parser) {
+ let mut reach = BwdReachableAnalysis::::default();
+ self.analysis.reach = self.topo_analysis(&mut reach);
+
self.initialise_transfer(DefaultCost, parser);
self.initialise_transfer(ProofCost, parser);
self.initialise_collect(DefaultDepth::, parser);
diff --git a/smt-log-parser/src/analysis/graph/analysis/reconnect.rs b/smt-log-parser/src/analysis/graph/analysis/reconnect.rs
index 28561e83..6a76f64a 100644
--- a/smt-log-parser/src/analysis/graph/analysis/reconnect.rs
+++ b/smt-log-parser/src/analysis/graph/analysis/reconnect.rs
@@ -1,5 +1,8 @@
use std::collections::hash_map::Entry;
+#[cfg(feature = "mem_dbg")]
+use mem_dbg::{MemDbg, MemSize};
+
use fxhash::FxHashSet;
use crate::{
@@ -9,10 +12,52 @@ use crate::{
use super::run::TopoAnalysis;
-pub struct BwdReachableVisAnalysis;
+pub trait ReachKind: Copy + core::fmt::Debug + From + Into {
+ fn current(node: &Node) -> Self;
+ fn value(self) -> bool {
+ self.into()
+ }
+}
+
+macro_rules! reach_kind {
+ ($name:ident($node:ident => $e:expr)) => {
+ #[cfg_attr(feature = "mem_dbg", derive(MemSize, MemDbg))]
+ #[cfg_attr(feature = "mem_dbg", copy_type)]
+ #[derive(Debug, Clone, Copy)]
+ pub struct $name(bool);
+ impl ReachKind for $name {
+ fn current($node: &Node) -> Self {
+ Self($e)
+ }
+ }
+ impl From for $name {
+ fn from(b: bool) -> Self {
+ Self(b)
+ }
+ }
+ impl From<$name> for bool {
+ fn from(b: $name) -> bool {
+ b.0
+ }
+ }
+ };
+}
+
+reach_kind!(ReachVisible(node => node.visible()));
+reach_kind!(ReachNonDisabled(node => !node.disabled()));
-impl TopoAnalysis for BwdReachableVisAnalysis {
- type Value = bool;
+/// If `VIS` is true, then it checks if a visible node is reachable from this
+/// one, otherwise it checks if any non-disabled node is reachable.
+#[derive(Clone, Copy)]
+pub struct BwdReachableAnalysis(core::marker::PhantomData);
+impl Default for BwdReachableAnalysis {
+ fn default() -> Self {
+ Self(Default::default())
+ }
+}
+
+impl TopoAnalysis for BwdReachableAnalysis {
+ type Value = Kind;
fn collect<'a, 'n, T: Iterator
- >(
&mut self,
@@ -24,11 +69,9 @@ impl TopoAnalysis for BwdReachableVisAnalysis {
where
Self::Value: 'n,
{
- if node.visible() {
- true
- } else {
- from_all().any(|(_, &b)| b)
- }
+ let curr = Kind::current(node).value();
+ let reach = curr || from_all().any(|(_, &b)| b.value());
+ reach.into()
}
}
@@ -42,7 +85,7 @@ impl TopoAnalysis for BwdReachableVisAnalysis {
///
/// The `to` is implicit in the index which we used to reach the
/// `TopoAnalysis::Value`.
-pub struct ReconnectAnalysis(pub TiVec);
+pub struct ReconnectAnalysis(pub TiVec);
#[derive(Debug, Default)]
pub struct ReconnectData {
@@ -164,7 +207,7 @@ impl TopoAnalysis for ReconnectAnalysis {
Self::Value: 'n,
{
let mut data = Self::Value::default();
- if !self.0[cidx] {
+ if !self.0[cidx].value() {
return data;
}
diff --git a/smt-log-parser/src/analysis/graph/analysis/run.rs b/smt-log-parser/src/analysis/graph/analysis/run.rs
index 4cc26a33..07d3b78b 100644
--- a/smt-log-parser/src/analysis/graph/analysis/run.rs
+++ b/smt-log-parser/src/analysis/graph/analysis/run.rs
@@ -10,6 +10,8 @@ use crate::{
TiVec, Z3Parser,
};
+use super::reconnect::ReachNonDisabled;
+
// FIXME: `ID` makes the implementations unique, but is not a great solution.
/// FORWARD: Do a forward or reverse topological walk?
pub trait Initialiser {
@@ -75,9 +77,10 @@ impl RawInstGraph {
&self,
curr: RawNodeIndex,
dir: Direction,
+ reach: &TiVec,
) -> impl Iterator
- + '_ {
if SKIP_DISABLED {
- either::Either::Left(self.neighbors_directed(curr, dir))
+ either::Either::Left(self.neighbors_directed(curr, dir, reach))
} else {
either::Either::Right(self.graph.neighbors_directed(curr.0, dir).map(RawNodeIndex))
}
@@ -119,7 +122,7 @@ impl InstGraph {
} else {
let from_all = || {
self.raw
- .neighbors_directed_::(curr, dir)
+ .neighbors_directed_::(curr, dir, &self.analysis.reach)
.map(|i| {
let data = &data[i];
// Safety: The data is initialised as the graph is a DAG
@@ -175,7 +178,11 @@ impl InstGraph {
let for_each = |idx: RawNodeIndex| {
let from_all = || {
self.raw
- .neighbors_directed_::(idx, I::direction())
+ .neighbors_directed_::(
+ idx,
+ I::direction(),
+ &self.analysis.reach,
+ )
.map(|i| &self.raw[i])
};
let value = initialiser.collect(&self.raw.graph[idx.0], from_all);
@@ -209,11 +216,14 @@ impl InstGraph {
let for_each = |idx: RawNodeIndex| {
let incoming: Vec<_> = self
.raw
- .neighbors_directed(idx, I::direction())
+ .neighbors_directed(idx, I::direction(), &self.analysis.reach)
.map(|i| initialiser.observe(&self.raw[i], parser))
.collect();
let mut i = 0;
- let mut neighbors = self.raw.neighbors_directed(idx, I::direction()).detach();
+ let mut neighbors = self
+ .raw
+ .neighbors_directed(idx, I::direction(), &self.analysis.reach)
+ .detach();
while let Some(neighbor) = neighbors.next(&self.raw) {
let transfer = initialiser.transfer(&self.raw.graph[idx.0], idx, i, &incoming);
initialiser.add(&mut self.raw[neighbor], transfer);
diff --git a/smt-log-parser/src/analysis/graph/raw.rs b/smt-log-parser/src/analysis/graph/raw.rs
index 6f4ff49f..3d643922 100644
--- a/smt-log-parser/src/analysis/graph/raw.rs
+++ b/smt-log-parser/src/analysis/graph/raw.rs
@@ -18,9 +18,11 @@ use crate::{
CdclIdx, ENodeBlame, ENodeIdx, EqGivenIdx, EqTransIdx, EqualityExpl, GraphIdx, InstIdx,
ProofIdx, StackIdx, TransitiveExplSegmentKind,
},
- DiGraph, FxHashMap, FxHashSet, NonMaxU32, Result, Z3Parser,
+ DiGraph, FxHashMap, FxHashSet, NonMaxU32, Result, TiVec, Z3Parser,
};
+use super::analysis::reconnect::{ReachKind, ReachNonDisabled};
+
graph_idx!(raw_idx, RawNodeIndex, RawEdgeIndex, RawIx);
#[cfg_attr(feature = "mem_dbg", derive(MemSize, MemDbg))]
@@ -251,20 +253,34 @@ impl RawInstGraph {
/// Similar to `self.graph.neighbors` but will walk through disabled nodes.
///
/// Note: Iterating the neighbors is **not** a O(1) operation.
- pub fn neighbors(&self, node: RawNodeIndex) -> Neighbors<'_> {
- self.neighbors_directed(node, Direction::Outgoing)
+ pub fn neighbors(
+ &self,
+ node: RawNodeIndex,
+ reach: &TiVec,
+ ) -> Neighbors<'_> {
+ self.neighbors_directed(node, Direction::Outgoing, reach)
}
+
/// Similar to `self.graph.neighbors_directed` but will walk through
/// disabled nodes.
///
/// Note: Iterating the neighbors is **not** a O(1) operation.
- pub fn neighbors_directed(&self, node: RawNodeIndex, dir: Direction) -> Neighbors<'_> {
+ pub fn neighbors_directed(
+ &self,
+ node: RawNodeIndex,
+ dir: Direction,
+ reach: &TiVec,
+ ) -> Neighbors<'_> {
let direct = self.graph.neighbors_directed(node.0, dir).detach();
- let walk = WalkNeighbors {
- dir,
- visited: FxHashSet::default(),
- stack: Vec::new(),
- direct,
+ let walk = if reach.get(node).is_some_and(|v| !v.value()) {
+ WalkNeighbors::None
+ } else {
+ WalkNeighbors::Some {
+ dir,
+ visited: FxHashSet::default(),
+ stack: Vec::new(),
+ direct,
+ }
};
Neighbors { raw: self, walk }
}
@@ -706,15 +722,27 @@ impl Iterator for Neighbors<'_> {
}
#[derive(Clone)]
-pub struct WalkNeighbors {
- pub dir: Direction,
- pub visited: FxHashSet,
- pub stack: Vec,
- pub direct: petgraph::graph::WalkNeighbors,
+pub enum WalkNeighbors {
+ None,
+ Some {
+ dir: Direction,
+ visited: FxHashSet,
+ stack: Vec,
+ direct: petgraph::graph::WalkNeighbors,
+ },
}
impl WalkNeighbors {
pub fn next(&mut self, raw: &RawInstGraph) -> Option {
+ let WalkNeighbors::Some {
+ dir,
+ visited,
+ stack,
+ direct,
+ } = self
+ else {
+ return None;
+ };
// TODO: decide if we want to prevent direct neighbors from being
// visited multiple times if there are multiple direct edges.
loop {
@@ -727,22 +755,17 @@ impl WalkNeighbors {
// }
// }
// let idx = idx.or_else(|| self.stack.pop())?;
- let idx = self
- .direct
+ let idx = direct
.next(&raw.graph)
.map(|(_, n)| RawNodeIndex(n))
- .or_else(|| self.stack.pop())?;
+ .or_else(|| stack.pop())?;
let node = &raw[idx];
if !node.disabled() {
return Some(idx);
}
- for n in raw
- .graph
- .neighbors_directed(idx.0, self.dir)
- .map(RawNodeIndex)
- {
- if self.visited.insert(n) {
- self.stack.push(n);
+ for n in raw.graph.neighbors_directed(idx.0, *dir).map(RawNodeIndex) {
+ if visited.insert(n) {
+ stack.push(n);
}
}
}
diff --git a/smt-log-parser/src/analysis/graph/visible.rs b/smt-log-parser/src/analysis/graph/visible.rs
index 916c8094..b9271cd9 100644
--- a/smt-log-parser/src/analysis/graph/visible.rs
+++ b/smt-log-parser/src/analysis/graph/visible.rs
@@ -14,7 +14,7 @@ use crate::{
};
use super::{
- analysis::reconnect::{BwdReachableVisAnalysis, ReconnectAnalysis},
+ analysis::reconnect::{BwdReachableAnalysis, ReachVisible, ReconnectAnalysis},
raw::{EdgeKind, NodeKind},
InstGraph, RawEdgeIndex, RawNodeIndex,
};
@@ -30,7 +30,8 @@ pub struct VisibleInstGraph {
impl InstGraph {
pub fn to_visible(&self) -> VisibleInstGraph {
- let bwd_vis_reachable = self.topo_analysis(&mut BwdReachableVisAnalysis);
+ let mut reach = BwdReachableAnalysis::::default();
+ let bwd_vis_reachable = self.topo_analysis(&mut reach);
let mut reconnect = self.topo_analysis(&mut ReconnectAnalysis(bwd_vis_reachable));
let (mut nodes, mut edges) = (0, 0);
for (idx, data) in reconnect.iter_mut_enumerated() {
@@ -49,8 +50,14 @@ impl InstGraph {
if !self.raw[idx].visible() {
continue;
}
- let hidden_parents = self.raw.neighbors_directed(idx, Incoming).count_hidden();
- let hidden_children = self.raw.neighbors_directed(idx, Outgoing).count_hidden();
+ let hidden_parents = self
+ .raw
+ .neighbors_directed(idx, Incoming, &self.analysis.reach)
+ .count_hidden();
+ let hidden_children = self
+ .raw
+ .neighbors_directed(idx, Outgoing, &self.analysis.reach)
+ .count_hidden();
let v_node = VisibleNode {
idx,
hidden_parents: hidden_parents as u32,
diff --git a/smt-log-parser/src/analysis/misc.rs b/smt-log-parser/src/analysis/misc.rs
index b3f9eb4d..0c216cf8 100644
--- a/smt-log-parser/src/analysis/misc.rs
+++ b/smt-log-parser/src/analysis/misc.rs
@@ -105,4 +105,11 @@ impl LogInfo {
.iter_enumerated()
.map(|(i, count)| (i, count.iter_enumerated().map(|(_, c)| c).sum()))
}
+
+ pub fn quant_insts(&self, qidx: QuantIdx) -> usize {
+ self.quants.0 .0[qidx]
+ .iter_enumerated()
+ .map(|(_, c)| *c)
+ .sum()
+ }
}
diff --git a/smt-log-parser/src/util.rs b/smt-log-parser/src/util.rs
index a42c7523..8010c47f 100644
--- a/smt-log-parser/src/util.rs
+++ b/smt-log-parser/src/util.rs
@@ -1,5 +1,11 @@
-#[derive(Debug, Clone, Copy, PartialEq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+#[derive(Debug, Clone, Copy)]
pub struct F64Ord(pub f64);
+impl std::cmp::PartialEq for F64Ord {
+ fn eq(&self, other: &Self) -> bool {
+ self.0.total_cmp(&other.0).is_eq()
+ }
+}
impl std::cmp::Eq for F64Ord {}
impl std::cmp::PartialOrd for F64Ord {
fn partial_cmp(&self, other: &Self) -> Option {