1use super::functions::*;
6use std::collections::{BTreeMap, HashMap, HashSet};
7use std::fmt;
8
9#[derive(Debug, Clone)]
11pub struct LTS<S: Clone + Eq + std::hash::Hash> {
12 pub states: HashSet<S>,
14 pub initial: S,
16 pub transitions: HashMap<S, Vec<(String, S)>>,
18}
19impl<S: Clone + Eq + std::hash::Hash + std::fmt::Debug> LTS<S> {
20 pub fn new(initial: S) -> Self {
22 let mut states = HashSet::new();
23 states.insert(initial.clone());
24 LTS {
25 states,
26 initial,
27 transitions: HashMap::new(),
28 }
29 }
30 pub fn add_transition(&mut self, from: S, label: impl Into<String>, to: S) {
32 self.states.insert(from.clone());
33 self.states.insert(to.clone());
34 self.transitions
35 .entry(from)
36 .or_default()
37 .push((label.into(), to));
38 }
39 pub fn reachable_states(&self) -> HashSet<S> {
41 let mut visited = HashSet::new();
42 let mut queue = vec![self.initial.clone()];
43 while let Some(s) = queue.pop() {
44 if visited.insert(s.clone()) {
45 if let Some(succs) = self.transitions.get(&s) {
46 for (_, t) in succs {
47 queue.push(t.clone());
48 }
49 }
50 }
51 }
52 visited
53 }
54 pub fn labels_subset_of(&self, allowed: &HashSet<String>) -> bool {
56 for succs in self.transitions.values() {
57 for (lbl, _) in succs {
58 if !allowed.contains(lbl) {
59 return false;
60 }
61 }
62 }
63 true
64 }
65}
66pub struct HoareLogic {
68 pub axiom_names: Vec<String>,
69}
70impl HoareLogic {
71 pub fn new() -> Self {
72 Self {
73 axiom_names: vec![
74 "SkipRule".to_string(),
75 "AssignRule".to_string(),
76 "SeqRule".to_string(),
77 "WhileRule".to_string(),
78 "ConsequenceRule".to_string(),
79 ],
80 }
81 }
82 pub fn axioms(&self) -> Vec<(&str, &str)> {
84 vec![
85 ("Skip", "{P} skip {P}"),
86 ("Assign", "{P[e/x]} x:=e {P}"),
87 ("Seq", "{P}C1{Q},{Q}C2{R} => {P}C1;C2{R}"),
88 ("While", "{I∧b}C{I} => {I} while b {I∧¬b}"),
89 ("Consequence", "{P'}⊢{P} {P}C{Q} {Q}⊢{Q'} => {P'}C{Q'}"),
90 ]
91 }
92 pub fn soundness_proof(&self) -> String {
94 "Soundness by induction on derivation height: \
95 each rule preserves the partial-correctness relation \
96 [[{P}C{Q}]] = ∀σ. P σ → ∀σ'. (C,σ)↓σ' → Q σ'."
97 .to_string()
98 }
99 pub fn completeness_proof(&self) -> String {
101 "Completeness (Cook 1978): if [[{P}C{Q}]] then ⊢ {P}C{Q}. \
102 Uses the weakest liberal precondition wlp(C,Q) as the canonical invariant. \
103 Relative completeness: assumes an expressive assertion language."
104 .to_string()
105 }
106}
107#[derive(Debug, Clone)]
109pub struct HoareTriple {
110 pub pre: Assertion,
112 pub command: String,
114 pub post: Assertion,
116 pub total: bool,
118}
119impl HoareTriple {
120 pub fn partial(pre: Assertion, command: impl Into<String>, post: Assertion) -> Self {
122 HoareTriple {
123 pre,
124 command: command.into(),
125 post,
126 total: false,
127 }
128 }
129 pub fn total(pre: Assertion, command: impl Into<String>, post: Assertion) -> Self {
131 HoareTriple {
132 pre,
133 command: command.into(),
134 post,
135 total: true,
136 }
137 }
138 pub fn display(&self) -> String {
140 if self.total {
141 format!("[{}] {} [{}]", self.pre, self.command, self.post)
142 } else {
143 format!("{{{}}}\n {}\n{{{}}}", self.pre, self.command, self.post)
144 }
145 }
146}
147#[derive(Debug, Clone, PartialEq, Eq)]
149pub enum ExclResource<T: Clone + Eq> {
150 Excl(T),
152 Invalid,
154}
155impl<T: Clone + Eq> ExclResource<T> {
156 pub fn compose(&self, _other: &Self) -> Self {
158 ExclResource::Invalid
159 }
160 pub fn is_valid(&self) -> bool {
162 matches!(self, ExclResource::Excl(_))
163 }
164 pub fn core(&self) -> Option<Self> {
166 None
167 }
168}
169#[allow(dead_code)]
170#[derive(Debug, Clone)]
171pub enum CSLActionModel {
172 OwnershipTransfer,
173 SharedInvariant,
174 FractionalPermission,
175 ViewShift,
176}
177#[allow(dead_code)]
178#[derive(Debug, Clone)]
179pub struct ProbabilisticHoareLogic {
180 pub logic_name: String,
181 pub pre_distribution: String,
182 pub command: String,
183 pub post_expectation: String,
184 pub expected_cost: Option<f64>,
185}
186#[allow(dead_code)]
187impl ProbabilisticHoareLogic {
188 pub fn phl(pre: &str, cmd: &str, post: &str) -> Self {
189 ProbabilisticHoareLogic {
190 logic_name: "PHL (probabilistic Hoare)".to_string(),
191 pre_distribution: pre.to_string(),
192 command: cmd.to_string(),
193 post_expectation: post.to_string(),
194 expected_cost: None,
195 }
196 }
197 pub fn expectation_transformer(&self) -> String {
198 format!(
199 "wp({}, {}) = pre expectation",
200 self.command, self.post_expectation
201 )
202 }
203 pub fn mciver_morgan_rule(&self) -> String {
204 format!(
205 "McIver-Morgan: [{}] → {} → [{}]",
206 self.pre_distribution, self.command, self.post_expectation
207 )
208 }
209 pub fn with_cost(mut self, cost: f64) -> Self {
210 self.expected_cost = Some(cost);
211 self
212 }
213}
214#[allow(dead_code)]
215#[derive(Debug, Clone)]
216pub struct ApproximateVerification {
217 pub epsilon: f64,
218 pub delta: f64,
219 pub verified_property: String,
220 pub confidence: f64,
221}
222#[allow(dead_code)]
223impl ApproximateVerification {
224 pub fn pac_verification(eps: f64, delta: f64, prop: &str) -> Self {
225 ApproximateVerification {
226 epsilon: eps,
227 delta,
228 verified_property: prop.to_string(),
229 confidence: 1.0 - delta,
230 }
231 }
232 pub fn sample_complexity(&self) -> usize {
233 let n = (1.0 / self.delta).ln() / (self.epsilon * self.epsilon);
234 n.ceil() as usize
235 }
236 pub fn soundness_statement(&self) -> String {
237 format!(
238 "With prob ≥ {:.3}: property '{}' holds up to ε={:.4}",
239 self.confidence, self.verified_property, self.epsilon
240 )
241 }
242}
243pub struct AuthLogic {
245 pub principals: Vec<String>,
246 pub statements: Vec<String>,
247}
248impl AuthLogic {
249 pub fn new(principals: Vec<String>, statements: Vec<String>) -> Self {
250 Self {
251 principals,
252 statements,
253 }
254 }
255 pub fn says_operator(&self) -> String {
257 format!(
258 "Says operator: principal A says φ means A is committed to φ. \
259 Principals: {:?}. \
260 Statements: {:?}.",
261 self.principals, self.statements
262 )
263 }
264 pub fn delegation(&self) -> String {
266 "Delegation: if A says (B controls f) and B says f, then A says f. \
267 Used to transfer authority without forging credentials."
268 .to_string()
269 }
270}
271#[derive(Debug, Clone)]
273pub struct VerificationCondition {
274 pub formula: Assertion,
276 pub origin: String,
278}
279impl VerificationCondition {
280 pub fn new(formula: Assertion, origin: impl Into<String>) -> Self {
282 VerificationCondition {
283 formula,
284 origin: origin.into(),
285 }
286 }
287}
288pub struct ConcurrentSeparationLogic {
290 pub threads: Vec<String>,
291}
292impl ConcurrentSeparationLogic {
293 pub fn new(threads: Vec<String>) -> Self {
294 Self { threads }
295 }
296 pub fn rely_guarantee(&self) -> String {
298 format!(
299 "Rely-Guarantee for {} thread(s): each thread specifies a rely R (interference \
300 tolerated) and guarantee G (interference produced). Thread-modular: \
301 {{P, R, G, Q}} t {{...}} requires stable(P, R) and G ⊆ Rely_of_others.",
302 self.threads.len()
303 )
304 }
305 pub fn permission_accounting(&self) -> String {
307 "Fractional permissions: write=1, read=½. \
308 Multiple readers hold ½ each; writer holds 1. \
309 Permissions are additive and must sum to ≤ 1."
310 .to_string()
311 }
312}
313#[derive(Debug, Clone, PartialEq, Eq)]
315pub enum Command {
316 Skip,
318 Assign(String, String),
320 Seq(Box<Command>, Box<Command>),
322 If(String, Box<Command>, Box<Command>),
324 While(String, Assertion, Box<Command>),
326}
327impl Command {
328 pub fn wp(&self, q: &Assertion) -> Assertion {
336 match self {
337 Command::Skip => q.clone(),
338 Command::Assign(x, e) => q.subst(x, e),
339 Command::Seq(c1, c2) => {
340 let q2 = c2.wp(q);
341 c1.wp(&q2)
342 }
343 Command::If(b, c1, c2) => {
344 let wp1 = c1.wp(q);
345 let wp2 = c2.wp(q);
346 Assertion::new(format!("({b} → ({wp1})) ∧ (¬{b} → ({wp2}))"))
347 }
348 Command::While(_, inv, _) => inv.clone(),
349 }
350 }
351 pub fn generate_vcs(&self, q: &Assertion) -> Vec<VerificationCondition> {
353 match self {
354 Command::Skip | Command::Assign(_, _) => vec![],
355 Command::Seq(c1, c2) => {
356 let mid = c2.wp(q);
357 let mut vcs = c1.generate_vcs(&mid);
358 vcs.extend(c2.generate_vcs(q));
359 vcs
360 }
361 Command::If(_, c1, c2) => {
362 let mut vcs = c1.generate_vcs(q);
363 vcs.extend(c2.generate_vcs(q));
364 vcs
365 }
366 Command::While(b, inv, body) => {
367 let wp_body_inv = body.wp(inv);
368 let guard_and_inv = inv.and(&Assertion::new(b));
369 let vc1 = VerificationCondition::new(
370 Assertion::new(format!("({guard_and_inv}) → ({wp_body_inv})")),
371 "loop invariant preservation",
372 );
373 let neg_b = Assertion::new(format!("¬{b}"));
374 let inv_and_neg_b = inv.and(&neg_b);
375 let vc2 = VerificationCondition::new(
376 Assertion::new(format!("({inv_and_neg_b}) → ({q})")),
377 "loop exit implies postcondition",
378 );
379 let mut vcs = body.generate_vcs(inv);
380 vcs.push(vc1);
381 vcs.push(vc2);
382 vcs
383 }
384 }
385 }
386}
387#[derive(Debug, Clone)]
389pub struct GhostHeap<T: Clone + Eq> {
390 cells: HashMap<String, ExclResource<T>>,
391}
392impl<T: Clone + Eq> GhostHeap<T> {
393 pub fn empty() -> Self {
395 GhostHeap {
396 cells: HashMap::new(),
397 }
398 }
399 pub fn alloc(&mut self, name: impl Into<String>, val: T) {
401 self.cells.insert(name.into(), ExclResource::Excl(val));
402 }
403 pub fn update(&mut self, name: &str, new_val: T) -> bool {
405 match self.cells.get(name) {
406 Some(ExclResource::Excl(_)) => {
407 self.cells
408 .insert(name.to_string(), ExclResource::Excl(new_val));
409 true
410 }
411 _ => false,
412 }
413 }
414 pub fn read(&self, name: &str) -> Option<&T> {
416 match self.cells.get(name)? {
417 ExclResource::Excl(v) => Some(v),
418 _ => None,
419 }
420 }
421}
422#[allow(dead_code)]
423#[derive(Debug, Clone)]
424pub struct EffectSystem {
425 pub name: String,
426 pub effect_types: Vec<String>,
427 pub is_algebraic: bool,
428 pub monad_based: bool,
429}
430#[allow(dead_code)]
431impl EffectSystem {
432 pub fn algebraic_effects() -> Self {
433 EffectSystem {
434 name: "Algebraic Effects (Plotkin-Power)".to_string(),
435 effect_types: vec!["IO".to_string(), "State".to_string(), "Exn".to_string()],
436 is_algebraic: true,
437 monad_based: false,
438 }
439 }
440 pub fn monad_transformers() -> Self {
441 EffectSystem {
442 name: "Monad Transformer Stack".to_string(),
443 effect_types: vec![
444 "StateT".to_string(),
445 "ExceptT".to_string(),
446 "WriterT".to_string(),
447 ],
448 is_algebraic: false,
449 monad_based: true,
450 }
451 }
452 pub fn add_effect(&mut self, eff: &str) {
453 self.effect_types.push(eff.to_string());
454 }
455 pub fn effect_handling_description(&self) -> String {
456 if self.is_algebraic {
457 format!(
458 "{}: operations defined algebraically, handlers provide interpretations",
459 self.name
460 )
461 } else {
462 format!("{}: effects composed via monad transformers", self.name)
463 }
464 }
465 pub fn free_monad_presentation(&self) -> String {
466 format!(
467 "Free monad F_Σ where Σ = {{{}}}",
468 self.effect_types.join(", ")
469 )
470 }
471}
472pub struct TemporalLTL {
474 pub program: String,
475 pub ltl_spec: String,
476}
477impl TemporalLTL {
478 pub fn new(program: impl Into<String>, ltl_spec: impl Into<String>) -> Self {
479 Self {
480 program: program.into(),
481 ltl_spec: ltl_spec.into(),
482 }
483 }
484 pub fn model_check(&self) -> Result<(), String> {
487 if self.ltl_spec.contains("false") {
488 Err(format!(
489 "Counterexample: program '{}' violates LTL spec '{}'.",
490 self.program, self.ltl_spec
491 ))
492 } else {
493 Ok(())
494 }
495 }
496 pub fn synthesize_winning_strategy(&self) -> String {
498 format!(
499 "LTL synthesis for spec '{}': compute a reactive system S such that \
500 for all environment strategies, S satisfies '{}'.",
501 self.ltl_spec, self.ltl_spec
502 )
503 }
504}
505#[derive(Debug, Clone, Copy, PartialEq)]
507pub struct FractionalPerm(f64);
508impl FractionalPerm {
509 pub fn new(q: f64) -> Self {
511 assert!(q > 0.0 && q <= 1.0 + 1e-9, "permission must be in (0, 1]");
512 FractionalPerm(q.min(1.0))
513 }
514 pub fn write() -> Self {
516 FractionalPerm(1.0)
517 }
518 pub fn read_half() -> Self {
520 FractionalPerm(0.5)
521 }
522 pub fn split_half(&self) -> (Self, Self) {
524 let half = self.0 / 2.0;
525 (FractionalPerm(half), FractionalPerm(half))
526 }
527 pub fn combine(&self, other: &Self) -> Option<Self> {
529 let sum = self.0 + other.0;
530 if sum <= 1.0 + 1e-9 {
531 Some(FractionalPerm(sum.min(1.0)))
532 } else {
533 None
534 }
535 }
536 pub fn is_write(&self) -> bool {
538 (self.0 - 1.0).abs() < 1e-9
539 }
540 pub fn value(&self) -> f64 {
542 self.0
543 }
544}
545#[derive(Debug, Clone, PartialEq, Eq, Hash)]
547pub struct Transition<S: Clone> {
548 pub before: S,
550 pub after: S,
552}
553impl<S: Clone> Transition<S> {
554 pub fn new(before: S, after: S) -> Self {
556 Transition { before, after }
557 }
558}
559#[derive(Debug, Clone, PartialEq, Eq)]
561pub struct Heap {
562 cells: BTreeMap<u64, u64>,
564}
565impl Heap {
566 pub fn empty() -> Self {
568 Heap {
569 cells: BTreeMap::new(),
570 }
571 }
572 pub fn read(&self, addr: u64) -> Option<u64> {
574 self.cells.get(&addr).copied()
575 }
576 pub fn write(&mut self, addr: u64, val: u64) {
578 self.cells.insert(addr, val);
579 }
580 pub fn dealloc(&mut self, addr: u64) {
582 self.cells.remove(&addr);
583 }
584 pub fn is_disjoint(&self, other: &Self) -> bool {
586 self.cells.keys().all(|k| !other.cells.contains_key(k))
587 }
588 pub fn disjoint_union(&self, other: &Self) -> Self {
590 assert!(self.is_disjoint(other), "heaps overlap");
591 let mut cells = self.cells.clone();
592 cells.extend(other.cells.iter());
593 Heap { cells }
594 }
595 pub fn domain(&self) -> HashSet<u64> {
597 self.cells.keys().copied().collect()
598 }
599 pub fn size(&self) -> usize {
601 self.cells.len()
602 }
603}
604#[derive(Debug, Clone, PartialEq, Eq)]
606pub enum ConcurrencyLogic {
607 ConcurrentSL,
609 Iris,
611 VST,
613 CompCert,
615}
616impl ConcurrencyLogic {
617 pub fn is_machine_checked(&self) -> bool {
619 matches!(
620 self,
621 ConcurrencyLogic::Iris | ConcurrencyLogic::VST | ConcurrencyLogic::CompCert
622 )
623 }
624 pub fn uses_separation_logic(&self) -> bool {
626 matches!(
627 self,
628 ConcurrencyLogic::ConcurrentSL
629 | ConcurrencyLogic::Iris
630 | ConcurrencyLogic::VST
631 | ConcurrencyLogic::CompCert
632 )
633 }
634}
635pub struct SeparationLogic {
637 pub heap_assertion: String,
638}
639impl SeparationLogic {
640 pub fn new(heap_assertion: impl Into<String>) -> Self {
641 Self {
642 heap_assertion: heap_assertion.into(),
643 }
644 }
645 pub fn frame_rule(&self) -> String {
647 format!(
648 "Frame Rule: if {{{}}}C{{Q}} and modifies(C) ∩ fv(R) = ∅, then {{{}*R}}C{{Q*R}}",
649 self.heap_assertion, self.heap_assertion
650 )
651 }
652 pub fn small_axiom(&self) -> String {
654 "{emp} x:=alloc(n) {x↦0,…,0} — small footprint for allocation".to_string()
655 }
656 pub fn bi_abduction(&self) -> String {
658 format!(
659 "Bi-abduction: given {} as P, find anti-frame X and frame Y such that P*X ⊢ Q*Y. \
660 Used in Infer for compositional analysis.",
661 self.heap_assertion
662 )
663 }
664}
665pub struct DifferentialPrivacyLogic {
667 pub program: String,
668 pub epsilon: f64,
669}
670impl DifferentialPrivacyLogic {
671 pub fn new(program: impl Into<String>, epsilon: f64) -> Self {
672 Self {
673 program: program.into(),
674 epsilon,
675 }
676 }
677 pub fn dp_proof_rule(&self) -> String {
679 format!(
680 "DP proof for '{}' at ε={}: use the probabilistic relational Hoare logic (apRHL) \
681 coupling rule. Show that for any adjacent inputs d, d', \
682 Pr[M(d) ∈ S] ≤ e^ε · Pr[M(d') ∈ S] for all events S.",
683 self.program, self.epsilon
684 )
685 }
686 pub fn coupling_proof(&self) -> String {
688 format!(
689 "Coupling proof at ε={}: construct a probabilistic coupling Γ of M(d) and M(d') \
690 such that Pr[(x,y) ∼ Γ : x ≠y] ≤ 1 - e^(-ε). \
691 The Laplace mechanism achieves ε-DP with noise Lap(Δf/ε).",
692 self.epsilon
693 )
694 }
695}
696#[allow(dead_code)]
697#[derive(Debug, Clone)]
698pub enum NumericalDomainType {
699 Interval,
700 Octagon,
701 Polyhedra,
702 Zones,
703 Congruences,
704}
705pub struct HeapPred(Box<dyn Fn(&Heap) -> bool>);
708impl HeapPred {
709 pub fn new(f: impl Fn(&Heap) -> bool + 'static) -> Self {
711 HeapPred(Box::new(f))
712 }
713 pub fn satisfies(&self, h: &Heap) -> bool {
715 (self.0)(h)
716 }
717 pub fn sep_star(p: HeapPred, q: HeapPred) -> HeapPred {
719 HeapPred::new(move |h| {
720 let domain: Vec<u64> = h.domain().into_iter().collect();
721 let n = domain.len();
722 for mask in 0u64..(1u64 << n) {
723 let mut h1 = Heap::empty();
724 let mut h2 = Heap::empty();
725 for (i, &addr) in domain.iter().enumerate() {
726 if (mask >> i) & 1 == 1 {
727 h1.write(
728 addr,
729 h.read(addr)
730 .expect("addr is from domain, which was iterated from h's keys"),
731 );
732 } else {
733 h2.write(
734 addr,
735 h.read(addr)
736 .expect("addr is from domain, which was iterated from h's keys"),
737 );
738 }
739 }
740 if p.satisfies(&h1) && q.satisfies(&h2) {
741 return true;
742 }
743 }
744 false
745 })
746 }
747 pub fn emp() -> HeapPred {
749 HeapPred::new(|h| h.size() == 0)
750 }
751 pub fn points_to(l: u64, v: u64) -> HeapPred {
753 HeapPred::new(move |h| h.size() == 1 && h.read(l) == Some(v))
754 }
755}
756#[derive(Debug, Clone, PartialEq, Eq)]
758pub struct Mask {
759 open: HashSet<u64>,
760}
761impl Mask {
762 pub fn full() -> Self {
764 Mask {
765 open: HashSet::new(),
766 }
767 }
768 pub fn contains(&self, n: Namespace) -> bool {
770 self.open.contains(&n.0)
771 }
772 pub fn remove(&self, n: Namespace) -> Self {
774 let mut m = self.clone();
775 m.open.insert(n.0);
776 m
777 }
778 pub fn insert(&self, n: Namespace) -> Self {
780 let mut m = self.clone();
781 m.open.remove(&n.0);
782 m
783 }
784}
785pub struct ResourceInvariant {
787 pub predicate: String,
788 pub is_stable: bool,
789}
790impl ResourceInvariant {
791 pub fn new(predicate: impl Into<String>, is_stable: bool) -> Self {
792 Self {
793 predicate: predicate.into(),
794 is_stable,
795 }
796 }
797 pub fn stabilize_under_interference(&self, rely: &str) -> String {
800 if self.is_stable {
801 format!(
802 "'{}' is already stable under rely '{}'.",
803 self.predicate, rely
804 )
805 } else {
806 format!(
807 "Stabilise '{}' under rely '{}': compute the closure \
808 Stab(P, R) = lfp(λS. P ∨ post_R(S)).",
809 self.predicate, rely
810 )
811 }
812 }
813}
814pub struct DynamicLogic {
816 pub program: String,
817 pub formula: String,
818}
819impl DynamicLogic {
820 pub fn new(program: impl Into<String>, formula: impl Into<String>) -> Self {
821 Self {
822 program: program.into(),
823 formula: formula.into(),
824 }
825 }
826 pub fn test_programs(&self) -> Vec<String> {
828 vec![
829 format!("({})? — test that {} holds", self.formula, self.formula),
830 "skip — null program".to_string(),
831 "abort — fail program".to_string(),
832 ]
833 }
834 pub fn regular_programs(&self) -> Vec<String> {
836 vec![
837 "α ; β — sequential composition".to_string(),
838 "α ∪ β — nondeterministic choice".to_string(),
839 "α* — finite iteration (Kleene star)".to_string(),
840 "φ? — test (guard)".to_string(),
841 ]
842 }
843}
844#[allow(dead_code)]
845#[derive(Debug, Clone)]
846pub struct TypeAndEffect {
847 pub value_type: String,
848 pub effect_annotation: String,
849 pub purity: EffectPurity,
850}
851#[allow(dead_code)]
852impl TypeAndEffect {
853 pub fn pure_type(ty: &str) -> Self {
854 TypeAndEffect {
855 value_type: ty.to_string(),
856 effect_annotation: "∅".to_string(),
857 purity: EffectPurity::Pure,
858 }
859 }
860 pub fn effectful(ty: &str, effects: Vec<String>) -> Self {
861 let ann = effects.join(",");
862 TypeAndEffect {
863 value_type: ty.to_string(),
864 effect_annotation: format!("{{{}}}", ann),
865 purity: EffectPurity::Impure(effects),
866 }
867 }
868 pub fn is_pure(&self) -> bool {
869 matches!(self.purity, EffectPurity::Pure)
870 }
871 pub fn type_and_effect_judgment(&self) -> String {
872 format!("⊢ e : {}!{}", self.value_type, self.effect_annotation)
873 }
874}
875#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
877pub struct Namespace(pub u64);
878#[allow(dead_code)]
879#[derive(Debug, Clone)]
880pub struct ConcurrentSeparationLogicExt {
881 pub framework: String,
882 pub action_model: CSLActionModel,
883 pub supports_rely_guarantee: bool,
884 pub fractional_permissions: bool,
885}
886#[allow(dead_code)]
887impl ConcurrentSeparationLogicExt {
888 pub fn csl_classic() -> Self {
889 ConcurrentSeparationLogicExt {
890 framework: "CSL (O'Hearn 2004)".to_string(),
891 action_model: CSLActionModel::SharedInvariant,
892 supports_rely_guarantee: false,
893 fractional_permissions: false,
894 }
895 }
896 pub fn iris() -> Self {
897 ConcurrentSeparationLogicExt {
898 framework: "Iris (Jung et al.)".to_string(),
899 action_model: CSLActionModel::ViewShift,
900 supports_rely_guarantee: true,
901 fractional_permissions: true,
902 }
903 }
904 pub fn concurrent_triple(&self, pre: &str, cmd: &str, post: &str) -> String {
905 format!("{{{}}}\n {}\n{{{}}}", pre, cmd, post)
906 }
907 pub fn frame_rule_concurrent(&self, resource_inv: &str) -> String {
908 format!(
909 "Concurrent frame rule: {{P}} C {{Q}} → {{P * {}}} C {{Q * {}}}",
910 resource_inv, resource_inv
911 )
912 }
913 pub fn race_condition_freedom(&self) -> bool {
914 true
915 }
916}
917#[derive(Debug, Clone, PartialEq, Eq)]
919pub struct Assertion {
920 pub formula: String,
922}
923impl Assertion {
924 pub fn new(formula: impl Into<String>) -> Self {
926 Assertion {
927 formula: formula.into(),
928 }
929 }
930 pub fn negate(&self) -> Self {
932 Assertion {
933 formula: format!("¬({})", self.formula),
934 }
935 }
936 pub fn and(&self, other: &Self) -> Self {
938 Assertion {
939 formula: format!("({}) ∧ ({})", self.formula, other.formula),
940 }
941 }
942 pub fn or(&self, other: &Self) -> Self {
944 Assertion {
945 formula: format!("({}) ∨ ({})", self.formula, other.formula),
946 }
947 }
948 pub fn subst(&self, var: &str, expr: &str) -> Self {
950 Assertion {
951 formula: self.formula.replace(var, expr),
952 }
953 }
954}
955#[derive(Debug, Clone)]
957pub struct RelyCondition<S: Clone + Eq + std::hash::Hash> {
958 pub transitions: HashSet<Transition<S>>,
960}
961impl<S: Clone + Eq + std::hash::Hash> RelyCondition<S> {
962 pub fn empty() -> Self {
964 RelyCondition {
965 transitions: HashSet::new(),
966 }
967 }
968 pub fn add(&mut self, t: Transition<S>) {
970 self.transitions.insert(t);
971 }
972 pub fn allows(&self, t: &Transition<S>) -> bool {
974 self.transitions.contains(t)
975 }
976}
977#[allow(dead_code)]
978#[derive(Debug, Clone)]
979pub struct RelyGuaranteeLogic {
980 pub rely_condition: String,
981 pub guarantee_condition: String,
982 pub stable_pre: String,
983 pub stable_post: String,
984}
985#[allow(dead_code)]
986impl RelyGuaranteeLogic {
987 pub fn new(rely: &str, guarantee: &str, pre: &str, post: &str) -> Self {
988 RelyGuaranteeLogic {
989 rely_condition: rely.to_string(),
990 guarantee_condition: guarantee.to_string(),
991 stable_pre: pre.to_string(),
992 stable_post: post.to_string(),
993 }
994 }
995 pub fn rg_triple(&self, cmd: &str) -> String {
996 format!(
997 "R: {}, G: {}\n {{{}}} {} {{{}}}",
998 self.rely_condition, self.guarantee_condition, self.stable_pre, cmd, self.stable_post
999 )
1000 }
1001 pub fn stability_check(&self) -> String {
1002 format!(
1003 "Stability: pre '{}' and post '{}' stable under rely '{}'",
1004 self.stable_pre, self.stable_post, self.rely_condition
1005 )
1006 }
1007}
1008#[allow(dead_code)]
1009#[derive(Debug, Clone)]
1010pub struct NumericalDomain {
1011 pub name: String,
1012 pub domain_type: NumericalDomainType,
1013 pub join_semilattice: bool,
1014 pub is_relational: bool,
1015}
1016#[allow(dead_code)]
1017impl NumericalDomain {
1018 pub fn intervals() -> Self {
1019 NumericalDomain {
1020 name: "Interval Domain (Cousot-Cousot)".to_string(),
1021 domain_type: NumericalDomainType::Interval,
1022 join_semilattice: true,
1023 is_relational: false,
1024 }
1025 }
1026 pub fn octagons() -> Self {
1027 NumericalDomain {
1028 name: "Octagon Domain (Miné)".to_string(),
1029 domain_type: NumericalDomainType::Octagon,
1030 join_semilattice: true,
1031 is_relational: true,
1032 }
1033 }
1034 pub fn polyhedra() -> Self {
1035 NumericalDomain {
1036 name: "Convex Polyhedra (Cousot-Halbwachs)".to_string(),
1037 domain_type: NumericalDomainType::Polyhedra,
1038 join_semilattice: true,
1039 is_relational: true,
1040 }
1041 }
1042 pub fn precision_cost_tradeoff(&self) -> String {
1043 match &self.domain_type {
1044 NumericalDomainType::Interval => "O(n) cost, low precision".to_string(),
1045 NumericalDomainType::Zones => "O(n²) cost, moderate precision".to_string(),
1046 NumericalDomainType::Octagon => "O(n²) cost, better precision".to_string(),
1047 NumericalDomainType::Polyhedra => "O(2^n) cost, highest precision".to_string(),
1048 NumericalDomainType::Congruences => "O(n) cost, congruence precision".to_string(),
1049 }
1050 }
1051 pub fn is_more_precise_than_intervals(&self) -> bool {
1052 !matches!(self.domain_type, NumericalDomainType::Interval)
1053 }
1054}
1055#[allow(dead_code)]
1056#[derive(Debug, Clone)]
1057pub enum EffectPurity {
1058 Pure,
1059 Impure(Vec<String>),
1060 Partial,
1061}
1062#[derive(Debug, Clone)]
1064pub struct InvariantRecord {
1065 pub ns: Namespace,
1067 pub formula: String,
1069 pub open: bool,
1071}
1072impl InvariantRecord {
1073 pub fn alloc(ns: Namespace, formula: impl Into<String>) -> Self {
1075 InvariantRecord {
1076 ns,
1077 formula: formula.into(),
1078 open: false,
1079 }
1080 }
1081 pub fn open_inv(&mut self) -> bool {
1083 if !self.open {
1084 self.open = true;
1085 true
1086 } else {
1087 false
1088 }
1089 }
1090 pub fn close_inv(&mut self) -> bool {
1092 if self.open {
1093 self.open = false;
1094 true
1095 } else {
1096 false
1097 }
1098 }
1099}
1100pub struct WeakestPrecondition {
1102 pub stmt: String,
1103 pub post: String,
1104}
1105impl WeakestPrecondition {
1106 pub fn new(stmt: impl Into<String>, post: impl Into<String>) -> Self {
1107 Self {
1108 stmt: stmt.into(),
1109 post: post.into(),
1110 }
1111 }
1112 pub fn compute_wp(&self) -> String {
1115 format!(
1116 "WP({}, {}) = <structurally computed predicate>",
1117 self.stmt, self.post
1118 )
1119 }
1120 pub fn is_valid_hoare(&self) -> bool {
1122 true
1123 }
1124}