Skip to content

Commit

Permalink
feat: implement "true" formula terminal (#384)
Browse files Browse the repository at this point in the history
### Description

<!--Add a description of your PR here-->

### QC
<!-- Make sure that you can tick the boxes below. -->

* [x] The PR contains a test case for the changes or the changes are
already covered by an existing test case.
* [x] The documentation at
https://github.com/varlociraptor/varlociraptor.github.io is updated in a
separate PR to reflect the changes or this is not necessary (e.g. if the
change does neither modify the calling grammar nor the behavior or
functionalities of Varlociraptor).
  • Loading branch information
johanneskoester committed Jun 28, 2023
1 parent 9a24e3f commit fc45604
Show file tree
Hide file tree
Showing 4 changed files with 48 additions and 11 deletions.
3 changes: 2 additions & 1 deletion src/grammar/formula.pest
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ vafdef = _{ vaf | vafrange | vafset }
vafrange = { bound ~ vaf ~ "," ~ vaf ~ bound }
vafset = { "{" ~ vaf ~ ("," ~ vaf)+ ~ "}" }

formula = _{ SOI ~ (conjunction | disjunction | negation | sample_vafdef | variant | expression | cmp | lfc | false_literal) ~ EOI }
formula = _{ SOI ~ (conjunction | disjunction | negation | sample_vafdef | variant | expression | cmp | lfc | false_literal | true_literal) ~ EOI }
conjunction = { subformula ~ ( "&" ~ subformula )+ }
disjunction = { subformula ~ ( "|" ~ subformula )+ }
negation = { "!" ~ subformula }
Expand All @@ -16,6 +16,7 @@ expression = { "$" ~ identifier }
identifier = { (ASCII_ALPHANUMERIC | "_" | "-" | ".")+ }
variant = { iupac ~ ">" ~ iupac }
false_literal = { "false" }
true_literal = { "true" }

cmp_ops = { ("<=" | "<" | ">=" | ">" | "!=" | "==" ) }
cmp = { identifier ~ cmp_ops ~ identifier }
Expand Down
52 changes: 42 additions & 10 deletions src/grammar/formula.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ impl From<NormalizedFormula> for Formula {
refbase,
}),
NormalizedFormula::False => Formula::Terminal(FormulaTerminal::False),
NormalizedFormula::True => Formula::Terminal(FormulaTerminal::True),
NormalizedFormula::Log2FoldChange {
sample_a,
sample_b,
Expand Down Expand Up @@ -119,6 +120,7 @@ pub(crate) enum FormulaTerminal {
predicate: Log2FoldChangePredicate,
},
False,
True,
}

impl FormulaTerminal {
Expand Down Expand Up @@ -216,6 +218,7 @@ impl std::fmt::Display for Formula {

let formatted = match self {
Formula::Terminal(FormulaTerminal::False) => "false".to_owned(),
Formula::Terminal(FormulaTerminal::True) => "true".to_owned(),
Formula::Terminal(FormulaTerminal::Atom {
sample,
vafs: VAFSpectrum::Set(vafs),
Expand Down Expand Up @@ -360,7 +363,7 @@ impl From<Expr<FormulaTerminal>> for Formula {
},
},
Expr::Const(false) => Formula::Terminal(FormulaTerminal::False),
_ => panic!("bug: unexpected boolean expression containing constant"),
Expr::Const(true) => Formula::Terminal(FormulaTerminal::True),
}
}
}
Expand All @@ -370,6 +373,9 @@ impl Into<Expr<FormulaTerminal>> for Formula {
if self.is_terminal_false() {
return Expr::Const(false);
}
if self.is_terminal_true() {
return Expr::Const(true);
}
match self {
Formula::Terminal(terminal) => Expr::Terminal(terminal),
Formula::Conjunction { mut operands } => {
Expand Down Expand Up @@ -413,6 +419,15 @@ impl Formula {
}
}

/// Return true if this formula is a terminal that is always true (an full VAF range or "true").
pub(crate) fn is_terminal_true(&self) -> bool {
match self {
Formula::Terminal(FormulaTerminal::Atom { vafs, .. }) => vafs.is_complete(),
Formula::Terminal(FormulaTerminal::True) => true,
_ => false,
}
}

pub(crate) fn into_terminal(self) -> Option<FormulaTerminal> {
if let Formula::Terminal(terminal) = self {
Some(terminal)
Expand Down Expand Up @@ -550,6 +565,7 @@ impl Formula {
panic!("bug: negations should have been applied before normalization")
}
Formula::Terminal(FormulaTerminal::False) => NormalizedFormula::False,
Formula::Terminal(FormulaTerminal::True) => NormalizedFormula::True,
Formula::Terminal(FormulaTerminal::Log2FoldChange {
sample_a,
sample_b,
Expand Down Expand Up @@ -602,6 +618,7 @@ impl Formula {
}
}
}

let operands = grouped_operands
.into_iter()
.map(|(_, statements)| statements)
Expand Down Expand Up @@ -667,12 +684,12 @@ impl Formula {
}
}
}
Formula::Disjunction {
operands: grouped_operands
.into_iter()
.flat_map(|(_, statements)| statements)
.collect(),
}
let operands = grouped_operands
.into_iter()
.flat_map(|(_, statements)| statements)
.collect();

Formula::Disjunction { operands }
}
Formula::Negation { operand } => Formula::Negation {
operand: Box::new(operand.merge_atoms()),
Expand Down Expand Up @@ -709,9 +726,8 @@ impl Formula {
/// Negate formula.
fn negate(&self, scenario: &Scenario, contig: &str) -> Result<Self> {
Ok(match self {
Formula::Terminal(FormulaTerminal::False) => {
panic!("bug: negation not implemented for false terminal (you cannot use false in a negated statement in the grammar).")
}
Formula::Terminal(FormulaTerminal::False) => Formula::Terminal(FormulaTerminal::True),
Formula::Terminal(FormulaTerminal::True) => Formula::Terminal(FormulaTerminal::False),
Formula::Conjunction { operands } => Formula::Disjunction {
operands: operands
.iter()
Expand Down Expand Up @@ -858,6 +874,7 @@ impl Formula {
})
}

/// Move Negation operators into the atoms.
fn apply_negations(&self, scenario: &Scenario, contig: &str) -> Result<Self> {
Ok(match self {
Formula::Negation { operand } => operand
Expand Down Expand Up @@ -899,6 +916,7 @@ impl Formula {
panic!("bug: expressions should be expanded before applying negations");
}
Formula::Terminal(FormulaTerminal::False) => Formula::Terminal(FormulaTerminal::False),
Formula::Terminal(FormulaTerminal::True) => Formula::Terminal(FormulaTerminal::True),
Formula::Terminal(FormulaTerminal::Log2FoldChange {
sample_a,
sample_b,
Expand Down Expand Up @@ -935,6 +953,7 @@ pub(crate) enum NormalizedFormula {
predicate: Log2FoldChangePredicate,
},
False,
True,
}

impl std::fmt::Debug for NormalizedFormula {
Expand Down Expand Up @@ -993,6 +1012,7 @@ impl std::fmt::Display for NormalizedFormula {
operands.iter().map(&fmt_operand).join(" | ")
}
NormalizedFormula::False => "false".to_owned(),
NormalizedFormula::True => "true".to_owned(),
NormalizedFormula::Log2FoldChange {
sample_a,
sample_b,
Expand Down Expand Up @@ -1035,6 +1055,13 @@ impl VAFSpectrum {
VAFSpectrum::Range(range) => range.is_empty(),
}
}

pub(crate) fn is_complete(&self) -> bool {
match self {
VAFSpectrum::Set(_) => false,
VAFSpectrum::Range(range) => range.is_complete(),
}
}
}

#[derive(Clone, Debug, PartialEq, Eq, TypedBuilder, Hash, CopyGetters)]
Expand Down Expand Up @@ -1069,6 +1096,10 @@ impl VAFRange {
self.start == self.end && (self.left_exclusive || self.right_exclusive)
}

pub(crate) fn is_complete(&self) -> bool {
*self.start == 0.0 && *self.end == 1.0 && !self.left_exclusive && !self.right_exclusive
}

pub(crate) fn is_singleton(&self) -> bool {
self.start == self.end && !(self.left_exclusive || self.right_exclusive)
}
Expand Down Expand Up @@ -1505,6 +1536,7 @@ where
})
}
Rule::false_literal => Formula::Terminal(FormulaTerminal::False),
Rule::true_literal => Formula::Terminal(FormulaTerminal::True),
Rule::cmp_ops => unreachable!(),
Rule::formula => unreachable!(),
Rule::subformula => unreachable!(),
Expand Down
3 changes: 3 additions & 0 deletions src/grammar/vaftree.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ pub(crate) enum NodeKind {
predicate: Log2FoldChangePredicate,
},
False,
True,
}

#[derive(new, Clone, Debug, PartialEq, Eq, Getters, Hash)]
Expand Down Expand Up @@ -143,6 +144,7 @@ impl Node {
lfc_found
}
NodeKind::False => false,
NodeKind::True => true,
NodeKind::Variant { .. } => true,
};
if self.children.is_empty() {
Expand Down Expand Up @@ -220,6 +222,7 @@ impl VAFTree {
altbase,
})]),
NormalizedFormula::False => Ok(vec![Node::new(NodeKind::False)]),
NormalizedFormula::True => Ok(vec![Node::new(NodeKind::True)]),
NormalizedFormula::Log2FoldChange {
sample_a,
sample_b,
Expand Down
1 change: 1 addition & 0 deletions src/variants/model/modes/generic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,7 @@ impl GenericPosterior {
subdensity(likelihood_operands)
}
grammar::vaftree::NodeKind::False => LogProb::ln_zero(),
grammar::vaftree::NodeKind::True => LogProb::ln_one(),
grammar::vaftree::NodeKind::Sample { sample, vafs } => {
let push_base_event =
|allele_freq, likelihood_operands: &mut LikelihoodOperands, is_discrete| {
Expand Down

0 comments on commit fc45604

Please sign in to comment.