class ActionNode(ActiveNode): '''A node that holds an action and tries to perform it.''' node_params = NodeParams(AttrParam('action'), AttrParam('state'), MateParam('rm_on_success', 'tags')) def actions(self, g, thisid): if not self.is_dormant(g, thisid): return [self.action.with_overrides_from(g, thisid)] # TODO If action has any missing args, make scout actions to fill them # in. # Otherwise return a version of the action with those args filled in. def action_failed(self, g, thisid, exc: Fizzle): failed_tag = g.make_node('Failed', reason=exc, taggees=[thisid]) g.add_support(thisid, failed_tag, 1.0)
class Proposal(ActiveNode): node_params = NodeParams(AttrParam('action')) # We expect more arguments, which we will pass to 'action'. #is_duplicable = True # HACK Is already_built mis-rejecting this? def proposed_kwargs(self) -> Dict[PortLabel, NodeId]: '''Strips leading 'proposed_' from port labels and returns a dictionary mapping the resulting names to this node's neighbors at the corresponding ports.''' result = {} for pk in self.g.port_labels_of(self): if not pk.startswith('proposed_'): continue k = pk[9:] v = self.g.neighbors(self, port_label=pk) if not v: v = None elif len(v) == 1: v = first(v) result[k] = v return result def actions(self): #return self.action.with_overrides_from(self.g, self) return self.action.with_overrides_from(self.g, self.proposed_kwargs())
def make_node_param(env, name): defn = env.get(name) if isinstance(defn, PortLabel): return MateParam(name, defn.unique_mate(env)) else: # TODO Throw error if name is defined as something inappropriate return AttrParam(name)
class SeekAndGlom(AcNode): node_params = NodeParams( AttrParam('seekclass', Brick) # Specific to testNumboClasses: default ) # to seeking Brick nodes threshold = 1.0 acs = [ All(OfClass('seekclass'), focal_point=MyContext), AddNode(Glom, members='nodes') ]
class ActionNode(ActiveNode): '''A node that holds an action and tries to perform it.''' node_params = NodeParams(AttrParam('action'), AttrParam('state', Start), MateParam('rm_on_success', 'tags')) initial_activation = 0.1 def actions(self): if self.g.is_blocked(self): return self.on_blocked() else: return self.action.with_overrides_from(self.g, self) # def action_blocked(self, exc: Fizzle): # if hasattr(self.action, 'action_blocked'): # self.action.action_blocked(self.g, self, exc) # else: # blocked_tag = self.g.add_node('Blocked', reason=exc, taggees=self) # self.g.set_activation_from_to(self, blocked_tag) # self.g.add_support(self, blocked_tag, 1.0) # self.transient_inhibit_all_next() # self.g.reset_activation(self) # # def action_failed(self, exc: ActionFailure): # failed_tag = self.g.add_node('Failed', reason=exc, taggees=self) # self.g.set_activation_from_to(self, failed_tag) # self.g.add_support(self, failed_tag, 1.0) # self.transient_inhibit_all_next() # self.g.reset_activation(self) def display_name(self): #action_name = self.action.__class__.__name__ if self.name: return self.name elif not self.action: return super().display_name() else: # TODO Put an * after the action's class name return str(self.action)
class Seeker(ActiveNode): '''A Seeker seeks a Sought with the same .value.''' node_params = NodeParams(AttrParam('value')) # Required: Returns list of Action objects def actions(self, g): return [ MakeLink(self, nodeid) for nodeid in g.nodes_of_class(Sought) if self.am_seeking(g, nodeid) ] # Override: Tells when to stop polling this node for actions def dormant(self, g): return g.has_neighbor_at(self, 'found') def am_seeking(self, g, nodeid): return (not g.has_neighbor_at(nodeid, 'seeker') and g.value_of(nodeid) == self.value)
class ActionSeqNode(ActiveNode): '''A group node whose members are a sequence of ActionNodes.''' node_params = NodeParams( MateParam('members', 'member_of'), AttrParam('action_nodes') # HACK: must be a list, to indicate sequence ) def actions(self, g, thisid): return None def on_build(self, g, thisid): # Give activation to each member and make each member inhibit all # following members. members = as_iter(self.action_nodes) for i, member in enumerate(members): g.set_activation_from_to(thisid, member, 0.3) g.add_edge(thisid, 'child_action', member, 'parent_action') for later_member in members[i + 1:]: g.set_activation_from_to(member, later_member, -1.0) for next_member in members[i + 1:i + 2]: g.add_edge(member, 'next_action', next_member, 'prev_action')
class AdHocAcNode(AcNode): '''An AcNode that accepts the .acs as a ctor argument.''' node_params = NodeParams(AttrParam('acs', None), AttrParam('state', Start), MateParam('rm_on_success', 'tags'))
class Sought(Node): '''A Sought passively (without generating Actions) awaits a Seeker.''' node_params = NodeParams(AttrParam('value'))
Want.min_activation = 1.0 Want.min_support_for = 10.0 def failed_display_name(self: Failed) -> str: return f'{self.__class__.__name__}({self.reason.__class__.__name__})' Failed.display_name = failed_display_name Minus.node_params = NodeParams(MateParam('minuend', 'consumer'), MateParam('subtrahend', 'consumer'), MateParam('result', 'source')) Diff.node_params = NodeParams(MateParam('lesser', 'tags'), MateParam('greater', 'tags'), AttrParam('value')) OoM.initial_activation = 1.0 # TODO rm these functions? #def plus_result(self, g: 'G', node: NRef) -> int: def plus_result(self: Plus) -> int: # TODO Appropriate exception(s) if an operand is missing a value or it's # the wrong type or there aren't enough operands. operands = self.g.neighbors(self, 'operands') return sum(self.g.value_of(o) for o in operands) Plus.result_value = plus_result
class MyNode(Node): node_params = NodeParams(AttrParam('name')) initial_activation = 0.0
class MyNode(Node): node_params = NodeParams(AttrParam('name'))
class Number(Node): node_params = NodeParams(AttrParam('n'))
class UniqueNumber(Node): node_params = NodeParams(AttrParam('value'))