def __lshift__(self, other: Union[Atom, Formula]) -> Formula: """<< Returns a new Specification that is the result of other -> self (implies)""" if not (isinstance(other, Atom) or isinstance(other, Formula)): raise AttributeError if isinstance(other, Atom): other = Formula(atom=other) return Formula(atom=self) << other
def __or__(self, other: Union[Atom, Formula]) -> Formula: """self | other Returns a new Specification with the disjunction with other""" if not (isinstance(other, Atom) or isinstance(other, Formula)): raise AttributeError if isinstance(other, Atom): other = Formula(atom=other) return Formula(atom=self) | other
def __setassumptions(self, value: Specification): """Setting Assumptions""" if value is None: self.__assumptions = Formula("TRUE") else: if not isinstance(value, Specification): raise AttributeError """Every contracts assigns a **copy** of A and G""" if isinstance(value, Atom): self.__assumptions = Formula(deepcopy(value)) elif isinstance(value, Formula): self.__assumptions = deepcopy(value)
def __setguarantees(self, value: Specification, saturate=True): if value is None: self.__guarantees = Formula() else: if not isinstance(value, Specification): raise AttributeError """Every contracts assigns a **copy** of A and G""" if isinstance(value, Atom): self.__guarantees = Formula(deepcopy(value)) elif isinstance(value, Formula): self.__guarantees = deepcopy(value) """Saturate the guarantees""" if saturate: self.__guarantees.saturate(self.__assumptions)
class Contract: def __init__(self, assumptions: Specification = None, guarantees: Specification = None, saturate: bool = True): self.__assumptions = None self.__guarantees = None self.__setassumptions(assumptions) self.__setguarantees(guarantees, saturate) self.__checkfeasibility() self.composed_by = {self} self.conjoined_by = {self} from ._copying import __deepcopy__ from ._printing import __str__ @property def assumptions(self) -> Formula: return self.__assumptions @assumptions.setter def assumptions(self, value: Specification): self.__setassumptions(value) self.__checkfeasibility() @property def guarantees(self) -> Formula: """Returning saturated guarantee""" return self.__guarantees @guarantees.setter def guarantees(self, value: Specification): self.__setguarantees(value) self.__checkfeasibility() def __setassumptions(self, value: Specification): """Setting Assumptions""" if value is None: self.__assumptions = Formula("TRUE") else: if not isinstance(value, Specification): raise AttributeError """Every contracts assigns a **copy** of A and G""" if isinstance(value, Atom): self.__assumptions = Formula(deepcopy(value)) elif isinstance(value, Formula): self.__assumptions = deepcopy(value) def __setguarantees(self, value: Specification, saturate=True): if value is None: self.__guarantees = Formula() else: if not isinstance(value, Specification): raise AttributeError """Every contracts assigns a **copy** of A and G""" if isinstance(value, Atom): self.__guarantees = Formula(deepcopy(value)) elif isinstance(value, Formula): self.__guarantees = deepcopy(value) """Saturate the guarantees""" if saturate: self.__guarantees.saturate(self.__assumptions) def __checkfeasibility(self): """Check Feasibility""" if self.assumptions is not None: try: self.__assumptions & self.__guarantees except NotSatisfiableException as e: raise UnfeasibleContracts(self, e) def get_controller_info(self, world_ts: Typeset = None) -> SynthesisInfo: """Extract All Info Needed to Build a Controller from the Contract""" if world_ts is None: world_ts = Typeset() """Assumptions""" a_initial: List[str] = [] a_fairness: List[str] = [] a_safety: List[str] = [] a_mutex: List[str] = [] """Guarantees""" g_initial: List[str] = [] g_safety: List[str] = [] g_mutex: List[str] = [] g_goal: List[str] = [] a_typeset = Typeset() g_typeset = Typeset() list, typeset = self.assumptions.formula(FormulaOutput.ListCNF) a_initial.extend(list) a_typeset |= typeset list, typeset = self.guarantees.formula(FormulaOutput.ListCNF) g_goal.extend(list) g_typeset |= typeset all_typeset = a_typeset | g_typeset | world_ts """Inputs typeset""" i_typeset = Typeset(all_typeset.extract_inputs()) """Output typeset""" o_typeset = Typeset(all_typeset.extract_outputs()) actions_typeset = Typeset(all_typeset.ext()) """Mutex""" ret = Atom.extract_mutex_rules(i_typeset, output=FormulaOutput.ListCNF) if ret is not None: rules, typeset = ret a_mutex.extend(rules) ret = Atom.extract_mutex_rules(o_typeset, output=FormulaOutput.ListCNF) if ret is not None: rules, typeset = ret g_mutex.extend(rules) """For the rules we extracts rules from the variables based on assumptions and inputs""" a_typeset = a_typeset | i_typeset """We remove the inputs typeset from the guarantees and we incorporate the variables ts""" g_typeset = g_typeset - i_typeset """Adding Mutex Rules""" ret = Atom.extract_mutex_rules(a_typeset, output=FormulaOutput.ListCNF) if ret is not None: rules, typeset = ret a_mutex.extend(rules) a_typeset |= typeset ret = Atom.extract_mutex_rules(g_typeset, output=FormulaOutput.ListCNF) if ret is not None: rules, typeset = ret g_mutex.extend(rules) g_typeset |= typeset """Adjacecy rules can include things that are in the world_ts""" if world_ts is not None: adjacency_ts = g_typeset | world_ts else: adjacency_ts = g_typeset ret = Atom.extract_adjacency_rules(adjacency_ts, output=FormulaOutput.ListCNF) if ret is not None: rules, typeset = ret g_adjacency.extend(rules) g_typeset |= typeset """Adding Liveness To Sensors (input)""" ret = Atom.extract_liveness_rules(i_typeset, output=FormulaOutput.ListCNF) if ret is not None: rules, typeset = ret a_liveness.extend(rules) """Extract Inputs and Outputs""" inputs = [t.name for t in (a_typeset | g_typeset).extract_inputs()] outputs = [t.name for t in (a_typeset | g_typeset).extract_outputs()] return SynthesisInfo(a_initial=assumptions, a_fairness=a_liveness, a_mutex=a_mutex, guarantees=guarantees, g_mutex=g_mutex, g_safety=g_adjacency, inputs=inputs, outputs=outputs) @staticmethod def composition(contracts: Set[Contract]) -> Contract: if len(contracts) == 1: return next(iter(contracts)) if len(contracts) == 0: raise Exception("No contract specified in the composition") contract_list = list(contracts) new_assumptions = deepcopy(contract_list[0].assumptions) new_guarantees = deepcopy(contract_list[0].guarantees) """Populate the data structure while checking for compatibility and consistency""" for contract in contract_list[1:]: try: new_assumptions &= contract.assumptions except NotSatisfiableException as e: raise IncompatibleContracts(contract, e) try: new_guarantees &= contract.guarantees except NotSatisfiableException as e: raise InconsistentContracts(contract, e) print("The composition is compatible and consistent") """Assumption relaxation""" new_assumptions.relax_by(new_guarantees) """New contracts without saturation cause it was already saturated""" new_contract = Contract(assumptions=new_assumptions, guarantees=new_guarantees, saturate=False) new_contract.composed_by = contracts return new_contract @staticmethod def conjunction(contracts: Set[Contract]) -> Contract: if len(contracts) == 1: return next(iter(contracts)) if len(contracts) == 0: raise Exception("No contract specified in the composition") contract_list = list(contracts) new_assumptions = deepcopy(contract_list[0].assumptions) new_guarantees = deepcopy(contract_list[0].guarantees) """Populate the data structure while checking for compatibility and consistency""" for contract in contract_list[1:]: new_assumptions |= contract.assumptions try: new_guarantees &= contract.guarantees except NotSatisfiableException as e: raise InconsistentContracts(contract, e) print("The conjunction is compatible and consistent") """New contracts without saturation cause it was already saturated""" new_contract = Contract(assumptions=new_assumptions, guarantees=new_guarantees, saturate=False) new_contract.conjoined_by = contracts return new_contract
Rule(rule=PromptReaction(w["hold"] & X(w["!drop"]), w["hold"]), trigger=w["clean"], description="keep holding unless the robot drops the object", system=True), Rule(rule=PromptReaction(w["drop"], w["!hold"]), trigger=w["clean"], description="if it drops the object then it does not hold anymore", system=True), Rule(rule=PromptReaction(X(w["drop"]), w["hold"]), trigger=w["clean"], description="if it wants to drops then it is holding an object", system=True) } """if the robot is available to hold and its in the location where it recognises an object then it should not move from that location""" stay_location_if_object = Formula("TRUE") for loc in living_room: stay_location_if_object &= PromptReaction( w["object_recognized"] & ~w["hold"] & loc, ~w["object_recognized"]) """Do not hold if no object is sensed""" dont_hold_if_no_object = PromptReaction(~w["hold"] & ~w["object_recognized"], ~w["hold"]) """If it drops the object then it does not hold anymore""" if_drop_not_hold = PromptReaction(w["hold"] & w["drop"], ~w["hold"]) """Drop only when it is in the garbage and is holding""" drop_near_garbage = InstantaneousReaction(w["drop"], ~w["k3"] & w["hold"]) """GF(!hold)""" keep_free_hands = GF(~w["hold"]) try: """Modeling the set of goals using robotic patterns"""
class Contract: def __init__(self, assumptions: Specification = None, guarantees: Specification = None, saturate: bool = True): self.__assumptions = None self.__guarantees = None self.__setassumptions(assumptions) self.__setguarantees(guarantees, saturate) self.__checkfeasibility() self.composed_by = {self} self.conjoined_by = {self} self.disjoined_by = {self} from ._copying import __deepcopy__ from ._printing import __str__ @property def assumptions(self) -> Formula: return self.__assumptions @assumptions.setter def assumptions(self, value: Specification): self.__setassumptions(value) self.__checkfeasibility() @property def guarantees(self) -> Formula: """Returning saturated guarantee""" return self.__guarantees @guarantees.setter def guarantees(self, value: Specification): self.__setguarantees(value) self.__checkfeasibility() @property def typeset(self) -> Typeset: return self.__guarantees.typeset | self.__assumptions.typeset def __setassumptions(self, value: Specification): """Setting Assumptions""" if value is None: self.__assumptions = Formula("TRUE") else: if not isinstance(value, Specification): raise AttributeError """Every contracts assigns a **copy** of A and G""" if isinstance(value, Atom): self.__assumptions = Formula(deepcopy(value)) elif isinstance(value, Formula): self.__assumptions = deepcopy(value) def __setguarantees(self, value: Specification, saturate=True): if value is None: self.__guarantees = Formula() else: if not isinstance(value, Specification): raise AttributeError """Every contracts assigns a **copy** of A and G""" if isinstance(value, Atom): self.__guarantees = Formula(deepcopy(value)) elif isinstance(value, Formula): self.__guarantees = deepcopy(value) """Saturate the guarantees""" if saturate: self.__guarantees.saturate(self.__assumptions) def __checkfeasibility(self): """Check Feasibility""" if self.assumptions is not None: try: self.__assumptions & self.__guarantees except NotSatisfiableException as e: raise UnfeasibleContracts(self, e) """Refinement""" def __le__(self: Contract, other: Contract): """self <= other. True if self is a refinement of other""" cond_a = self.assumptions >= other.assumptions cond_g = self.guarantees <= other.guarantees return cond_a and cond_g def get_controller_info(self, world_ts: Typeset = None) -> SynthesisInfo: """Extract All Info Needed to Build a Controller from the Contract""" """Assumptions""" assumptions = [] a_mutex = [] a_liveness = [] """Guarantees""" guarantees = [] g_mutex = [] g_adjacency = [] a_typeset = Typeset() g_typeset = Typeset() list, typeset = self.assumptions.formula(FormulaOutput.ListCNF) assumptions.extend(list) a_typeset |= typeset list, typeset = self.guarantees.formula(FormulaOutput.ListCNF) guarantees.extend(list) g_typeset |= typeset if world_ts is not None: instance_ts = Typeset.get_instance_ts((a_typeset | g_typeset), world_ts) else: instance_ts = (a_typeset | g_typeset) """Extracting Inputs and Outputs Including the variables""" i_set, o_set = instance_ts.extract_inputs_outputs() i_typeset = Typeset(i_set) o_typeset = Typeset(o_set) """Mutex Rules""" ret = Atom.extract_mutex_rules(i_typeset, output=FormulaOutput.ListCNF) if ret is not None: rules, typeset = ret a_mutex.extend(rules) ret = Atom.extract_mutex_rules(o_typeset, output=FormulaOutput.ListCNF) if ret is not None: rules, typeset = ret g_mutex.extend(rules) """Adjacecy Rules""" ret = Atom.extract_adjacency_rules(o_typeset, output=FormulaOutput.ListCNF) if ret is not None: rules, typeset = ret g_adjacency.extend(rules) """Adding Liveness To Sensors (input)""" ret = Atom.extract_liveness_rules(i_typeset, output=FormulaOutput.ListCNF) if ret is not None: rules, typeset = ret a_liveness.extend(rules) """Adding context and active signal rules""" ret = Atom.context_active_rules(i_typeset, output=FormulaOutput.ListCNF) if ret is not None: rules, typeset = ret assumptions.extend(rules) """Extract Inputs and Outputs""" inputs = [t.name for t in i_set] outputs = [t.name for t in o_set] return SynthesisInfo(assumptions=assumptions, a_liveness=a_liveness, a_mutex=a_mutex, guarantees=guarantees, g_mutex=g_mutex, g_adjacency=g_adjacency, inputs=inputs, outputs=outputs) @staticmethod def composition(contracts: Set[Contract]) -> Contract: if len(contracts) == 1: return next(iter(contracts)) if len(contracts) == 0: raise Exception("No contract specified in the composition") contract_list = list(contracts) new_assumptions = deepcopy(contract_list[0].assumptions) new_guarantees = deepcopy(contract_list[0].guarantees) """Populate the data structure while checking for compatibility and consistency""" for contract in contract_list[1:]: try: new_assumptions &= contract.assumptions except NotSatisfiableException as e: raise IncompatibleContracts(contract, e) try: new_guarantees &= contract.guarantees except NotSatisfiableException as e: raise InconsistentContracts(contract, e) print("The composition is compatible and consistent") """Assumption relaxation""" new_assumptions.relax_by(new_guarantees) """New contracts without saturation cause it was already saturated""" new_contract = Contract(assumptions=new_assumptions, guarantees=new_guarantees, saturate=False) new_contract.composed_by = contracts return new_contract @staticmethod def conjunction(contracts: Set[Contract]) -> Contract: if len(contracts) == 1: return next(iter(contracts)) if len(contracts) == 0: raise Exception("No contract specified in the conjunction") contract_list = list(contracts) new_assumptions = deepcopy(contract_list[0].assumptions) new_guarantees = deepcopy(contract_list[0].guarantees) """Populate the data structure while checking for compatibility and consistency""" for contract in contract_list[1:]: new_assumptions |= contract.assumptions try: new_guarantees &= contract.guarantees except NotSatisfiableException as e: raise InconsistentContracts(contract, e) print("The conjunction is compatible and consistent") """New contracts without saturation cause it was already saturated""" new_contract = Contract(assumptions=new_assumptions, guarantees=new_guarantees, saturate=False) new_contract.conjoined_by = contracts return new_contract @staticmethod def disjunction(contracts: Set[Contract]) -> Contract: if len(contracts) == 1: return next(iter(contracts)) if len(contracts) == 0: raise Exception("No contract specified in the disjunction") contract_list = list(contracts) new_assumptions = deepcopy(contract_list[0].assumptions) new_guarantees = deepcopy(contract_list[0].guarantees) """Populate the data structure while checking for compatibility and consistency""" for contract in contract_list[1:]: new_assumptions &= contract.assumptions try: new_guarantees |= contract.guarantees except NotSatisfiableException as e: raise InconsistentContracts(contract, e) print("The disjunction is compatible and consistent") """New contracts without saturation cause it was already saturated""" new_contract = Contract(assumptions=new_assumptions, guarantees=new_guarantees, saturate=False) new_contract.disjoined_by = contracts return new_contract