def one_in_post(self) -> mona.Formula: substitution = {v: Variable(self.system, f"substitute_{v.name}") for v in self.quantified_variables} try: renamed_broadcast = self.normalize(substitution) except FormulaError: raise FormulaError("Cannot generate formula for non-normalized" + " Broadcast {self}") pos_variables = sorted([cast(mona.Variable, v.as_mona()) for v in self.quantified_variables], key=str) pos_guard = self.guard_as_mona() neg_variables = sorted([ cast(mona.Variable, v.as_mona()) for v in renamed_broadcast.quantified_variables], key=str) neg_guard = renamed_broadcast.guard_as_mona() inner = mona.UniversalFirstOrder( neg_variables, mona.Implication( mona.Conjunction( [neg_guard, mona.Disjunction([ p.hit_post() for p in renamed_broadcast.body.predicates])]), mona.Equal(cast(mona.Variable, substitution[self.variable].as_mona()), cast(mona.Variable, self.variable.as_mona())))) outer = mona.ExistentialFirstOrder( pos_variables, mona.Conjunction([pos_guard] + [p.hit_post() for p in self.body.predicates] + [inner])) return outer
def unique_intersection_predicate(self) -> mona.Formula: x = mona.Variable("x") y = mona.Variable("y") one_states = [mona.Variable(f"one{s}") for s in self.system.states] two_states = [mona.Variable(f"two{s}") for s in self.system.states] pairs = list(zip(one_states, two_states)) statements: List[mona.Formula] = [] # fix x in intersection of one state: for pair in pairs: pos = [cast(mona.Formula, mona.ElementIn(x, state)) for state in pair] different_pairs = [p for p in pairs if p != pair] neg = [ # negated statement from above cast(mona.Formula, mona.Negation( mona.Conjunction( [mona.ElementIn(x, state) for state in pair]))) # for all other pairs for pair in different_pairs] statements.append(mona.Conjunction(pos + neg)) fix_x = mona.Disjunction(statements) # make sure x is unique: # y is in intersection y_in_intersection = mona.Disjunction([ mona.Conjunction([mona.ElementIn(y, state) for state in pair]) for pair in pairs]) # y is x if y is in intersection unique_x = mona.UniversalFirstOrder( [y], mona.Implication(y_in_intersection, mona.Equal(x, y))) formula = mona.ExistentialFirstOrder([x], mona.Conjunction([fix_x, unique_x])) return mona.PredicateDefinition( "unique_intersection", one_states + two_states, [], formula).simplify()
def uniquely_intersects_initial_predicate(self) -> mona.Formula: x = mona.Variable("x") y = mona.Variable("y") initial_states = [mona.Variable(c.initial_state) for c in self.system.components] statements: List[mona.Formula] = [] for init in initial_states: other_initial_states = [i for i in initial_states if i != init] x_only_in_init = mona.Conjunction( [cast(mona.Formula, mona.ElementIn(x, init))] + [cast(mona.Formula, mona.ElementNotIn(x, i)) for i in other_initial_states]) statements.append(x_only_in_init) x_in_only_one_initial = mona.Disjunction(statements) y_in_initial = mona.Disjunction( [mona.ElementIn(y, i) for i in initial_states]) x_unique = mona.UniversalFirstOrder([y], mona.Implication( y_in_initial, mona.Equal(x, y))) formula = mona.ExistentialFirstOrder( [x], mona.Conjunction([x_in_only_one_initial, x_unique])) return mona.PredicateDefinition( "uniquely_intersects_initial", self.system.state_variables, [], formula).simplify()
def as_mona(self): left = self.left.as_mona() right = self.right.as_mona() return mona.Equal(left, right)