Hello World¶
We begin with a simple cogent that prints and then stops…
1"""
2Hello World!
3"""
4
5from cognition import Cogent, DecisionProcess, IOContainer, Operator
6
7# ===
8
9# dp state is boolean, starting as False
10my_cogent = Cogent(DecisionProcess(lambda: False))
11
12
13@my_cogent.dp.operator(
14 "hello", terminal=True
15) # shortcut to create + add an operator instance
16# (named "hello" with the terminal flag to stop the DP)
17class HelloOperator(Operator[bool]):
18 """
19 Says hello!
20 """
21
22 def can_perform(self, state: bool, _io: IOContainer) -> bool:
23 # this will only apply if the state is False
24 return not state
25
26 def perform(self, _state: bool, _io: IOContainer) -> bool:
27 print("Hello, World!")
28
29 # mutable state can be just changed;
30 # returned values replace state
31 return True
32
33
34# initial state
35print(f"{my_cogent.dp.state}")
36
37# nifty way to run the cogent 🤓
38# 0. no arguments/sensors/actuators, so just starts the DP
39# 1. elaborate: no elaborators, done!
40# 2. terminal: no checks; no prior action selected; done!
41# 3. propose: hello (via can_perform, where state=False) is proposed!
42# 4. rank: only one action, so hello is selected
43# 5. apply: print, new state applied (via perform, where state=False)
44# 6. elaborate: no elaborators, done!
45# 7. terminal: no checks; prior action was terminal -> stop!
46# 8. by default, cogent doesn't continue after dp -> done!
47my_cogent()
48
49# final state
50print(f"{my_cogent.dp.state}")
Low-Level¶
For those interested in the details of how this is equivalently implemented using core primitives…
1"""
2Hello World!
3(at a low level)
4"""
5
6from collections.abc import Iterable
7
8from cognition import Action, BaseDecisionProcess, IOContainer, stringify
9
10# ===
11
12
13@stringify("hello")
14def hello_factory(s: bool, _io: IOContainer) -> Iterable[Action[bool]]:
15 """action factory"""
16
17 @stringify("hello")
18 def hello(_a_s: bool, _a_io: IOContainer) -> bool:
19 """potentially proposed action"""
20
21 # if selected, say hello!
22 print("Hello, World!")
23
24 # return new state
25 return True
26
27 # if init state, propose hello!
28 if not s:
29 return (hello,)
30
31 # otherwise, nothing to propose
32 return ()
33
34
35# ===
36
37dp = BaseDecisionProcess(lambda: False)
38
39dp.add_action_factory(hello_factory)
40
41# done if state is True
42dp.add_termination_check(stringify("done?")(lambda s, _io: s))
43
44# ===
45
46# initial state
47print(f"{dp.state}")
48
49dp.run_until_done()
50
51# uncomment to see the result of stringify'd components
52# print(dp)
53
54# final state
55print(f"{dp.state}")
Notes…
The
BaseDecisionProcessutilizesActionFactoryto identify whatAction(s) are appropriate in the current context.Notice how an
Operatorfacilitates a clean separation of proposal vs application logic:Operatorprovides a predicate (can_perform) to control proposal of a singularActioninstantiation,OperatorGeneratorprovides flexibility (viagenerate) to dynamically propose multiple instantiation(s).
The
terminalflag of an instantiatedOperatoravoids duplicating the logic ofActionpost-conditions within a customTerminationCheck.Without any sensors/actuators, the
Cogentserves largely as a wrapper around the supplied DP.While not necessary for function, the
stringifydecorator provides objects a user-friendlystr()result.This is particularly helpful when examining a DP (via
print).