def mcf_or(modal_context, fml, clausal_form_dict, id_mc): """ Takes OR fml, and applies transformation rules. """ global max_mc_id mcf_dict_key = len(modal_context) modal_context_clauses = False # modal context does not distribute over the 'or' operator left_fml = fml[1] right_fml = fml[2] # if both formulas are simple, add to context if not u.is_complex(left_fml) or not u.is_complex(right_fml): if not u.is_complex(left_fml) and not u.is_complex(right_fml): to_mcf(modal_context, left_fml, clausal_form_dict, id_mc) to_mcf(modal_context, right_fml, clausal_form_dict, id_mc) else: # one of the formulas must be complex - &, | or modality if u.is_complex(right_fml): complex_fml = right_fml simple_fml = left_fml else: complex_fml = left_fml simple_fml = right_fml # check simple_fml is only other conjunct in context if mcf_dict_key in clausal_form_dict: modal_context_clauses = eq_modal_context( modal_context, id_mc, clausal_form_dict[mcf_dict_key]) complex_fml_connective = complex_fml[0] if repr(complex_fml_connective) == '|' or modal_context_clauses: to_mcf(modal_context, simple_fml, clausal_form_dict, id_mc) to_mcf(modal_context, complex_fml, clausal_form_dict, id_mc) elif repr(complex_fml_connective) == '&': # simple_fml is only other conjunct in context therefore apply de morgans com_left_fml = complex_fml[1] com_right_fml = complex_fml[2] to_mcf(modal_context, [ u.op('&'), [u.op('|'), simple_fml, com_left_fml], [u.op('|'), simple_fml, com_right_fml] ], clausal_form_dict, id_mc) elif isinstance(complex_fml_connective, parser.Modality): # simple_fml is only other conjunct in context to_mcf(modal_context, simple_fml, clausal_form_dict, id_mc) to_mcf(modal_context, complex_fml, clausal_form_dict, id_mc, False) else: mcf_error(modal_context, fml, clausal_form_dict, id_mc) else: # both arguments are complex sub formulas to_mcf(modal_context, left_fml, clausal_form_dict, id_mc, True) to_mcf(modal_context, right_fml, clausal_form_dict, id_mc, True)
def get_bool(atom): """ :param atom: parsed classical atom, can be negated :return z3 appropriate boolean value """ assert not is_complex(atom), "Error adding atom to sat solver: %s" % atom # need to account for 'False' and 'True' if is_atomic(atom): if atom == TOP: return True elif atom == BOTTOM: return False else: return Bool(str(atom)) elif str(atom[0]) == '~': if atom[1] == TOP: return False elif atom[1] == BOTTOM: return True else: return Not(Bool(str(atom[1]))) else: # error sys.stderr.write('Error adding atom to sat solver: ' + str(atom) + '\n') raise SystemExit(1)
def check_activation(modal_implication, valuation): """ :param modal_implication: see active_modalities above :param valuation: see active_modalities above :return tuple representing modal implications (modal atom, classical atom) if modality is active. otherwise, return False. """ assert len( modal_implication.disjuncts ) <= 2, "The modal disjunction is not formed correctly: %s" % modal_implication prop_atom, modal_atom = None, None true_literals = valuation[0] false_literals = valuation[1] # given assertion there should be one prop atom and one modal atom for disjunct in modal_implication.disjuncts: if not is_complex(disjunct): prop_atom = disjunct elif my_isinstance(disjunct[0], Modality): modal_atom = disjunct # check valuation of prop_atom, to determine num_modal_atoms activity # check if prop_atom is negated if is_atomic(prop_atom) and str(prop_atom) not in true_literals: # not negated return modal_atom, prop_atom if not is_atomic(prop_atom) and str(prop_atom[1]) not in false_literals: return modal_atom, prop_atom return False
def to_mcf(modal_context, nnf_fml, clausal_form_dict, id_mc, distributive=False): """ Given an expression in nnf (nnf_fml), return an equivalent expression in modal clausal form. """ if nnf_fml and u.is_complex(nnf_fml): connective = repr(nnf_fml[0]) switch = { '&': mcf_and, '|': mcf_or, 'box': mcf_modality, 'dia': mcf_modality, } operation = switch.get(connective, mcf_error) if operation == mcf_and or operation == mcf_modality: operation(modal_context, nnf_fml, clausal_form_dict, id_mc, distributive) else: operation(modal_context, nnf_fml, clausal_form_dict, id_mc) else: # expr is a classical literal, add to relevant disjunct mcf_classical_atom(modal_context, nnf_fml, clausal_form_dict, id_mc) return clausal_form_dict
def get_modal_lit(self): """ Returns first modal atom in a given disjunction. """ for disjunct in self.disjuncts: if u.is_complex(disjunct): if isinstance(disjunct[0], parser.Modality): self.disjuncts.remove(disjunct) return disjunct return None
def get_modality(disjunctions): """ :param disjunctions: list of disjunctions :return first stripped modal literal """ for disjunct in disjunctions: if is_complex(disjunct): connective = disjunct[0] if my_isinstance(connective, Modality): return repr(connective) return False
def mcf_modality(modal_context, fml, clausal_form_dict, id_mc, distributive): """ Takes MODAL fml, and applies transformation rules. """ global max_mc_id # print("MODAL " + str(fml) + ", id: " + str(id_mc)) nested_fml = fml[1] max_mc_id = max(id_mc, max_mc_id) if not distributive: if not u.is_complex(nested_fml): create_mc(modal_context, id_mc, clausal_form_dict, fml) else: # nested_fml is complex disjunctive_atoms = get_num_atoms(modal_context, id_mc, clausal_form_dict) p_atom = create_atom() # no classical literal in disjunction, therefore add false if disjunctive_atoms == 0: false_literal = parser.Atomic(parser.BOTTOM) create_mc(modal_context, id_mc, clausal_form_dict, false_literal) # complex modal formula with one classical literal in disjunction if disjunctive_atoms <= 1: max_mc_id += 2 create_mc(modal_context, id_mc, clausal_form_dict, [fml[0], p_atom]) updated_modal_context = copy.deepcopy(modal_context) updated_modal_context.append(parser.Modality('box', fml[0].id)) upd_fml = [u.op('|'), [u.op('~'), p_atom], nested_fml] to_mcf(updated_modal_context, upd_fml, clausal_form_dict, max_mc_id, distributive=False) else: to_mcf(modal_context, fml, clausal_form_dict, id_mc, True) else: # complex modal fml nested within OR connective p_atom = create_atom() to_mcf(modal_context, p_atom, clausal_form_dict, id_mc) upd_fml = [u.op('|'), [u.op('~'), p_atom], fml] max_mc_id += 2 to_mcf(modal_context, upd_fml, clausal_form_dict, max_mc_id, distributive=False)
def get_num_atoms(modal_context, id_modal_context, clausal_form_dict): """ Returns number of classical literals in given modal context (returns max 2). """ classic_atoms = 0 mcf_dict_key = len(modal_context) if not mcf_dict_key in clausal_form_dict: return 0 # disjunction has not been created modal_context_clauses = eq_modal_context(modal_context, id_modal_context, clausal_form_dict[mcf_dict_key]) if modal_context_clauses: for disjunct in modal_context_clauses.disjuncts: if not u.is_complex(disjunct): classic_atoms += 1 if classic_atoms > 1: return 2 elif isinstance(disjunct[0], parser.Modality): return 2 return 1 else: return 0 # disjunction (mc and id) has not been created
def get_constraints(modal_clause_dict, w): """ :return parses modal clauses for input w and returns dictionary of following clauses: A disjunction of classical literals IB disjunction of one box literal and one classical literal ID disjunction of one diamond literal and one classical literal D single diamond literal """ A = set() IB = set() ID = set() D = set() if w in modal_clause_dict.keys(): w_modal_clauses = modal_clause_dict[w] # modal_clause is a ModalExpr - modal context and list of disjunctions for modal_clause in w_modal_clauses: disjunction = modal_clause.disjuncts if len(disjunction) > 2: A.add(modal_clause) elif len(disjunction) == 1: if not is_complex(disjunction[0]): A.add(modal_clause) else: assert get_modality(disjunction) == 'dia', \ "Error in getting constraint sets - incorrectly formed modal clause: %s" % modal_clause D.add(modal_clause ) # if complex, has to be single dia literal else: # by deduction, only two disjuncts in modal_clause mod = get_modality(disjunction) if mod == 'box': IB.add(modal_clause) elif mod == 'dia': ID.add(modal_clause) else: A.add(modal_clause) return {'A': A, 'IB': IB, 'ID': ID, 'D': D}
def add_disjunct(self, arg): """ Add modal and classical literals to disjunction. Checks to ensure modal clauses are well formed. """ if not u.is_complex(arg): # not complex, as in classical literal self.disjuncts.append(get_tuple(arg)) self.num_prop_atoms += 1 if self.num_modal_atoms >= 1 and self.num_prop_atoms > 1: offending_atom = self.get_modal_lit() return self.adjust_modal_literal(offending_atom) else: return None elif isinstance(arg[0], parser.Modality): if self.num_modal_atoms == 0 and self.num_prop_atoms <= 1: self.disjuncts.append(get_tuple(arg)) self.num_modal_atoms += 1 return None else: return self.adjust_modal_literal(arg) else: mcf_error(self.mc, arg, self.disjuncts, self.mcid)
def mcf_classical_atom(modal_context, fml, clausal_form_dict, id_mc): """ Takes classical literal (fml), and adds to relevant disjunction. """ assert not u.is_complex(fml) create_mc(modal_context, id_mc, clausal_form_dict, fml)