Example #1
0
class AddTag(Codelet):
    taggee: R[Node] = Ref('taggee')
    tag: R[Node] = Ref('tag')

    def run(  # type: ignore[override]
        self,
        fm: FARGModel,
        taggee: Node,
        tag: Node,
        sources: Sources
    ) -> CodeletResults:
        if not fm.has_node(taggee):
            if isinstance(taggee, CellRef):  # HACKish and needs UT
                sources = fm.run_codelet_and_follow_ups(
                    Build(to_build=taggee),
                    sources
                )
        if fm.has_node(taggee):
            if isclass(tag):
                # TODO Supply arguments to tag ctor
                tag = tag()  # type: ignore[operator]
            sources = fm.run_codelet_and_follow_ups(
                Build(to_build=tag),
                sources
            )
            tag = first(fm.look_up_by_name('built', sources))
            # TODO What if tag is None now?
            fm.add_tag(taggee, tag)
        else:
            raise TaggeeDoesNotExist(taggee=taggee)

        return None
Example #2
0
class MakeVariantFromAvails(Codelet):
    agent: R[Agent] = Ref('agent')
    cellref: R[CellRef] = Ref('source')
    avails: R[Tuple[Value, ...]] = Ref('avails')
        # These values were avail; indices match indices in seeker's request
    unavails: R[Tuple[Value, ...]] = Ref('unavails')
        # These values were unavail; indices match indices in seeker's request

    def run(  # type: ignore[override]
        self,
        fm: FARGModel,
        cellref: CellRef,
        agent: Agent,  # the Agent to make a variant of
        avails: Tuple[Value, ...],
        unavails: Tuple[Value, ...],
        running_agent: Optional[Agent]=None
    ) -> CodeletResults:
        true_avails = list(as_iter(cellref.avails))
        new_operands: List[Value] = []

        for a, u in zip(avails, unavails):  # TODO zip_longest?
            if a is not None:
                if a in true_avails:
                    new_operands.append(a)
                    true_avails.remove(a)
                else:
                    self.fill_unavail_from_avails(a, new_operands, true_avails)
            if u is not None:
                self.fill_unavail_from_avails(u, new_operands, true_avails)
        # TODO Don't make a new agent that's already there
        if not isinstance(agent, Agents.Consumer):
            return None  # TODO raise exception?
        else:
            return Build(
                # TODO Standardize order of operands when commutative?
                to_build=replace(agent, operands=tuple(new_operands)),
                builder=running_agent
            )

    @classmethod
    def fill_unavail_from_avails(
        cls,
        u: Value,
        new_operands: List[Value],
        true_avails: List[Value]
    ) -> None:
        '''Chooses one or more replacements for 'u' from 'true_avails',
        removes them from 'true_avails', and appends them to 'new_operands'.'''
        ua: Sequence[Value] = choose_most_similar(true_avails, u)
        if ua:
            new_operands += ua
            for v in ua:
                true_avails.remove(v)
        else:
            pass  # TODO raise an exception?
Example #3
0
class Consume(Codelet):
    operator: R[Operator] = Ref('operator')
    operands: R[Tuple[Value, ...]] = Ref('operands')
    source: R[CellRef] = Ref('source')
    result_in: R[str] = 'result'

    def run(  # type: ignore[override]
            self, fm: FARGModel, operator: Operator, operands: Tuple[Value,
                                                                     ...],
            source: CellRef, result_in: str) -> CodeletResults:
        return dict([(result_in, operator.consume(source, operands)),
                     ('dest', source.next_cellref())])
Example #4
0
class Paint(Codelet):
    '''Paints a value in a Canvas cell.'''
    dest: R[CellRef] = Ref('dest')
    value: R[Value] = Ref('value')
    sk: R[Codelets] = NewState(Ref('running_agent'), Succeeded)
    fk: R[Codelets] = NewState(Ref('running_agent'), Snag)

    def run(  # type: ignore[override]
        self, fm, dest: CellRef, value: Value, running_agent: Optional[Agent],
        sk: Optional[Codelet]
    ) -> CodeletResults:
        #print('PAINT', fm.a(running_agent), running_agent)
        fm.paint(dest, value, running_agent)
        return None
Example #5
0
class Consumer(Agent):
    Q = TypeVar('Q', bound='Consumer')

    operator: Union[Operator, None] = None
    operands: Union[Tuple[Value, ...], None] = None
    source: Union[CellRef, None] = None  # where to get operands
    # TODO rm dest?
    #dest: Union[CellRef, None] = None    # where to paint result

    wake: Codelets = (Consume(operator=Ref('operator'),
                              operands=Ref('operands'),
                              source=Ref('source'),
                              result_in='result'),
                      BuildLitPainter(value=Ref('result')),
                      Sleep(agent=Ref('running_agent')))
    # Another possible approach, breaking down Consume into smaller codelets:
    #TakeOperands(operands=Ref('operands'), cellref=Ref('source')),
    #ComputeResult(),
    delegate_succeeded: Codelets = ISucceeded()

    def features_of(self) -> Iterable[Node]:
        for operand in as_iter(self.operands):
            yield Before(operand)
        if self.operator:
            yield self.operator
        if self.operands and self.operator:
            result = self.operator(*self.operands)
            yield After(result)

    def short(self) -> str:
        cl = self.__class__.__name__
        s = short(self.operator).join(short(o) for o in as_iter(self.operands))
        return f'{cl}({s})'

    @classmethod
    def make(cls: Type[Q], operator: Union[Operator, None],
             operands: Union[Tuple[Value, ...], None]) -> Q:
        return cls(operator=operator, operands=operands)

    @classmethod
    def make_table(cls, rands1: Iterable[int], rands2: Iterable[int],
                   rators: Iterable[Operator]) -> Iterable['Consumer']:
        for rand1 in rands1:
            for rand2 in rands2:
                for rator in rators:
                    if rand1 >= rand2:
                        result = rator(rand1, rand2)
                        if result != rand1 and result != rand2:
                            yield cls(operator=rator, operands=(rand1, rand2))
Example #6
0
class BuildLitPainter(Codelet):
    value: R[Value] = Ref('value')
    dest: R[CellRef] = Ref('dest')

    def run(  # type: ignore[override]
        self,
        fm: FARGModel,
        value: Value,
        dest: CellRef,
        running_agent: Optional[Agent]
    ) -> CodeletResults:
        fm.build(
            Agents.LitPainter(value=value, dest=dest),
            builder=running_agent
        )
        return None
Example #7
0
class Build(Codelet):
    '''Builds one or more nodes that serve as companions for the acting
    node.'''
    to_build: R[Nodes] = None
    builder: R[Actor] = Ref('running_agent')

    def run(  # type: ignore[override]
        self,
        fm: FARGModel,
        builder: Optional[Actor],
        to_build: Nodes,
        sources: Sources
    ) -> CodeletResults:
        built: List[Node] = []
        for node in as_iter(to_build):
            node = fm.replace_refs(node, sources)
            node = fm.build(node, builder=builder)
            built.append(node)
        '''
        if builder:
            return NewState(builder, Wake)
        else:
            return None
        '''
        return {'built': set(built)}

    def short(self) -> str:
        cl = self.__class__.__name__
        return f'{cl}({short(self.to_build)})'
Example #8
0
class QuerySlipnetForDelegate(Codelet):
    qargs: R[QArgs] = Ref('qargs')
    #sk: R[Codelets] = Sleep(Ref('running_agent'))  TODO

    def run(  # type: ignore[override]
        self,
        fm: FARGModel,
        running_agent: Optional[Agent],
        qargs: QArgs,  # TODO Require at least one QArg?
        sources: Sources
    ) -> CodeletResults:
        kwargs = fm.mk_slipnet_args(qargs, sources)
        slipnet_results = fm.pulse_slipnet(
            alog=fm.start_alog((running_agent, self)),
            **kwargs
        )
        if not slipnet_results:
            raise NoResultFromSlipnet(qargs=qargs)
        return [
            Build(
                to_build=fm.try_to_fill_nones(node, sources, running_agent),
                builder=running_agent
            )
                for node in slipnet_results
        ]
        """
Example #9
0
 def test_agent_replace_refs(self) -> None:
     fm = FARGModel()
     ag1 = ag.replace_refs(fm, None)
     self.assertEqual(
         ag1,
         DummyAgent(agstr='FROM AGENT',
                    born=DummyCodelet(late_bound=Ref('agstr'))))
Example #10
0
class RaiseException(Codelet):
    exctype: R[Type[Exception]] = Ref('exctype')

    def run(  # type: ignore[override]
        self,
        fm: FARGModel,
        exctype: Type[Exception],
        sources: Sources
    ) -> CodeletResults:
        raise exctype(**fm.mk_func_args(exctype, sources))  # type: ignore[call-arg]
Example #11
0
class Sleep(Codelet):
    agent: R[Actor] = Ref('agent')
    sleep_duration: int = 3

    def run(  # type: ignore[override]
        self,
        fm: FARGModel,
        agent: Agent,
        sleep_duration: int
    ) -> CodeletResults:
        fm.sleep(agent, sleep_duration)
        return None
Example #12
0
class VariantMakerFromAvails(Agent):
    agent: R[Agent] = Ref('agent')  # The agent to make a variant of
    cellref: R[CellRef] = Ref('source')
    avails: R[Tuple[Value, ...]] = Ref('avails')
    # These values were avail; indices match indices in seeker's request
    unavails: R[Tuple[Value, ...]] = Ref('unavails')
    # These values were unavail; indices match indices in seeker's request

    wake: Codelets = (MakeVariantFromAvails(Ref('agent'), Ref('source'),
                                            Ref('avails'), Ref('unavails')),
                      Sleep(agent=Ref('running_agent')))

    def short(self) -> str:
        cl = self.__class__.__name__
        return f'{cl}({short(self.agent)}, {short(self.cellref)}, {short(self.avails)}, {short(self.unavails)})'

    def features_of(self) -> Iterable[Node]:
        yield Desnag(ValuesNotAvail)
Example #13
0
class Want(Agent):
    startcell: R[CellRef] = Ref('startcell')
    target: R[Value] = Ref('target')
    on_success: R[Codelets] = Ref('on_success')

    born: Codelets = (
        Build(AvailDetector()),
        Build(
            DeadEndDetector(on_success=AddTag(
                tag=DeadEnd(),  # TODO for_goal = this Want
                taggee=Ref('dead_end')))),
        NewState(agent=Ref('running_agent'), state=Wake))
    wake: Codelets = (FindLastPaintedCell(),
                      QuerySlipnetForDelegate(
                          qargs=(QBeforeFromAvails(Ref('startcell')),
                                 QAfter(Ref('target')), SearchFor(Agent),
                                 ExcludeExisting())),
                      Sleep(agent=Ref('running_agent')))

    #delegate_succeeded: Codelets = RaiseException(KeyError)

    def short(self) -> str:
        cl = self.__class__.__name__
        return f'{cl}({short(self.target)}, {short(self.startcell)})'
Example #14
0
class DeadEnd(Tag):
    for_goal: R[Node] = Ref('for_goal')

    # TODO Inherit from something that has this.
    def short(self) -> str:
        cl = self.__class__.__name__
        return f'{cl}({dict_str(as_dict(self), xform=short)})'

    """
    def extend(self, fm: FARGModel, sources: Sources) -> None:
        '''Extend the taggees of this tag as far as possible. So, a DeadEnd
        that tags a CellRef should be extended to tag the CellRef's LitPainter
        and Consumer that produced the LitPainter.'''
        taggees = set(fm.taggees_of(self))
        pending: Set[Node] = set(taggees)
        new_taggees: Set[Node] = set()
        while pending:
            for old_node in pending:
                for new_node in self.also_needs_tagging1(fm, old_node):
                    if new_node not in taggees:
                        fm.add_tag(new_node, self)
                        new_taggees.add(new_node)
            taggees |= new_taggees
            pending = new_taggees
            new_taggees.clear()
    """

    @classmethod
    def also_tag(cls, fm: FARGModel, node: Node) -> Iterable[Node]:
        '''Returns nodes that also need tagging if 'node' is tagged, but does
        not recurse. So, if 'node' necessitates tagging node A, and node A
        necessitates tagging node B, then also_needs_tagging1 will return
        node A but not node B.'''
        if isinstance(node, CellRef):
            yield from fm.painters_of(node, node.value)
        elif isinstance(node, Painter):
            yield from fm.behalf_of(node)
Example #15
0
 def test_codelet_replace_refs(self) -> None:
     fm = FARGModel()
     co0 = DummyCodelet(late_bound=Ref('agstr'))
     ag = DummyAgent(agstr='FROM AGENT', born=DummyCodelet())
     co1 = co0.replace_refs(fm, ag)
     self.assertEqual(co1, DummyCodelet(late_bound='FROM AGENT'))
Example #16
0
            self, fm: FARGModel, late_bound: str):
        DummyCodelet.depository = late_bound


@dataclass(frozen=True)
class DummyAgent(Agent):
    agstr: str = 'default'

    # string in Agent; will be copied to DummyAgent.late_bound

    def short(self) -> str:
        cl = self.__class__.__name__
        return f'{cl}({self.agstr})'


ag = DummyAgent(agstr='FROM AGENT', born=DummyCodelet(late_bound=Ref('agstr')))

ag2 = DummyAgent(agstr='ag2', born=DummyCodelet(late_bound=Ref('agstr')))


class TestFARGModel(unittest.TestCase):
    def test_fargmodel_basics(self) -> None:
        fm = FARGModel()
        self.assertEqual(fm.t, 0)
        # Did it initialize a random-number seed?
        self.assertIsInstance(fm.seed, int)

        # Build something
        ca = fm.build(StepCanvas([Step([4, 5, 6])]))
        # Is it there?
        self.assertTrue(fm.the(StepCanvas))