def add_state(self, *, mod: module.Module, st: state.State): if st in self.states: logging.error(f"Attempt to add state `{st.name}` twice!") return # annotate the state's signal name with it's module name if len(st.signal) > 0: st.signal = f"{mod.name}:{st.signal}" st.module_name = mod.name # make sure that all of the state's depended-upon properties exist for prop in st.read_props + st.write_props: if prop not in self.properties: logging.error( f"Attempt to add state which depends on unknown property `{prop}`!" ) # register the state's signal with self.states_lock: if st.signal: self.states_per_signal[st.signal] = set() # make sure that all of the state's depended-upon signals exist for clause in st.triggers: for signal in clause: if signal in self.states_per_signal: self.states_per_signal[signal].add(st) else: logging.error( f"Attempt to add state which depends on unknown signal `{signal}`!" ) self.states.add(st)
def __init__(self, *, ctx: IContext, state: State, spike_parents: Set[Spike] = None, spike_payloads: Dict[str, Any] = None): self.state = state self.ctx = ctx self.properties = dict() self.spike_parents = spike_parents self.spike_payloads = spike_payloads # Recursively complete properties dict with children: for prop_parent_id in state.get_all_props_ids(): # May have been covered by a parent before if prop_parent_id not in self.properties: prop_and_children = ctx[prop_parent_id].gather_children() for prop in prop_and_children: # Child may have been covered by a parent before if prop.id() not in self.properties: self.properties[prop.id()] = PropertyWrapper( prop=prop, ctx=self.ctx, spike_parents=self.spike_parents, allow_read=prop_parent_id in state.get_read_props_ids(), allow_write=prop_parent_id in state.get_write_props_ids(), boring=self.state.boring)
def under_test(default_signal, default_read, default_write, default_triggers): return State( signal=default_signal, read=default_read, write=default_write, cond=default_triggers, action=default_action )
def _complete_constraint(self, st: State): new_conjuncts: Set[Conjunct] = deepcopy(set(st.constraint.conjunctions())) for conj in st.constraint.conjunctions(): known_signals = set() new_conjuncts.update( Conjunct(*conj_signals) for conj_signals in self._complete_conjunction(conj, known_signals)) assert len(known_signals) == 0 st.completed_constraint = Disjunct(*{conj for conj in new_conjuncts})
def rm_state(self, *, st: State) -> None: """ Remove a state from this context. Note, that any state which is constrained on the signal that is emitted by the deleted state will also be deleted. * `st`: The state to remove. An error message will be generated, if the state was not previously added to this context with add_state(). """ if st not in self._activations_per_state: logger.error(f"Attempt to remove unknown state `{st.name}`!") return with self._lock: # Remove the state's signal if st.signal(): self._rm_sig(st.signal()) # Remove state activations for the state self._del_state_activations(st) # Actually forget about the state del self._activations_per_state[st] # unregister the state's consumable dummy self.rm_prop(prop=st.consumable)
def receptor_decorator(action): nonlocal ctx_wrap, write ctx = ctx_wrap.ctx receptor_state = State(write=write, read=(), signal_name=None, cond=None, action=action, is_receptor=True) def receptor_function(*args, **kwargs): nonlocal receptor_state, ctx Activation(st=receptor_state, ctx=ctx).run(*args, **kwargs) return receptor_function
def receptor_decorator(action): nonlocal ctx_wrap, write ctx = ctx_wrap.ctx receptor_state = State(write=write, read=(), signal=None, triggers=(), action=action, is_receptor=True) def receptor_function(*args, **kwargs): nonlocal receptor_state, ctx activation = StateActivation(st=receptor_state, ctx=ctx) act_thread = activation.run(args, kwargs) act_thread.start() return receptor_function
def receptor_decorator(action): nonlocal ctx_wrap, write if isinstance(ctx_wrap, ContextWrapper): ctx = ctx_wrap.ctx else: ctx = ctx_wrap receptor_state = State(write=write, read=(), signal=None, cond=None, action=action, is_receptor=True) def receptor_function(*args, **kwargs): nonlocal receptor_state, ctx Activation(st=receptor_state, ctx=ctx).run(*args, **kwargs) return receptor_function
def add_state(self, *, st: State) -> None: """ Add a state to this context. It will be indexed wrt/ the properties/signals it depends on. Error messages will be generated for unknown signals/properties. * `st`: The state which should be added to this context. """ if st in self._activations_per_state: logger.error(f"Attempt to add state `{st.name}` twice!") return # make sure that all of the state's depended-upon properties exist for prop in st.read_props+st.write_props: if prop not in self._properties: logger.error(f"Attempt to add state which depends on unknown property `{prop}`!") return # replace configurable ages with their config values for signal in st.constraint.signals(): if isinstance(signal.min_age, ConfigurableAge): conf_entry = self.conf(mod=st.module_name, key=signal.min_age.key) if conf_entry is None: logger.error(f"Could not set min_age for cond of state {st.name} in module {st.module_name}") signal.min_age = 0. else: signal.min_age = conf_entry if isinstance(signal.max_age, ConfigurableAge): conf_entry = self.conf(mod=st.module_name, key=signal.max_age.key) if conf_entry is None: logger.error(f"Could not set max_age for cond of state {st.name} in module {st.module_name}") signal.max_age = 5. else: signal.max_age = conf_entry # register the state's signal with self._lock: if st.signal(): self._add_sig(st.signal()) # add state's constraints as causes for the written prop's :changed signals, # as well as the state's own signal. states_to_recomplete: Set[State] = {st} if not st.emit_detached: for conj in st.constraint.conjunctions(filter_detached=True): for propname in st.write_props: if propname in self._properties: for signal in self._properties[propname].signals(): self._signal_causes[signal].append(conj) # Since a new cause for the property's signal is added, # it must be added to all states depending on that signal. states_to_recomplete.update(self._states_for_signal(signal)) if st.signal(): self._signal_causes[st.signal()].append(conj) # add state to state activation map self._activations_per_state[st] = set() # make sure that all of the state's depended-upon signals exist, # add a default state activation for every constraint. for state in states_to_recomplete: self._del_state_activations(state) self._complete_constraint(state) self._new_state_activation(state) # register the state's consumable dummy, so that it is passed # to Spike and from there to CausalGroup as a consumable resource. if st.consumable.id() not in self._properties: self.add_prop(prop=st.consumable)