Class FormulaWeakening
- java.lang.Object
-
- owl.ltl.visitors.FormulaWeakening
-
- All Implemented Interfaces:
Function<owl.ltl.Formula,owl.ltl.Formula>,owl.ltl.visitors.Visitor<owl.ltl.Formula>
public class FormulaWeakening extends Object implements owl.ltl.visitors.Visitor<owl.ltl.Formula>
The weakening mutation mode of AuRUS: rewrites an LTL formula (in negation normal form) into a semantically weaker one, i.e. a formula φw such that φ ⊨ φw — every model of the original formula survives the rewrite. Applied to an assumption, this relaxes a constraint on the environment; seeFormulaStrengtheningfor the dual mode, andgeneticalgorithm.SpecificationMutatorfor how the two are selected during the search.This class implements the weakening 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 weaken that node. Two knobs control this, both threaded through the constructor:weakening_rate— the per-node mutation probability is1/weakening_rate(a freshRandom.nextInt(weakening_rate) == 0roll at each node); seeSpecificationMutator.weakenFormula, which derives this fromSettings.GA_GENE_MUTATION_RATE.numOfAllowedWeakening— a mutable budget, decremented every time a node is actually weakened; once it reaches0, no further node is touched, bounding how many changes one mutation call can make to a single formula.
Bloat guard. Several
visitmethods count the number of temporal operators in the (already partially rewritten) current formula and abandon further weakening of that node — returning the original, unweakened sub-formula — once the count exceeds2. This keeps mutated formulas from growing without bound, the classic bloat problem in genetic-programming-style search.Universal weakest bound. At every node, one of the random options is simply
true— the weakest possible formula — giving the search a way to discard a sub-formula entirely regardless of its shape.A note on soundness of the fallback rules. Most rules below are the same directed rewrites as the thesis table and are sound by construction (entailment-preserving for every substitution of the variables involved). A few fallback branches — e.g. the last option of
visit(FOperator),visit(UOperator)andvisit(WOperator), which combine the current formula with a freshly drawn, but not fresh in the logical sense, existing proposition vianew_literal(Formula)— are not guaranteed entailments for every possible choice of that proposition (e.g.F(a) ⊨ c W adoes not hold for everyc). These branches are best understood as heuristic exploration in the spirit of the undirected general mutation, injected into the weakening operator for extra diversity; any resulting semantic drift is caught downstream by the fitness function's semantic-similarity component, not by this class.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:
FormulaStrengthening,GeneralFormulaMutator
-
-
Constructor Summary
Constructors Constructor Description FormulaWeakening(List<String> literals, int weakening_rate, int num_of_weakening_to_apply)Creates a weakening 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 weakened — used by the "add disjunct" / "widen the until" style rules above.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)Weakens a boolean constant:false ⤳ true(the only possible weakening of a constant;trueis already the weakest formula and is left untouched by the random draw).owl.ltl.Formulavisit(owl.ltl.Conjunction conjunction)Weakens a conjunctiona1 ∧ ... ∧ an(recursing into every conjunct first) into one of:true(option 0); dropping one randomly chosen conjunct,a1 ∧ a2 ⤳ a1(option 1 — Table 4.1's "drop conjunct" rule); turning the whole conjunction into a disjunction,a1 ∧ a2 ⤳ a1 ∨ a2(option 2); or, when the formula is not already temporally heavy,F(a1 ∧ ... ∧ an)(option 3 — postponing the whole conjunction rather than requiring it now).owl.ltl.Formulavisit(owl.ltl.Disjunction disjunction)Weakens a disjunctiona1 ∨ ... ∨ an(recursing into every disjunct first) into one of:true(option 0); or adding one more disjunct drawn from the alphabet,a1 ∨ a2 ⤳ a1 ∨ a2 ∨ c(option 1 — a disjunction can only grow more permissive by adding disjuncts).owl.ltl.Formulavisit(owl.ltl.FOperator fOperator)WeakensF(a)(recursing intoafirst) into one of, drawn uniformly out of 6 outcomes:true(option 0, default); distributing over a conjunction,F(a1 ∧ a2) ⤳ F(a1) ∧ F(a2)(option 1, only whenais a conjunction — each conjunct is allowed to happen at its own time rather than simultaneously);F G(b) ⤳ G F(b)(option 2, whena = G(b)— the classic valid LTL implication "eventually always" ⇒ "infinitely often");F X(b) ⤳ F(b)(option 3, whena = X(b)— dropping the extra step of delay);F G(b) ⤳ F(b)(option 4, whena = G(b)— a second, independent weakening applicable to the sameF G(b)shape as option 2, this one discarding the "forever" and keeping only the first occurrence); or, as the fallback for every other case,F(a) ⤳ (c W a)for a drawn literalc(option 5 and any option whose structural guard failed) — see the class-level caveat about this fallback's soundness.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)WeakensG(a)(recursing intoafirst) into one of, drawn uniformly out of 7 outcomes:true(option 0);aitself (option 1 — dropping "always" entirely, Table 4.1's "identity" row);F(a)(option 2 — "always" implies "eventually");X(a)(option 3 — "always" implies "next");G F(a)(option 4, only when the formula so far has at most one other temporal operator — "always" implies "infinitely often");F G(a)(option 5, same guard — "always" implies "eventually always", the classic valid direction); orX G(a)(option 6 — delaying the "always" by one step is itself a weakening).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)Weakens an atomic literalpinto one of, chosen uniformly at random:true(option 0);p ∨ qfor a fresh literalq(option 1 — Table 4.1's "add disjunct" rule); orF(p)(option 2 — "eventually" is weaker than "now").owl.ltl.Formulavisit(owl.ltl.MOperator mOperator)Weakensa M b("strong release" — via the standard dualitya M b ≡ b U (a ∧ b)— recursing into both sides first) into one of:true(option 0);b W (a ∧ b)(option 1 — the weak-until relaxation of the duality above, dropping the requirement thata ∧ beventually hold); orF(a ∧ b)(option 2 — keeping only the eventual joint 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)Weakensa R b("release" — via the standard dualitya R b ≡ b W (a ∧ b)— recursing into both sides first) into one of:true(option 0);F(b) ∨ (b U (a ∧ b))(option 1 — relaxing the "alwaysb" disjunct of the weak-until expansion down to a bare "eventuallyb"); orG(b) ∨ F(a ∧ b)(option 2 — relaxing the "until" disjunct down to a bare "eventually" joint obligation).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)Weakensa U b("aholds untilb", recursing into both sides first) into one of:true(option 0);a W b(option 1 — the weak-until Table 4.1 rule:bno longer needs to eventually hold);(a ∨ c) U bfor a drawn literalc(option 2 — widening what may hold while waiting forb); orF(b)(option 3 — keeping only the eventual obligation, dropping the "until" precondition ona).owl.ltl.Formulavisit(owl.ltl.WOperator wOperator)Weakensa W b("aholds unless/untilb", recursing into both sides first).owl.ltl.Formulavisit(owl.ltl.XOperator xOperator)WeakensX(a)(recursing intoafirst) into one of:true(option 0, default);F(a)(option 1 — dropping the "next" timing keeps only "eventually"); or, whenais itselfF(b), simplifyingX F(b)down toF(b)(option 2 — "eventually" already absorbs one step of delay).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
-
FormulaWeakening
public FormulaWeakening(List<String> literals, int weakening_rate, int num_of_weakening_to_apply)
Creates a weakening visitor over the given variable alphabet.- Parameters:
literals- the specification's variable names, in index orderweakening_rate- per-node mutation probability is1/weakening_ratenum_of_weakening_to_apply- maximum number of sub-formulas this visitor may weaken 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)
Weakens a boolean constant:false ⤳ true(the only possible weakening of a constant;trueis already the weakest 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)
Weakens an atomic literalpinto one of, chosen uniformly at random:true(option 0);p ∨ qfor a fresh literalq(option 1 — Table 4.1's "add disjunct" rule); orF(p)(option 2 — "eventually" is weaker than "now").- Specified by:
visitin interfaceowl.ltl.visitors.Visitor<owl.ltl.Formula>
-
visit
public owl.ltl.Formula visit(owl.ltl.XOperator xOperator)
WeakensX(a)(recursing intoafirst) into one of:true(option 0, default);F(a)(option 1 — dropping the "next" timing keeps only "eventually"); or, whenais itselfF(b), simplifyingX F(b)down toF(b)(option 2 — "eventually" already absorbs one step of delay).- Specified by:
visitin interfaceowl.ltl.visitors.Visitor<owl.ltl.Formula>
-
visit
public owl.ltl.Formula visit(owl.ltl.FOperator fOperator)
WeakensF(a)(recursing intoafirst) into one of, drawn uniformly out of 6 outcomes:true(option 0, default); distributing over a conjunction,F(a1 ∧ a2) ⤳ F(a1) ∧ F(a2)(option 1, only whenais a conjunction — each conjunct is allowed to happen at its own time rather than simultaneously);F G(b) ⤳ G F(b)(option 2, whena = G(b)— the classic valid LTL implication "eventually always" ⇒ "infinitely often");F X(b) ⤳ F(b)(option 3, whena = X(b)— dropping the extra step of delay);F G(b) ⤳ F(b)(option 4, whena = G(b)— a second, independent weakening applicable to the sameF G(b)shape as option 2, this one discarding the "forever" and keeping only the first occurrence); or, as the fallback for every other case,F(a) ⤳ (c W a)for a drawn literalc(option 5 and any option whose structural guard failed) — see the class-level caveat about this fallback's soundness.- Specified by:
visitin interfaceowl.ltl.visitors.Visitor<owl.ltl.Formula>
-
visit
public owl.ltl.Formula visit(owl.ltl.GOperator gOperator)
WeakensG(a)(recursing intoafirst) into one of, drawn uniformly out of 7 outcomes:true(option 0);aitself (option 1 — dropping "always" entirely, Table 4.1's "identity" row);F(a)(option 2 — "always" implies "eventually");X(a)(option 3 — "always" implies "next");G F(a)(option 4, only when the formula so far has at most one other temporal operator — "always" implies "infinitely often");F G(a)(option 5, same guard — "always" implies "eventually always", the classic valid direction); orX G(a)(option 6 — delaying the "always" by one step is itself a weakening).- Specified by:
visitin interfaceowl.ltl.visitors.Visitor<owl.ltl.Formula>
-
visit
public owl.ltl.Formula visit(owl.ltl.Conjunction conjunction)
Weakens a conjunctiona1 ∧ ... ∧ an(recursing into every conjunct first) into one of:true(option 0); dropping one randomly chosen conjunct,a1 ∧ a2 ⤳ a1(option 1 — Table 4.1's "drop conjunct" rule); turning the whole conjunction into a disjunction,a1 ∧ a2 ⤳ a1 ∨ a2(option 2); or, when the formula is not already temporally heavy,F(a1 ∧ ... ∧ an)(option 3 — postponing the whole conjunction rather than requiring it now).- Specified by:
visitin interfaceowl.ltl.visitors.Visitor<owl.ltl.Formula>
-
visit
public owl.ltl.Formula visit(owl.ltl.Disjunction disjunction)
Weakens a disjunctiona1 ∨ ... ∨ an(recursing into every disjunct first) into one of:true(option 0); or adding one more disjunct drawn from the alphabet,a1 ∨ a2 ⤳ a1 ∨ a2 ∨ c(option 1 — a disjunction can only grow more permissive by adding disjuncts).- Specified by:
visitin interfaceowl.ltl.visitors.Visitor<owl.ltl.Formula>
-
visit
public owl.ltl.Formula visit(owl.ltl.UOperator uOperator)
Weakensa U b("aholds untilb", recursing into both sides first) into one of:true(option 0);a W b(option 1 — the weak-until Table 4.1 rule:bno longer needs to eventually hold);(a ∨ c) U bfor a drawn literalc(option 2 — widening what may hold while waiting forb); orF(b)(option 3 — keeping only the eventual obligation, dropping the "until" precondition ona).- Specified by:
visitin interfaceowl.ltl.visitors.Visitor<owl.ltl.Formula>
-
visit
public owl.ltl.Formula visit(owl.ltl.WOperator wOperator)
Weakensa W b("aholds unless/untilb", recursing into both sides first). Recalling thata W b ≡ G(a) ∨ (a U b), this weakens one of the two disjuncts at a time:true(option 0);F(a) ∨ (a U b)(option 1 — relaxing the "always" disjunct down to "eventually");G(a) ∨ F(b)(option 2 — relaxing the "until" disjunct down to a bare "eventually"); or(a ∨ c) W bfor a drawn literalc(option 3 — widening what may hold throughout).- Specified by:
visitin interfaceowl.ltl.visitors.Visitor<owl.ltl.Formula>
-
visit
public owl.ltl.Formula visit(owl.ltl.MOperator mOperator)
Weakensa M b("strong release" — via the standard dualitya M b ≡ b U (a ∧ b)— recursing into both sides first) into one of:true(option 0);b W (a ∧ b)(option 1 — the weak-until relaxation of the duality above, dropping the requirement thata ∧ beventually hold); orF(a ∧ b)(option 2 — keeping only the eventual joint obligation).- Specified by:
visitin interfaceowl.ltl.visitors.Visitor<owl.ltl.Formula>
-
visit
public owl.ltl.Formula visit(owl.ltl.ROperator rOperator)
Weakensa R b("release" — via the standard dualitya R b ≡ b W (a ∧ b)— recursing into both sides first) into one of:true(option 0);F(b) ∨ (b U (a ∧ b))(option 1 — relaxing the "alwaysb" disjunct of the weak-until expansion down to a bare "eventuallyb"); orG(b) ∨ F(a ∧ b)(option 2 — relaxing the "until" disjunct down to a bare "eventually" joint obligation).- 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 weakened — used by the "add disjunct" / "widen the until" style rules above. Tries (up to 5 attempts) to avoid a variable already appearing (positively or negatively) incurrent, then negates the result with 50% probability. Note this is not a logically fresh Skolem variable: it is drawn from the same fixed, finite alphabet as every other proposition in the specification, which is what underlies the soundness caveat discussed in the class documentation.- Parameters:
current- the formula being weakened, used only to bias the draw away from its own propositions- Returns:
- a literal (possibly negated) from the variable alphabet
-
-