+ {if f { props.expanded.clone() } else { props.collapsed.clone() }}
+
}
+}
diff --git a/axiom-profiler-GUI/src/screen/graphviz.rs b/axiom-profiler-GUI/src/screen/graphviz.rs
index b4f46695..a6252460 100644
--- a/axiom-profiler-GUI/src/screen/graphviz.rs
+++ b/axiom-profiler-GUI/src/screen/graphviz.rs
@@ -180,8 +180,8 @@ impl
match *self {
Instantiation(inst) => match &parser[parser[inst].match_].kind {
MatchKind::TheorySolving { axiom_id, .. } => {
- let namespace = &parser[axiom_id.namespace];
- let id = axiom_id.id.map(|id| format!("[{id}]")).unwrap_or_default();
+ let (namespace, id) = axiom_id.to_string_components(&parser.strings);
+ let id = id.map(|id| format!("[{id}]")).unwrap_or_default();
format!("{namespace}{id}")
}
MatchKind::MBQI { quant, .. }
diff --git a/axiom-profiler-GUI/src/screen/inst_graph/display/node_info.rs b/axiom-profiler-GUI/src/screen/inst_graph/display/node_info.rs
index 2b9d0ed1..ba7f88db 100644
--- a/axiom-profiler-GUI/src/screen/inst_graph/display/node_info.rs
+++ b/axiom-profiler-GUI/src/screen/inst_graph/display/node_info.rs
@@ -232,7 +232,7 @@ impl<'a, 'b> NodeInfo<'a, 'b> {
.node
.kind()
.inst()
- .and_then(|i| self.ctxt.parser[i].z3_generation)
+ .and_then(|i| self.ctxt.parser[i].kind.z3_generation())
{
extra_info.push(("z3 gen", z3gen.to_string()));
}
@@ -405,6 +405,7 @@ impl<'a, 'b> EdgeInfo<'a, 'b> {
use VisibleEdgeKind::*;
match self.kind {
Direct(_, EdgeKind::Yield) => "Yield".to_string(),
+ Direct(_, EdgeKind::Asserted) => "Asserted".to_string(),
Direct(_, EdgeKind::Blame { pattern_term }) => {
format!("Blame pattern #{pattern_term}")
}
diff --git a/axiom-profiler-GUI/src/screen/inst_graph/mode.rs b/axiom-profiler-GUI/src/screen/inst_graph/mode.rs
index 20808bf2..f9fbd331 100644
--- a/axiom-profiler-GUI/src/screen/inst_graph/mode.rs
+++ b/axiom-profiler-GUI/src/screen/inst_graph/mode.rs
@@ -25,7 +25,7 @@ impl GraphMode {
true
}
(Self::Inst, _) => false,
- (Self::Proof, Instantiation(..) | Proof(..)) => true,
+ (Self::Proof, Instantiation(..) | ENode(..) | Proof(..)) => true,
(Self::Proof, _) => false,
(Self::Cdcl, Cdcl(..)) => true,
(Self::Cdcl, _) => false,
diff --git a/axiom-profiler-GUI/src/utils/tab.rs b/axiom-profiler-GUI/src/utils/tab.rs
index 021dbfcb..e7a97fe2 100644
--- a/axiom-profiler-GUI/src/utils/tab.rs
+++ b/axiom-profiler-GUI/src/utils/tab.rs
@@ -58,9 +58,9 @@ pub struct DetailContainerProps {
#[function_component]
pub fn DetailContainer(props: &DetailContainerProps) -> Html {
- html! {
+ html! {
{props.children.clone()}
-
}
+
}
}
// Tree
diff --git a/smt-log-parser/src/analysis/dependencies.rs b/smt-log-parser/src/analysis/dependencies.rs
index 1f03cf49..1a813818 100644
--- a/smt-log-parser/src/analysis/dependencies.rs
+++ b/smt-log-parser/src/analysis/dependencies.rs
@@ -65,7 +65,7 @@ impl QuantifierAnalysis {
}
let direct_dep = &mut qinfo.direct_deps[i];
- let created_by = parser[blame.enode()].created_by;
+ let created_by = parser[blame.enode()].blame.inst();
let created_by =
created_by.and_then(|iidx| parser.get_inst(iidx).match_.kind.quant_idx());
*direct_dep.enode.entry(created_by).or_default() += 1;
diff --git a/smt-log-parser/src/analysis/graph/analysis/cost.rs b/smt-log-parser/src/analysis/graph/analysis/cost.rs
index 945cea21..685567d4 100644
--- a/smt-log-parser/src/analysis/graph/analysis/cost.rs
+++ b/smt-log-parser/src/analysis/graph/analysis/cost.rs
@@ -89,16 +89,16 @@ impl CostInitialiser for DefaultCost {
}
fn transfer(
&mut self,
- node: &Node,
+ child: &Node,
_from_idx: RawNodeIndex,
- idx: usize,
- incoming: &[Self::Observed],
+ parent_idx: usize,
+ parents: &[Self::Observed],
) -> f64 {
- let total = incoming.iter().sum::();
- if total == 0 {
+ let total = parents.iter().sum::();
+ if total == 0 || child.kind().proof().is_some() {
return 0.0;
}
- node.cost * incoming[idx] as f64 / total as f64
+ child.cost * parents[parent_idx] as f64 / total as f64
}
}
@@ -127,17 +127,17 @@ impl CostInitialiser for ProofCost {
&mut self,
node: &Node,
_from_idx: RawNodeIndex,
- idx: usize,
- incoming: &[Self::Observed],
+ child_idx: usize,
+ children: &[Self::Observed],
) -> f64 {
if node.kind().proof().is_none() {
return 0.0;
}
- let total = incoming.iter().sum::();
+ let total = children.iter().sum::();
if total == 0 {
return 0.0;
}
- node.cost * incoming[idx] as f64 / total as f64
+ node.cost * children[child_idx] as f64 / total as f64
}
}
diff --git a/smt-log-parser/src/analysis/graph/analysis/matching_loop/explain.rs b/smt-log-parser/src/analysis/graph/analysis/matching_loop/explain.rs
index e16205c7..f87834bb 100644
--- a/smt-log-parser/src/analysis/graph/analysis/matching_loop/explain.rs
+++ b/smt-log-parser/src/analysis/graph/analysis/matching_loop/explain.rs
@@ -334,7 +334,7 @@ impl MlExplainer {
fn add_enode(&mut self, parser: &Z3Parser, enode: ENodeIdx, result_enode: NodeIndex) -> bool {
let enode_data = &parser[enode];
- let created_by = enode_data.created_by;
+ let created_by = enode_data.blame.inst();
let created_by = created_by.and_then(|cb| self.instantiations.get(&cb));
if let Some(created_by) = created_by {
self.graph
@@ -375,7 +375,7 @@ impl MlExplainer {
let eq_expl = &self.equalities().given[eq];
match eq_expl {
&EqualityExpl::Literal { eq, .. } => {
- let created_by = self.parser[eq].created_by;
+ let created_by = self.parser[eq].blame.inst();
let created_by =
created_by.and_then(|iidx| self.explainer.instantiations.get(&iidx));
if let Some(created_by) = created_by {
diff --git a/smt-log-parser/src/analysis/graph/analysis/matching_loop/signature.rs b/smt-log-parser/src/analysis/graph/analysis/matching_loop/signature.rs
index c3b814c3..ddbaf524 100644
--- a/smt-log-parser/src/analysis/graph/analysis/matching_loop/signature.rs
+++ b/smt-log-parser/src/analysis/graph/analysis/matching_loop/signature.rs
@@ -52,7 +52,7 @@ impl MlSignature {
let eq_len = blame.equalities().count();
let blame = blame.enode();
let eblame = &parser[blame];
- let Some(created_by) = eblame.created_by else {
+ let Some(created_by) = eblame.blame.inst() else {
return (InstParent::Const(blame), eq_len);
};
match parser[parser[created_by].match_].kind.quant_idx() {
diff --git a/smt-log-parser/src/analysis/graph/raw.rs b/smt-log-parser/src/analysis/graph/raw.rs
index 98b6f4a2..6f4ff49f 100644
--- a/smt-log-parser/src/analysis/graph/raw.rs
+++ b/smt-log-parser/src/analysis/graph/raw.rs
@@ -15,8 +15,8 @@ use petgraph::{
use crate::{
graph_idx,
items::{
- CdclIdx, ENodeIdx, EqGivenIdx, EqTransIdx, EqualityExpl, GraphIdx, InstIdx, ProofIdx,
- StackIdx, TransitiveExplSegmentKind,
+ CdclIdx, ENodeBlame, ENodeIdx, EqGivenIdx, EqTransIdx, EqualityExpl, GraphIdx, InstIdx,
+ ProofIdx, StackIdx, TransitiveExplSegmentKind,
},
DiGraph, FxHashMap, FxHashSet, NonMaxU32, Result, Z3Parser,
};
@@ -101,11 +101,8 @@ impl RawInstGraph {
stats,
};
- // Add instantiation blamed and yield edges
+ // Add instantiation blamed edges
for (idx, inst) in parser.insts.insts.iter_enumerated() {
- for yields in inst.yields_terms.iter() {
- self_.add_edge(idx, *yields, EdgeKind::Yield);
- }
for (i, blame) in parser.insts.matches[inst.match_]
.pattern_matches()
.enumerate()
@@ -125,6 +122,15 @@ impl RawInstGraph {
}
}
+ // Add enode blamed edges
+ for (idx, enode) in parser.egraph.enodes.iter_enumerated() {
+ match enode.blame {
+ ENodeBlame::Inst(iidx) => self_.add_edge(iidx, idx, EdgeKind::Asserted),
+ ENodeBlame::Proof(pidx) => self_.add_edge(pidx, idx, EdgeKind::Yield),
+ ENodeBlame::BoolConst | ENodeBlame::Unknown => (),
+ }
+ }
+
// Add given equality created edges
for (idx, eq) in parser.egraph.equalities.given.iter_enumerated() {
match eq {
@@ -571,6 +577,8 @@ impl NodeKind {
pub enum EdgeKind {
/// Instantiation -> ENode
Yield,
+ /// Proof (asserted) -> ENode
+ Asserted,
/// ENode -> Instantiation
Blame { pattern_term: u16 },
/// TransEquality -> Instantiation
diff --git a/smt-log-parser/src/analysis/proofs.rs b/smt-log-parser/src/analysis/proofs.rs
index ebc1474e..88c7d0fd 100644
--- a/smt-log-parser/src/analysis/proofs.rs
+++ b/smt-log-parser/src/analysis/proofs.rs
@@ -1,36 +1,26 @@
use std::cmp::Reverse;
-use crate::{items::ProofIdx, F64Ord, FxHashMap, Z3Parser};
+use crate::{items::TermIdx, F64Ord, FxHashMap, Z3Parser};
use super::InstGraph;
pub struct ProofAnalysis {
- /// The cost approximation that it took to disprove the hypothesis (may have
- /// been disproved in conjunction with other hypotheses).
- pub hypothesis_cost: Vec<(ProofIdx, f64)>,
+ /// The cost approximation that it took to prove each lemma (by
+ /// contradiction).
+ pub lemmas_cost: Vec<(TermIdx, f64)>,
}
impl ProofAnalysis {
pub fn new(parser: &Z3Parser, graph: &InstGraph) -> Self {
- let mut hypothesis = FxHashMap::<_, f64>::default();
- for (idx, _) in parser.proofs().iter_enumerated() {
- let node = &graph.raw[idx];
- if !node.proof.proves_false() {
+ let mut lemmas = FxHashMap::<_, f64>::default();
+ for (idx, proof) in parser.proofs().iter_enumerated() {
+ if !proof.kind.is_lemma() {
continue;
}
- let cost = node.cost;
- let hypotheses = graph.raw.hypotheses(parser, idx);
- if hypotheses.is_empty() {
- // proved unsat
- continue;
- }
- let cost_div = cost / hypotheses.len() as f64;
- for h in hypotheses {
- *hypothesis.entry(h).or_default() += cost_div;
- }
+ *lemmas.entry(proof.result).or_default() += graph.raw[idx].cost;
}
- let mut hypothesis_cost = hypothesis.into_iter().collect::>();
- hypothesis_cost.sort_by_key(|&(idx, cost)| (Reverse(F64Ord(cost)), idx));
- Self { hypothesis_cost }
+ let mut lemmas_cost = lemmas.into_iter().collect::>();
+ lemmas_cost.sort_unstable_by_key(|&(lemma, cost)| (Reverse(F64Ord(cost)), lemma));
+ Self { lemmas_cost }
}
}
diff --git a/smt-log-parser/src/display_with.rs b/smt-log-parser/src/display_with.rs
index dc306213..fb7a0199 100644
--- a/smt-log-parser/src/display_with.rs
+++ b/smt-log-parser/src/display_with.rs
@@ -486,10 +486,8 @@ impl DisplayWithCtxt, ()> for &MatchKind {
quant.fmt_with(f, ctxt, data)
}
MatchKind::TheorySolving { axiom_id, .. } => {
- write!(f, "[TheorySolving] {}#", &ctxt.parser[axiom_id.namespace])?;
- if let Some(id) = axiom_id.id {
- write!(f, "{id}")?;
- }
+ write!(f, "[TheorySolving] ")?;
+ axiom_id.fmt_with(f, ctxt, data)?;
Ok(())
}
MatchKind::Axiom { axiom, .. } => {
@@ -617,9 +615,13 @@ impl<'a: 'b, 'b> DisplayWithCtxt, ()> for &'a TermId {
ctxt: &DisplayCtxt<'b>,
_data: &mut (),
) -> fmt::Result {
- let namespace = &ctxt.parser[self.namespace];
- let id = self.id.map(|id| id.to_string()).unwrap_or_default();
- write!(f, "{namespace}#{id}")
+ let (namespace, id) = self.to_string_components(&ctxt.parser.strings);
+ write!(f, "{namespace}#")?;
+ if let Some(id) = id {
+ write!(f, "{id}")
+ } else {
+ Ok(())
+ }
}
}
diff --git a/smt-log-parser/src/error.rs b/smt-log-parser/src/error.rs
index 06c6f4fa..d5601efe 100644
--- a/smt-log-parser/src/error.rs
+++ b/smt-log-parser/src/error.rs
@@ -37,7 +37,7 @@ pub enum Error {
InvalidVersion(semver::Error),
// Id parsing
- InvalidIdNumber(ParseIntError),
+ InvalidIdNumber(nonmax::ParseIntError),
InvalidIdHash(String),
UnknownId(TermId),
@@ -85,6 +85,9 @@ pub enum Error {
PopConflictMismatch,
InvalidFrameInteger(ParseIntError),
+ // Proof
+ ProvedVar(TermIdx),
+
// CDCL
NoConflict,
BoolLiteral,
diff --git a/smt-log-parser/src/items/enode.rs b/smt-log-parser/src/items/enode.rs
index 7924a1b2..5351e295 100644
--- a/smt-log-parser/src/items/enode.rs
+++ b/smt-log-parser/src/items/enode.rs
@@ -3,22 +3,44 @@ use mem_dbg::{MemDbg, MemSize};
use crate::{FxHashMap, NonMaxU32};
-use super::{ENodeIdx, EqGivenIdx, EqTransIdx, InstIdx, StackIdx, TermIdx};
+use super::{ENodeIdx, EqGivenIdx, EqTransIdx, InstIdx, ProofIdx, StackIdx, TermIdx};
#[cfg_attr(feature = "mem_dbg", derive(MemSize, MemDbg))]
#[derive(Debug)]
pub struct ENode {
pub frame: StackIdx,
- pub created_by: Option,
+ pub blame: ENodeBlame,
pub owner: TermIdx,
- pub z3_generation: Option,
+ pub z3_generation: NonMaxU32,
pub(crate) equalities: Vec,
/// This will never contain a `TransitiveExpl::to` pointing to itself. It
/// may contain `TransitiveExpl::given_len` of 0, but only when
/// `get_simple_path` fails but `can_mismatch` is true.
pub(crate) transitive: FxHashMap,
- pub(crate) self_transitive: Option,
+}
+
+#[cfg_attr(feature = "mem_dbg", derive(MemSize, MemDbg))]
+#[cfg_attr(feature = "mem_dbg", copy_type)]
+#[derive(Debug, Clone, Copy)]
+pub enum ENodeBlame {
+ /// The `ENode` was created by an instantiation.
+ Inst(InstIdx),
+ /// The `ENode` was created by a proof step.
+ Proof(ProofIdx),
+ /// The `ENode` represents either `#1` or `#2`.
+ BoolConst,
+ /// We don't know why the `ENode` was created.
+ Unknown,
+}
+
+impl ENodeBlame {
+ pub fn inst(self) -> Option {
+ match self {
+ Self::Inst(inst) => Some(inst),
+ _ => None,
+ }
+ }
}
#[cfg_attr(feature = "mem_dbg", derive(MemSize, MemDbg))]
diff --git a/smt-log-parser/src/items/inst.rs b/smt-log-parser/src/items/inst.rs
index 8029847f..087d0716 100644
--- a/smt-log-parser/src/items/inst.rs
+++ b/smt-log-parser/src/items/inst.rs
@@ -215,9 +215,8 @@ impl fmt::Display for Fingerprint {
#[derive(Debug, Clone)]
pub struct Instantiation {
pub match_: MatchIdx,
- pub fingerprint: Fingerprint,
+ pub kind: InstantiationKind,
pub proof_id: InstProofLink,
- pub z3_generation: Option,
/// The enodes that were yielded by the instantiation along with the
/// generalised terms for them (`MaybeSynthIdx::Parsed` if the yielded term
/// doesn't contain any quantified variables)
@@ -225,6 +224,34 @@ pub struct Instantiation {
pub frame: StackIdx,
}
+#[cfg_attr(feature = "mem_dbg", derive(MemSize, MemDbg))]
+#[cfg_attr(feature = "mem_dbg", copy_type)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
+#[derive(Debug, Clone, Copy)]
+pub enum InstantiationKind {
+ Axiom,
+ NonAxiom {
+ fingerprint: Fingerprint,
+ z3_generation: NonMaxU32,
+ },
+}
+
+impl InstantiationKind {
+ pub fn fingerprint(&self) -> Fingerprint {
+ match self {
+ Self::NonAxiom { fingerprint, .. } => *fingerprint,
+ _ => Fingerprint(0),
+ }
+ }
+
+ pub fn z3_generation(&self) -> Option {
+ match self {
+ Self::NonAxiom { z3_generation, .. } => Some(*z3_generation),
+ _ => None,
+ }
+ }
+}
+
/// A Z3 instantiation.
#[cfg_attr(feature = "mem_dbg", derive(MemSize, MemDbg))]
#[cfg_attr(feature = "mem_dbg", copy_type)]
diff --git a/smt-log-parser/src/items/proof.rs b/smt-log-parser/src/items/proof.rs
index 0a234a53..5700c92e 100644
--- a/smt-log-parser/src/items/proof.rs
+++ b/smt-log-parser/src/items/proof.rs
@@ -577,6 +577,10 @@ impl ProofStepKind {
pub fn is_quant_inst(self) -> bool {
matches!(self, ProofStepKind::PR_QUANT_INST)
}
+
+ pub fn is_lemma(self) -> bool {
+ matches!(self, ProofStepKind::PR_LEMMA)
+ }
}
static SEARCH_MAP: OnceLock> = OnceLock::new();
diff --git a/smt-log-parser/src/items/term.rs b/smt-log-parser/src/items/term.rs
index c2752f5a..f1e4ac97 100644
--- a/smt-log-parser/src/items/term.rs
+++ b/smt-log-parser/src/items/term.rs
@@ -58,7 +58,7 @@ impl TermKind {
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[derive(Debug, Clone, Copy, Default, Hash, PartialEq, Eq)]
pub struct TermId {
- pub namespace: IString,
+ pub namespace: Option,
pub id: Option,
}
impl TermId {
@@ -68,21 +68,29 @@ impl TermId {
pub fn parse(strings: &mut StringTable, value: &str) -> Result {
let hash_idx = value.bytes().position(|b| b == b'#');
let hash_idx = hash_idx.ok_or_else(|| Error::InvalidIdHash(value.to_string()))?;
- let namespace = IString(strings.get_or_intern(&value[..hash_idx]));
+ let namespace = (hash_idx != 0).then(|| IString(strings.get_or_intern(&value[..hash_idx])));
let id = &value[hash_idx + 1..];
let id = match id {
"" => None,
- id => Some(NonMaxU32::new(id.parse::().map_err(Error::InvalidIdNumber)?).unwrap()),
+ id => Some(id.parse::().map_err(Error::InvalidIdNumber)?),
};
Ok(Self { namespace, id })
}
pub fn order(&self) -> u32 {
self.id.map(|id| id.get() + 1).unwrap_or_default()
}
+
+ pub fn to_string_components<'a>(
+ &self,
+ strings: &'a StringTable,
+ ) -> (&'a str, Option) {
+ let namespace = self.namespace.map(|ns| &strings[*ns]).unwrap_or_default();
+ (namespace, self.id)
+ }
pub fn to_string(&self, strings: &StringTable) -> String {
- let namespace = &strings[*self.namespace];
- let id = self.id.map(|id| id.to_string()).unwrap_or_default();
- format!("{}#{}", namespace, id)
+ let (namespace, id) = self.to_string_components(strings);
+ let id = id.map(|id| id.to_string()).unwrap_or_default();
+ format!("{namespace}#{id}")
}
}
@@ -93,25 +101,27 @@ impl TermId {
#[cfg_attr(feature = "mem_dbg", derive(MemSize, MemDbg))]
#[derive(Debug)]
pub struct TermIdToIdxMap {
- empty_string: IString,
empty_namespace: Vec