Class FormulaStrengthening
- java.lang.Object
-
- owl.ltl.visitors.FormulaStrengthening
-
- All Implemented Interfaces:
Function<owl.ltl.Formula,owl.ltl.Formula>,owl.ltl.visitors.Visitor<owl.ltl.Formula>
public class FormulaStrengthening extends Object implements owl.ltl.visitors.Visitor<owl.ltl.Formula>
The strengthening mutation mode of AuRUS: rewrites an LTL formula (in negation normal form) into a semantically stronger one, i.e. a formula φs such that φs ⊨ φ — no new model is introduced by the rewrite. Applied to a guarantee, this tightens an obligation on the system — the default direction for guarantee mutations, since unrealisability most often originates there (seegeneticalgorithm.SpecificationMutator). SeeFormulaWeakeningfor the dual mode; the two classes are structural mirrors of each other, operator for operator.This class implements the strengthening rules of Table 4.1 in the paper and thesis this project is the reference implementation of (one
visitmethod per LTL operator, one rewrite rule per numberedoption); see the individualvisitmethods below for the correspondence. The two additional operatorsM(strong release) andR(release) are handled via their standard dualities withU/W(noted inline) rather than appearing as separate rows in the thesis table.How mutation is applied. This is a recursive
Visitor: it walks the formula bottom-up, and at every node — not just the root — it may independently roll the dice to strengthen that node. Two knobs control this, both threaded through the constructor, mirroringFormulaWeakening:strengthening_rate(per-node mutation probability1/strengthening_rate) andnumOfAllowedStrengthenings(a mutable budget of remaining mutations, decremented on each applied change).Bloat guard. As in
FormulaWeakening, severalvisitmethods count the number of temporal operators in the (already partially rewritten) current formula and abandon further strengthening of that node — returning the original sub-formula — once the count exceeds2.Universal strongest bound. At every node, one of the random options is simply
false— the strongest possible formula — giving the search a way to discard a sub-formula's satisfiability entirely.A note on soundness of the fallback rules. As with
FormulaWeakening, most rules below are sound by construction. The unrolling fallback branches ofvisit(UOperator),visit(FOperator)(option 7) and their siblings, which introduce a fresh draw vianew_literal(Formula), share the same caveat documented there: the drawn proposition is taken from the same fixed alphabet as the rest of the specification, not a logically fresh variable, so these particular branches are heuristic exploration rather than guaranteed entailments for every possible draw.Part of the reference implementation of: Brizzio, Cordy, Papadakis, Sánchez, Aguirre, Degiovanni. "Automated Repair of Unrealisable LTL Specifications Guided by Model Counting", GECCO 2023 (doi:10.1145/3583131.3590454).
- Author:
- Matías Brizzio
- See Also:
FormulaWeakening,GeneralFormulaMutator
-
-
Constructor Summary
Constructors Constructor Description FormulaStrengthening(List<String> literals, int strengthening_rate, int num_of_strengthening_to_apply)Creates a strengthening visitor over the given variable alphabet.
-
Method Summary
All Methods Instance Methods Concrete Methods Modifier and Type Method Description owl.ltl.Formulaapply(owl.ltl.Formula formula)Entry point: applies this visitor to the root of the given formula.owl.ltl.Literalnew_literal(owl.ltl.Formula current)Picks a literal, from the specification's variable alphabet, to combine with a formula being strengthened.List<String>variables()owl.ltl.Formulavisit(owl.ltl.Biconditional biconditional)Rejected: the mutator only ever runs on formulas already converted to negation normal form.owl.ltl.Formulavisit(owl.ltl.BooleanConstant booleanConstant)Strengthens a boolean constant:true ⤳ false(the only possible strengthening of a constant;falseis already the strongest formula and is left untouched by the random draw).owl.ltl.Formulavisit(owl.ltl.Conjunction conjunction)Strengthens a conjunctiona1 ∧ ... ∧ an(recursing into every conjunct first) into one of:false(option 0); adding one more conjunct drawn from the alphabet,a1 ∧ a2 ⤳ a1 ∧ a2 ∧ c(option 1 — a conjunction can only become more demanding by adding conjuncts); or, when not already temporally heavy,G(a1 ∧ ... ∧ an)(option 2 — requiring the whole conjunction to hold forever rather than just now).owl.ltl.Formulavisit(owl.ltl.Disjunction disjunction)Strengthens a disjunctiona1 ∨ ... ∨ an(recursing into every disjunct first) into one of:false(option 0); turning the whole disjunction into a conjunction,a1 ∨ a2 ⤳ a1 ∧ a2(option 1 — Table 4.1's "conjunct" rule); dropping one randomly chosen disjunct,a1 ∨ a2 ⤳ a1(option 2 — narrowing which alternative is allowed); or, when not already temporally heavy,G(a1 ∨ ... ∨ an)(option 3 — requiring the disjunction to hold forever rather than just now).owl.ltl.Formulavisit(owl.ltl.FOperator fOperator)StrengthensF(a)(recursing intoafirst) into one of, drawn uniformly out of 8 outcomes:false(option 0);aitself (option 1 — requiring it now rather than eventually);X(a)(option 2 — requiring it at the very next step);G(a)(option 3 — requiring it forever, Table 4.1's strongest "eventually" tightening);F X(a)(option 4, guarded against runaway size — delaying by exactly one step);F G(a)(option 5, same guard — "eventually always", strictly implying plain "eventually");G F(a)(option 6, same guard — "infinitely often" is the valid strengthening direction of "eventually always", the mirror ofFormulaWeakening.visit(GOperator)'s weakening ofG Fdown toF G); ora U bfor a drawn literalb(option 7 — requiringato hold at least until some point, rather than merely eventually).owl.ltl.Formulavisit(owl.ltl.FrequencyG freq)Rejected: the mutator only ever runs on formulas already converted to negation normal form.owl.ltl.Formulavisit(owl.ltl.GOperator gOperator)StrengthensG(a)(recursing intoafirst) into one of, drawn uniformly out of 5 outcomes:false(option 0, default); distributing over a disjunction,G(a1 ∨ a2) ⤳ G(a1) ∨ G(a2)(option 1, only whenais a disjunction, via the disjunctive normal form of the operand — each disjunct is required to hold forever on its own, rather than the weaker requirement that some disjunct hold at each step);G F(b) ⤳ F G(b)(option 2, whena = F(b)— the valid strengthening direction noted above); simplifyingG X(b)down toG(b)(option 3, whena = X(b)— equivalent, since "always" already covers the next step); or simplifying the (already-idempotent)G G(b)down toG(b)(option 4, whenais itself aG-formula — a non-strict, equivalence-preserving simplification rather than a proper strengthening).owl.ltl.Formulavisit(owl.ltl.HOperator hOperator)Rejected: past-time operator, not expected in the LTL fragment this mutator handles.owl.ltl.Formulavisit(owl.ltl.Literal literal)Strengthens an atomic literalpinto one of, chosen uniformly at random:false(option 0);p ∧ qfor a fresh literalq(option 1 — Table 4.1's "add conjunct" rule); orG(p)(option 2 — "always" is stronger than "now").owl.ltl.Formulavisit(owl.ltl.MOperator mOperator)Strengthensa M b("strong release" — via the standard dualitya M b ≡ b U (a ∧ b), and its own unrolling≡ (a ∧ b) ∨ (b ∧ ¬(a ∧ b) ∧ X(b U (a ∧ b)))— recursing into both sides first) into one of:false(option 0);a ∧ b(option 1 — requiring the joint condition to hold now, the strongest immediate reading); orb ∧ ¬(a ∧ b) ∧ X(a M b)(option 2 — unrolling one step of the "strong release" obligation).owl.ltl.Formulavisit(owl.ltl.OOperator oOperator)Rejected: the mutator only ever runs on formulas already converted to negation normal form.owl.ltl.Formulavisit(owl.ltl.ROperator rOperator)Strengthensa R b("release" — via the standard dualitya R b ≡ b W (a ∧ b) ≡ G(b) ∨ (a M b)— recursing into both sides first) into one of:false(option 0);G(b)(option 1 — keeping only the "alwaysb" disjunct); ora M b(option 2 — keeping only the "strong release" disjunct, strictly stronger than the original release).owl.ltl.Formulavisit(owl.ltl.SOperator sOperator)Rejected: past-time operator, not expected in the LTL fragment this mutator handles.owl.ltl.Formulavisit(owl.ltl.TOperator tOperator)Rejected: past-time operator, not expected in the LTL fragment this mutator handles.owl.ltl.Formulavisit(owl.ltl.UOperator uOperator)Strengthensa U b(recursing into both sides first) via its unrollinga U b ≡ b ∨ (a ∧ ¬b ∧ X(a U b)), into one of:false(option 0);b(option 1 — requiring the eventual condition to hold now, dropping the "until" build-up entirely); or, when not already temporally heavy,a ∧ ¬b ∧ X(a U b)(option 2 — unrolling one step:amust hold now,bmust not yet, and the same obligation continues from the next step).owl.ltl.Formulavisit(owl.ltl.WOperator wOperator)Strengthensa W b(recursing into both sides first).owl.ltl.Formulavisit(owl.ltl.XOperator xOperator)StrengthensX(a)(recursing intoafirst) into one of:false(option 0, default);G(a)(option 1 — "always" from the next step on is stronger than a single "next"); or, whenais itselfG(b), simplifyingX G(b)down toG(b)(option 2 — equivalent, since "always from the next step" already implies "always").owl.ltl.Formulavisit(owl.ltl.YOperator yOperator)Rejected: past-time operator, not expected in the LTL fragment this mutator handles.owl.ltl.Formulavisit(owl.ltl.ZOperator zOperator)Rejected: past-time operator, not expected in the LTL fragment this mutator handles.
-
-
-
Constructor Detail
-
FormulaStrengthening
public FormulaStrengthening(List<String> literals, int strengthening_rate, int num_of_strengthening_to_apply)
Creates a strengthening visitor over the given variable alphabet.- Parameters:
literals- the specification's variable names, in index orderstrengthening_rate- per-node mutation probability is1/strengthening_ratenum_of_strengthening_to_apply- maximum number of sub-formulas this visitor may strengthen in one pass
-
-
Method Detail
-
variables
public List<String> variables()
- Returns:
- a defensive copy of the variable alphabet this visitor was built with
-
apply
public owl.ltl.Formula apply(owl.ltl.Formula formula)
Entry point: applies this visitor to the root of the given formula.
-
visit
public owl.ltl.Formula visit(owl.ltl.BooleanConstant booleanConstant)
Strengthens a boolean constant:true ⤳ false(the only possible strengthening of a constant;falseis already the strongest formula and is left untouched by the random draw).- Specified by:
visitin interfaceowl.ltl.visitors.Visitor<owl.ltl.Formula>
-
visit
public owl.ltl.Formula visit(owl.ltl.Literal literal)
Strengthens an atomic literalpinto one of, chosen uniformly at random:false(option 0);p ∧ qfor a fresh literalq(option 1 — Table 4.1's "add conjunct" rule); orG(p)(option 2 — "always" is stronger than "now").- Specified by:
visitin interfaceowl.ltl.visitors.Visitor<owl.ltl.Formula>
-
visit
public owl.ltl.Formula visit(owl.ltl.XOperator xOperator)
StrengthensX(a)(recursing intoafirst) into one of:false(option 0, default);G(a)(option 1 — "always" from the next step on is stronger than a single "next"); or, whenais itselfG(b), simplifyingX G(b)down toG(b)(option 2 — equivalent, since "always from the next step" already implies "always").- Specified by:
visitin interfaceowl.ltl.visitors.Visitor<owl.ltl.Formula>
-
visit
public owl.ltl.Formula visit(owl.ltl.FOperator fOperator)
StrengthensF(a)(recursing intoafirst) into one of, drawn uniformly out of 8 outcomes:false(option 0);aitself (option 1 — requiring it now rather than eventually);X(a)(option 2 — requiring it at the very next step);G(a)(option 3 — requiring it forever, Table 4.1's strongest "eventually" tightening);F X(a)(option 4, guarded against runaway size — delaying by exactly one step);F G(a)(option 5, same guard — "eventually always", strictly implying plain "eventually");G F(a)(option 6, same guard — "infinitely often" is the valid strengthening direction of "eventually always", the mirror ofFormulaWeakening.visit(GOperator)'s weakening ofG Fdown toF G); ora U bfor a drawn literalb(option 7 — requiringato hold at least until some point, rather than merely eventually).- Specified by:
visitin interfaceowl.ltl.visitors.Visitor<owl.ltl.Formula>
-
visit
public owl.ltl.Formula visit(owl.ltl.GOperator gOperator)
StrengthensG(a)(recursing intoafirst) into one of, drawn uniformly out of 5 outcomes:false(option 0, default); distributing over a disjunction,G(a1 ∨ a2) ⤳ G(a1) ∨ G(a2)(option 1, only whenais a disjunction, via the disjunctive normal form of the operand — each disjunct is required to hold forever on its own, rather than the weaker requirement that some disjunct hold at each step);G F(b) ⤳ F G(b)(option 2, whena = F(b)— the valid strengthening direction noted above); simplifyingG X(b)down toG(b)(option 3, whena = X(b)— equivalent, since "always" already covers the next step); or simplifying the (already-idempotent)G G(b)down toG(b)(option 4, whenais itself aG-formula — a non-strict, equivalence-preserving simplification rather than a proper strengthening).- Specified by:
visitin interfaceowl.ltl.visitors.Visitor<owl.ltl.Formula>
-
visit
public owl.ltl.Formula visit(owl.ltl.Conjunction conjunction)
Strengthens a conjunctiona1 ∧ ... ∧ an(recursing into every conjunct first) into one of:false(option 0); adding one more conjunct drawn from the alphabet,a1 ∧ a2 ⤳ a1 ∧ a2 ∧ c(option 1 — a conjunction can only become more demanding by adding conjuncts); or, when not already temporally heavy,G(a1 ∧ ... ∧ an)(option 2 — requiring the whole conjunction to hold forever rather than just now).- Specified by:
visitin interfaceowl.ltl.visitors.Visitor<owl.ltl.Formula>
-
visit
public owl.ltl.Formula visit(owl.ltl.Disjunction disjunction)
Strengthens a disjunctiona1 ∨ ... ∨ an(recursing into every disjunct first) into one of:false(option 0); turning the whole disjunction into a conjunction,a1 ∨ a2 ⤳ a1 ∧ a2(option 1 — Table 4.1's "conjunct" rule); dropping one randomly chosen disjunct,a1 ∨ a2 ⤳ a1(option 2 — narrowing which alternative is allowed); or, when not already temporally heavy,G(a1 ∨ ... ∨ an)(option 3 — requiring the disjunction to hold forever rather than just now).- Specified by:
visitin interfaceowl.ltl.visitors.Visitor<owl.ltl.Formula>
-
visit
public owl.ltl.Formula visit(owl.ltl.UOperator uOperator)
Strengthensa U b(recursing into both sides first) via its unrollinga U b ≡ b ∨ (a ∧ ¬b ∧ X(a U b)), into one of:false(option 0);b(option 1 — requiring the eventual condition to hold now, dropping the "until" build-up entirely); or, when not already temporally heavy,a ∧ ¬b ∧ X(a U b)(option 2 — unrolling one step:amust hold now,bmust not yet, and the same obligation continues from the next step).- Specified by:
visitin interfaceowl.ltl.visitors.Visitor<owl.ltl.Formula>
-
visit
public owl.ltl.Formula visit(owl.ltl.WOperator wOperator)
Strengthensa W b(recursing into both sides first). Recallinga W b ≡ G(a) ∨ (a U b), this collapses the disjunction to one side rather than weakening it:false(option 0);G(a)(option 1 — keeping only the "always" disjunct); ora U b(option 2 — keeping only the "until" disjunct, which additionally requiresbto eventually hold — strictly stronger than the original weak-until).- Specified by:
visitin interfaceowl.ltl.visitors.Visitor<owl.ltl.Formula>
-
visit
public owl.ltl.Formula visit(owl.ltl.MOperator mOperator)
Strengthensa M b("strong release" — via the standard dualitya M b ≡ b U (a ∧ b), and its own unrolling≡ (a ∧ b) ∨ (b ∧ ¬(a ∧ b) ∧ X(b U (a ∧ b)))— recursing into both sides first) into one of:false(option 0);a ∧ b(option 1 — requiring the joint condition to hold now, the strongest immediate reading); orb ∧ ¬(a ∧ b) ∧ X(a M b)(option 2 — unrolling one step of the "strong release" obligation).- Specified by:
visitin interfaceowl.ltl.visitors.Visitor<owl.ltl.Formula>
-
visit
public owl.ltl.Formula visit(owl.ltl.ROperator rOperator)
Strengthensa R b("release" — via the standard dualitya R b ≡ b W (a ∧ b) ≡ G(b) ∨ (a M b)— recursing into both sides first) into one of:false(option 0);G(b)(option 1 — keeping only the "alwaysb" disjunct); ora M b(option 2 — keeping only the "strong release" disjunct, strictly stronger than the original release).- Specified by:
visitin interfaceowl.ltl.visitors.Visitor<owl.ltl.Formula>
-
visit
public owl.ltl.Formula visit(owl.ltl.Biconditional biconditional)
Rejected: the mutator only ever runs on formulas already converted to negation normal form.- Specified by:
visitin interfaceowl.ltl.visitors.Visitor<owl.ltl.Formula>
-
visit
public owl.ltl.Formula visit(owl.ltl.FrequencyG freq)
Rejected: the mutator only ever runs on formulas already converted to negation normal form.- Specified by:
visitin interfaceowl.ltl.visitors.Visitor<owl.ltl.Formula>
-
visit
public owl.ltl.Formula visit(owl.ltl.OOperator oOperator)
Rejected: the mutator only ever runs on formulas already converted to negation normal form.- Specified by:
visitin interfaceowl.ltl.visitors.Visitor<owl.ltl.Formula>
-
visit
public owl.ltl.Formula visit(owl.ltl.HOperator hOperator)
Rejected: past-time operator, not expected in the LTL fragment this mutator handles.- Specified by:
visitin interfaceowl.ltl.visitors.Visitor<owl.ltl.Formula>
-
visit
public owl.ltl.Formula visit(owl.ltl.TOperator tOperator)
Rejected: past-time operator, not expected in the LTL fragment this mutator handles.- Specified by:
visitin interfaceowl.ltl.visitors.Visitor<owl.ltl.Formula>
-
visit
public owl.ltl.Formula visit(owl.ltl.SOperator sOperator)
Rejected: past-time operator, not expected in the LTL fragment this mutator handles.- Specified by:
visitin interfaceowl.ltl.visitors.Visitor<owl.ltl.Formula>
-
visit
public owl.ltl.Formula visit(owl.ltl.YOperator yOperator)
Rejected: past-time operator, not expected in the LTL fragment this mutator handles.- Specified by:
visitin interfaceowl.ltl.visitors.Visitor<owl.ltl.Formula>
-
visit
public owl.ltl.Formula visit(owl.ltl.ZOperator zOperator)
Rejected: past-time operator, not expected in the LTL fragment this mutator handles.- Specified by:
visitin interfaceowl.ltl.visitors.Visitor<owl.ltl.Formula>
-
new_literal
public owl.ltl.Literal new_literal(owl.ltl.Formula current)
Picks a literal, from the specification's variable alphabet, to combine with a formula being strengthened. MirrorsFormulaWeakening.new_literal(Formula): tries (up to 5 attempts) to avoid a variable already appearing incurrent, then negates the result with 50% probability. Not a logically fresh Skolem variable — see the class-level soundness caveat.- Parameters:
current- the formula being strengthened, used only to bias the draw away from its own propositions- Returns:
- a literal (possibly negated) from the variable alphabet
-
-