Skip to content

Commit 1de4e5b

Browse files
author
GBathie
committed
Add Not operator, remove NNF
1 parent 78603e0 commit 1de4e5b

File tree

8 files changed

+50
-65
lines changed

8 files changed

+50
-65
lines changed

src/algos/meta/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ pub mod meta_res;
2222
/// LTL search followed by Divide and Conquer.
2323
pub fn divide_conquer<P>(
2424
traces: &[Trace],
25-
alphabet: Vec<String>,
25+
atomic_propositions: Vec<String>,
2626
operators: Operators,
2727
target: Vec<bool>,
2828
max_size_ltl: usize,
@@ -34,7 +34,7 @@ where
3434
{
3535
let start = Instant::now();
3636

37-
let atoms = atoms(traces, alphabet);
37+
let atoms = atoms(traces, atomic_propositions);
3838
// Add initial formulas
3939
let (atom, mut ltl_cache) = create_initial_cache(atoms, &target);
4040
// Check if target is an atom

src/algos/mod.rs

Lines changed: 10 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -14,18 +14,18 @@
1414
//!
1515
//! Implementing a Boolean Synthesis for use with meta-algorithms is done via
1616
//! the [`BoolAlgoParams`] trait.
17-
use std::{ops::Not, rc::Rc};
17+
use std::rc::Rc;
1818

1919
use meta::cache::InitialBoolCache;
2020

2121
use crate::{
2222
cache::{EnumFormulaCache, EnumFormulaCacheLine},
23-
formula::{tree::FormulaTree, Formula},
23+
formula::{Formula, tree::FormulaTree},
2424
ltl::{
25+
AtomicProposition, LtlFormula,
2526
cache::LtlCache,
2627
charac::LtlCharac,
2728
trace::{Operators, Trace},
28-
LtlFormula, Predicate, PredicateForm,
2929
},
3030
traits::EqTarget,
3131
};
@@ -51,34 +51,20 @@ pub trait BoolAlgoParams {
5151
fn name() -> &'static str;
5252
}
5353

54-
/// Return a [`Vec`] containing all size-1 LTL formulas: the predicates and their negation.
55-
fn atoms(traces: &[Trace], alphabet: Vec<String>) -> Vec<LtlFormula> {
54+
/// Return a [`Vec`] containing all size-1 LTL formulas, that consist only of an atomic proposition.
55+
fn atoms(traces: &[Trace], atomic_propositions: Vec<String>) -> Vec<LtlFormula> {
5656
let mut atoms = Vec::new();
57-
for (i, s) in alphabet.into_iter().enumerate() {
58-
let charac = traces.iter().map(|t| t.alphabet[i]).collect::<LtlCharac>();
59-
let f = Formula::new_base(
60-
charac,
61-
1,
62-
Rc::from(FormulaTree::Atom(Predicate(
63-
s.clone(),
64-
PredicateForm::Positive(i),
65-
))),
66-
);
67-
atoms.push(f);
68-
57+
for (i, s) in atomic_propositions.into_iter().enumerate() {
6958
let charac = traces
7059
.iter()
71-
.map(|t| t.alphabet[i].not())
60+
.map(|t| t.atomic_propositions[i])
7261
.collect::<LtlCharac>();
73-
let not_f = Formula::new_base(
62+
let f = Formula::new_base(
7463
charac,
7564
1,
76-
Rc::from(FormulaTree::Atom(Predicate(
77-
format!("!{s}"),
78-
PredicateForm::Negative(i),
79-
))),
65+
Rc::from(FormulaTree::Atom(AtomicProposition(s, i))),
8066
);
81-
atoms.push(not_f);
67+
atoms.push(f);
8268
}
8369

8470
atoms

src/bin/experiments.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ fn main() {
6060

6161
fn get_name_time_sol<P: BoolAlgoParams + Clone>(
6262
traces: Vec<Trace>,
63-
alphabet: Vec<String>,
63+
atomic_propositions: Vec<String>,
6464
operators: Operators,
6565
target: Vec<bool>,
6666
max_size_ltl: usize,
@@ -69,7 +69,7 @@ fn get_name_time_sol<P: BoolAlgoParams + Clone>(
6969
) -> (f64, Option<FormulaTree>, &'static str) {
7070
let res = divide_conquer(
7171
&traces,
72-
alphabet,
72+
atomic_propositions,
7373
operators,
7474
target.clone(),
7575
max_size_ltl,

src/formula/tree.rs

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
//! Explicit formula tree representation.
2-
use std::{fmt::Display, ops::Not, rc::Rc};
2+
use std::{fmt::Display, rc::Rc};
33

44
use crate::{
5-
ltl::{cm::CharMatrix, trace::Trace, Predicate, PredicateForm},
5+
ltl::{AtomicProposition, cm::CharMatrix, trace::Trace},
66
ops::{binary::LtlBinaryOp, unary::LtlUnaryOp},
77
};
88

99
/// Representation of an LTL as a tree of operators.
1010
#[derive(Debug, PartialEq, Eq, Hash, Clone)]
1111
pub enum FormulaTree {
12-
Atom(Predicate),
12+
Atom(AtomicProposition),
1313
UnaryNode {
1414
op: LtlUnaryOp,
1515
child: Rc<FormulaTree>,
@@ -34,10 +34,9 @@ impl FormulaTree {
3434
/// Evaluate the formula on a set of input traces.
3535
pub fn eval(&self, traces: &[Trace]) -> CharMatrix {
3636
match self {
37-
FormulaTree::Atom(Predicate(_, pf)) => match *pf {
38-
PredicateForm::Positive(i) => traces.iter().map(|t| t.alphabet[i]).collect(),
39-
PredicateForm::Negative(i) => traces.iter().map(|t| t.alphabet[i].not()).collect(),
40-
},
37+
FormulaTree::Atom(AtomicProposition(_, i)) => {
38+
traces.iter().map(|t| t.atomic_propositions[*i]).collect()
39+
}
4140
FormulaTree::UnaryNode { op, child } => {
4241
let cm = child.eval(traces);
4342
LtlUnaryOp::apply_cm(*op, &cm)
@@ -54,7 +53,7 @@ impl FormulaTree {
5453
impl Display for FormulaTree {
5554
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5655
match self {
57-
FormulaTree::Atom(Predicate(p, _)) => write!(f, "{p}"),
56+
FormulaTree::Atom(AtomicProposition(p, _)) => write!(f, "{p}"),
5857
FormulaTree::UnaryNode { op, child } => write!(f, "{op} ({child})"),
5958
FormulaTree::BinaryNode { op, left, right } => write!(f, "({left}) {op} ({right})"),
6059
}

src/ltl/cm.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
//! Characteristic Matrix of LTL formulas.
22
use std::{
33
hash::{Hash, Hasher},
4-
ops::{BitAnd, BitOr},
4+
ops::{BitAnd, BitOr, Not},
55
};
66

77
use crate::HashType;
@@ -74,7 +74,7 @@ impl CharMatrix {
7474
self.seqs.iter().map(|x| x.accepts()).collect()
7575
}
7676

77-
op_for_cm!(weak_next, strong_next, globally, finally);
77+
op_for_cm!(not, weak_next, strong_next, globally, finally);
7878
binop_for_cm!(bitor as or);
7979
binop_for_cm!(bitand as and);
8080
binop_for_cm!(until);

src/ltl/mod.rs

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,17 +10,12 @@ pub mod cs;
1010
pub mod hash;
1111
pub mod trace;
1212

13+
/// Represents an atomic proposition, e.g. `p`, `q`, `var0`, etc.
14+
///
15+
/// The first component is the string representation of the proposition,
16+
/// the second is its index in the vector of atomic propositions.
1317
#[derive(Debug, Hash, PartialEq, Eq, Clone)]
14-
pub struct Predicate(pub(crate) String, pub(crate) PredicateForm);
15-
16-
/// Formula corresponding to a single variable `x_i`, which may be negated.
17-
#[derive(Debug, Hash, PartialEq, Eq, Clone)]
18-
pub enum PredicateForm {
19-
/// Formula `x_i`
20-
Positive(usize),
21-
/// Formula `not x_i`
22-
Negative(usize),
23-
}
18+
pub struct AtomicProposition(pub(crate) String, pub(crate) usize);
2419

2520
pub(crate) type LtlFormula = Formula<LtlCharac>;
2621

src/ltl/trace.rs

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,10 @@ pub struct Instance {
1414
pub operators: Operators,
1515
}
1616

17-
/// Stores the [`CharSeq`] of each predicate on a given trace.
17+
/// Stores the [`CharSeq`] of each atomic_proposition on a given trace.
1818
#[derive(Debug, PartialEq, Eq, Hash, Clone)]
1919
pub struct Trace {
20-
pub alphabet: Vec<CharSeq>,
20+
pub atomic_propositions: Box<[CharSeq]>,
2121
}
2222

2323
#[derive(Debug, PartialEq, Eq, Clone)]
@@ -66,12 +66,12 @@ pub fn parse_traces(buf: &str) -> Instance {
6666
let traces: Option<Vec<_>> = parsed_input
6767
.positive_traces
6868
.into_iter()
69-
.map(|pt| pt.traces_vec_from_alphabet(&parsed_input.atomic_propositions))
69+
.map(|pt| pt.traces_vec_from_atomic_props(&parsed_input.atomic_propositions))
7070
.chain(
7171
parsed_input
7272
.negative_traces
7373
.into_iter()
74-
.map(|pt| pt.traces_vec_from_alphabet(&parsed_input.atomic_propositions)),
74+
.map(|pt| pt.traces_vec_from_atomic_props(&parsed_input.atomic_propositions)),
7575
)
7676
.collect();
7777
let traces = traces.expect("Incorrect traces format");
@@ -95,7 +95,7 @@ pub fn parse_traces(buf: &str) -> Instance {
9595
#[derive(Debug, Clone, Deserialize)]
9696
pub struct ParsedTrace {
9797
#[serde(flatten)]
98-
alphabet: HashMap<String, Vec<String>>,
98+
atomic_propositions: HashMap<String, Vec<String>>,
9999
}
100100

101101
/// Converts a vector of "0"/"1" strings to a CharSeq
@@ -110,13 +110,13 @@ fn vec_to_cs(v: &Vec<String>) -> CharSeq {
110110
}
111111

112112
impl ParsedTrace {
113-
pub fn traces_vec_from_alphabet(&self, alphabet: &[String]) -> Option<Trace> {
114-
let char_seqs: Option<Vec<CharSeq>> = alphabet
113+
pub fn traces_vec_from_atomic_props(&self, atomic_propositions: &[String]) -> Option<Trace> {
114+
let char_seqs: Option<Box<[CharSeq]>> = atomic_propositions
115115
.iter()
116-
.map(|s| self.alphabet.get(s).map(vec_to_cs))
116+
.map(|s| self.atomic_propositions.get(s).map(vec_to_cs))
117117
.collect();
118118
Some(Trace {
119-
alphabet: char_seqs?,
119+
atomic_propositions: char_seqs?,
120120
})
121121
}
122122
}

src/ops/unary.rs

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use crate::ltl::cm::CharMatrix;
77

88
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
99
pub enum LtlUnaryOp {
10-
// Not,
10+
Not,
1111
WeakNext,
1212
StrongNext,
1313
Finally,
@@ -17,14 +17,13 @@ pub enum LtlUnaryOp {
1717
impl LtlUnaryOp {
1818
pub(crate) fn all() -> Vec<LtlUnaryOp> {
1919
use LtlUnaryOp::*;
20-
vec![WeakNext, StrongNext, Finally, Globally]
21-
// vec![Not, WeakNext, StrongNext, Finally, Globally]
20+
vec![Not, WeakNext, StrongNext, Finally, Globally]
2221
}
2322

2423
pub(crate) fn is_boolean_monotone(&self) -> bool {
2524
match self {
26-
// LtlUnaryOp::Not => true,
27-
LtlUnaryOp::WeakNext
25+
LtlUnaryOp::Not
26+
| LtlUnaryOp::WeakNext
2827
| LtlUnaryOp::StrongNext
2928
| LtlUnaryOp::Finally
3029
| LtlUnaryOp::Globally => false,
@@ -33,7 +32,7 @@ impl LtlUnaryOp {
3332

3433
pub(crate) fn apply_cm(op: Self, cm: &CharMatrix) -> CharMatrix {
3534
match op {
36-
// LtlUnaryOp::Not => cm.not(),
35+
LtlUnaryOp::Not => cm.not(),
3736
LtlUnaryOp::WeakNext => cm.weak_next(),
3837
LtlUnaryOp::StrongNext => cm.strong_next(),
3938
LtlUnaryOp::Finally => cm.finally(),
@@ -55,13 +54,15 @@ impl<'a> TryFrom<&'a str> for LtlUnaryOp {
5554
///
5655
/// | String | Result |
5756
/// |:-------|:---------------------|
57+
/// | `"!"` | [`LtlUnaryOp::Not`] |
5858
/// | `"X"` | [`LtlUnaryOp::WeakNext`] |
5959
/// | `"X[!]"` | [`LtlUnaryOp::StrongNext`] |
6060
/// | `"F"` | [`LtlUnaryOp::Finally`] |
6161
/// | `"G"` | [`LtlUnaryOp::Globally`]|
62-
/// | Other value | `Error` |
62+
/// | Other value | [`InvalidUnaryOp`] |
6363
fn try_from(value: &'a str) -> Result<Self, Self::Error> {
6464
match value {
65+
"!" => Ok(LtlUnaryOp::Not),
6566
"X" => Ok(LtlUnaryOp::WeakNext),
6667
"X[!]" => Ok(LtlUnaryOp::StrongNext),
6768
"F" => Ok(LtlUnaryOp::Finally),
@@ -74,6 +75,7 @@ impl<'a> TryFrom<&'a str> for LtlUnaryOp {
7475
impl Display for LtlUnaryOp {
7576
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
7677
match self {
78+
LtlUnaryOp::Not => write!(f, "!"),
7779
LtlUnaryOp::WeakNext => write!(f, "X"),
7880
LtlUnaryOp::StrongNext => write!(f, "X[!]"),
7981
LtlUnaryOp::Finally => write!(f, "F"),
@@ -88,6 +90,9 @@ mod test {
8890

8991
#[test]
9092
fn string_try_into_unary_op() {
93+
let parsed = "!".try_into();
94+
assert_eq!(parsed, Ok(LtlUnaryOp::Not));
95+
9196
let parsed = "X".try_into();
9297
assert_eq!(parsed, Ok(LtlUnaryOp::WeakNext));
9398

@@ -105,7 +110,7 @@ mod test {
105110
}
106111

107112
#[test]
108-
fn binary_op_display_then_parse_is_ident() {
113+
fn unary_op_display_then_parse_is_ident() {
109114
for op in LtlUnaryOp::all() {
110115
assert_eq!(Ok(op), format!("{op}").as_str().try_into())
111116
}

0 commit comments

Comments
 (0)