ESBMC
Efficient SMT-based Context-Bounded Model Checker
Loading...
Searching...
No Matches
k_path_spanning.h
Go to the documentation of this file.
1#pragma once
2
3#include <irep2/irep2.h>
4
5#include <cstdint>
6#include <set>
7#include <string>
8#include <utility>
9#include <vector>
10
11/*
12k-path spanning-set scoring (Phase 2, see GitHub issue #4335).
13
14Marré & Bertolino (IEEE TSE 29(11), 2003) define the *spanning set* of a
15coverage criterion as a minimal subset of test requirements such that
16covering every requirement in the subset implies covering all the original
17requirements. Equivalently: the maximal elements of the subsumption order,
18where requirement g subsumes requirement g' iff every test that covers g
19also covers g'.
20
21For k-path coverage, witnesses are conjunctions of branch-direction atoms.
22Goal g (atoms A) subsumes goal g' (atoms A') iff A' ⊂ A — any test that
23satisfies all of A automatically satisfies the smaller A'. So the spanning
24set is the set of goals whose atom multisets are not a proper subset of any
25other emitted goal's atom multiset. Atom equality is structural (deep
26expr2tc compare), not pointer-identity, so the analysis stays sound under
27future expr2tc copies, canonicalisation, or hash-consing changes.
28
29Phase-1 reports `reached / total_emitted`, which over-counts redundancy:
30the depth-(n-1) goal {a} is structurally redundant when a depth-n goal
31{a, b} is also emitted, but it inflates the denominator. Spanning-set
32scoring switches the denominator to |maximal_set|, tightening the lower
33bound without ever inflating coverage past the true value.
34
35This module is a pure structural analysis over the emitted goal list — no
36SMT call, no value-flow analysis. Phase 2 PR2 (semantic comparison-domain
37contradictions) feeds in by skipping infeasible goals at instrumentation
38time, which transitively shrinks the spanning set.
39*/
41{
42public:
43 // An atom is a (stored_guard, polarity) pair. Polarity true means the
44 // guard appears positively in the witness; false means negated.
45 using atom_t = std::pair<expr2tc, bool>;
46
47 // Multiset of atoms in a goal's witness conjunction. Duplicates are
48 // preserved (the contradiction filter in goto_coverage drops opposite-
49 // polarity duplicates before this point, but identical-polarity
50 // duplicates can still appear when the same guard repeats in the
51 // sliding window — see test 8). Named *_multiset_t to make the
52 // duplicate-preserving semantics explicit at the call site.
53 using atom_multiset_t = std::vector<atom_t>;
54
55 // Record a goal that has been emitted as an instrumented assertion. The
56 // (claim_msg, claim_loc) pair is the same key used in
57 // goto_coveraget::all_claims and the JSON report.
58 void
59 add_goal(atom_multiset_t atoms, std::string claim_msg, std::string claim_loc);
60
61 // Compute the spanning set. After this call, spanning_size() returns
62 // |maximal_set| and is_redundant(msg, loc) returns true iff every goal
63 // record with that (msg, loc) is non-maximal (subsumed by another goal).
64 void finalize();
65
66 // Number of emitted goals — denominator under Phase-1 scoring.
67 size_t total() const
68 {
69 return goals_.size();
70 }
71
72 // Number of maximal goals — denominator under spanning-set scoring.
73 size_t spanning_size() const
74 {
75 return spanning_size_;
76 }
77
78 // True iff the (claim_msg, claim_loc) pair is non-maximal in every
79 // emission. A claim is "feasible" otherwise.
80 bool is_redundant(const std::string &msg, const std::string &loc) const;
81
82 // Reset for a fresh run (e.g., second invocation in a session).
83 void clear();
84
85private:
86 struct goal_t
87 {
88 // Sorted by atom_lt — a deep structural ordering (expr2tc::operator<
89 // followed by polarity). Sorting is required for std::includes-based
90 // multiset subset checks in is_proper_multiset_subset.
91 atom_multiset_t atoms;
92 // Bloom-style 64-bit signature: one bit set per atom hash modulo 64.
93 // Used as a fast necessary condition before the deep multiset compare:
94 // for `small ⊂ big`, every bit in small.signature must appear in
95 // big.signature, so (small.signature & big.signature) == small.signature
96 // is implied. False positives are possible (two distinct atoms can
97 // collide on the same bucket); a false signature match always falls
98 // back to the structural check, so soundness is preserved.
99 uint64_t signature = 0;
100 std::string msg;
101 std::string loc;
102 bool maximal = true;
103 };
104
105 std::vector<goal_t> goals_;
106 std::set<std::pair<std::string, std::string>> redundant_claims_;
107 size_t spanning_size_ = 0;
108};
Definition k_path_spanning.h:41
void add_goal(atom_multiset_t atoms, std::string claim_msg, std::string claim_loc)
Definition k_path_spanning.cpp:62
size_t spanning_size() const
Definition k_path_spanning.h:73
bool is_redundant(const std::string &msg, const std::string &loc) const
Definition k_path_spanning.cpp:135
std::pair< expr2tc, bool > atom_t
Definition k_path_spanning.h:45
std::vector< atom_t > atom_multiset_t
Definition k_path_spanning.h:53
void finalize()
Definition k_path_spanning.cpp:73
void clear()
Definition k_path_spanning.cpp:142
size_t total() const
Definition k_path_spanning.h:67
Classes and definitions for non-stringy internal representation.