In this chapter, aspects of AGI development are discussed, affecting, in addition to what is mentioned in the title, two more topics: IMPLICIT ASSUMPTIONS and the problem of slang professional terminology.
Being a type of soft real-time system, AGI implementation naturally uses one or another variant of event-driven architecture. In this statement, we use the term "event-driven architecture" not in the jargon sense, which implies the use of a system for sending event messages to processing modules, but the fact that the AGI components of the system act by reacting to various events.
In programming jargon, an event is often understood not as an actual event in the defined sense of the term but as a description of an event that is to be forwarded from one system component to another/others, which implies the presence of code that detects the event, forms its description, and sends it to one or more event handlers.
To receive such event messages, the event handler usually has an event queue to which new event messages are added; the event handler processes messages from this queue one by one (sometimes selecting an event from the queue in a complex way - taking into account the priority of events).
For developing systems with such an architecture, both ready-made frameworks implementing the messaging system (like, for example, ROS/ROS2) and custom versions are used.
The described approach basically has an (implicitly formulated) assumption: since we are talking about events, it is necessary to have the "Event" class, so what to do with objects of this type, except to send them to event handlers - there is more than one, and the same event often requires several logically independent actions, right? The next step is to include in the Event class object all imaginable information about the event, which can potentially be helpful to the recipient of the event message: event type, time, unique identifier, identifier of the generating module, priority, the ability to add all possible data specific to different events. This is designed to ensure universality and the ability to expand/modify the system without changing the mailing system.
Such an architecture logically copies the traditional system of distribution of the paper press by conventional mail, which reacts to the event of the appearance of a new issue by delivering paper copies of the publication to subscribers' mailboxes.
The result is the use of a cumbersome infrastructure, which requires significant computing resources, the universality of which is very conditional since the module that generates the event object must have information about the recipients to whom it is necessary to send messages.
But the problems do not end there. First, reactivity decreases; that is, the reaction time to events increases: sending messages and staying in the event queue takes some time.
Secondly, situations are possible when a pair of events fall into the queue, the latter making the processing of the previous one meaningless. For example, if in the queue of unprocessed events, an earlier message says, "Object A has appeared in the field of view", and a later one says, "Object A has ceased to be visible", then most likely the processing of the message about the appearance of the object A is meaningless or even leads to an error. As a result, instead of simply extracting the next event from the queue, an algorithm is constructed to analyze the entire content of the event queue, which complicates the logic, increases the volume of the code, and reduces the system's reactivity.
Thirdly, the use of the messaging system provokes that together with the message about the event, data related to the event is sent to be used by the recipient to react to the event. This means additional copying of data, which becomes multiple when sent to several recipients (analog in everyday life: in a library, one copy of a magazine can be used by many readers; when mailing by subscription, a copy should be printed for each subscriber).
As in the other previously mentioned situations, the architecture based on the event messaging system is a consequence of the "obviousness" of such a choice, caused by the fact that the architect ignored the existence of an alternative approach to construct event-driven architecture to the description of which we proceed.
In any computer system, an event is the fact of changing some data. For example, in a cycle
for( int i=0; i < n; i++ ){
if( i % 100 == 0 ) print( ... );
// ...
}
the achievement of a cycle variable `i', a value multiple of 100, is an event handled by printing some text. The if(...) operator plays the role of an event detector, and the following print operator plays the role of an event handler. In any program more complex than the famous "Hello world" in any programming language, many similar constructions differ from the described above "obvious" scheme: an event detector and an event handler form a single construction that does not require messaging.
Analogous to this situation is a driver at an intersection with a traffic light waiting for a green light. The driver directly detects that the green light has appeared and reacts accordingly. If the driver was distracted by reading messages on the phone, and the green light not only appeared but also changed back to red, no problems arose. If messages about the signal change from the traffic light were placed in a queue for sequential processing (for example, by the autopilot module), then a delay in processing could lead to a reaction to the "green signal turned on" event, when in fact the traffic light is already switched back to red. In the case of a traffic light, the consequences of such a situation can be catastrophic.
In this regard, a variant of the event handler without a queue can be used: the handler is simply a function called by the event detector. This option, however, has its drawbacks: firstly, while the event handler is working, the detector is unable to detect new events; secondly (which in practice creates much more severe problems), with independent development of modules, there is a high risk that the event handler is also a detector of other events, which is a direct path to infinite loops and/or deadlocks (this difficult-to-diagnose problem is familiar to, who uses ROS/ROS2).
What prevents the use of a potentially simpler, more reliable, and, at the same time, more productive event-driven architecture that does not use the forwarding of event messages?
The event that needs to be detected is a change in some data. The event handler is combined with the detector; such a "compound module" must have direct access to the data that needs to be monitored (the traffic light must be visible to the driver so that he can detect the change of red lights to green). This requires appropriate data structuring rules.
Suppose a module creates/updates a particular group (structure) of data available to other modules. In that case, it is necessary to ensure safe simultaneous access to reading data by many modules, including blocking such access during data updating (access synchronization). By now, the corresponding programming technique has ceased to be exotic but has yet to become trivial - this is essentially the only real obstacle for messageless event-driven architecture.
In particular, chapter AGI: MULTICORE AND MULTITHREADING describes the tools that allow you to effectively implement such an architecture in a unified way within the framework of a multicore soft real-time system.
After reading the above, the reader may ask: what if the system is a few hardware units forming a network with data transmission? This does not change much since the other units are represented by the corresponding local drivers in each hardware unit. For example, if the main unit receives information from a video camera, it has a local video driver that constantly updates the contents of video buffers. It is enough to have a wrapper class that provides access to any modules to the current video frame for reading (blocking this access during data update) and assigns a unique identifier to each new frame. Several modules processing video information can detect the event of receiving a new frame by comparing the ID of the current frame with the ID of the last frame processed by the module. If the frame is updated, the necessary data (often, it is not a complete set of video frame data) is copied for local processing. It is reasonable to make the ID of the video frame an atomic variable.
The above, of course, does not apply to the operating system, which for many reasons cannot provide direct access to system data - but there are no fewer reasons for using the system's messaging capabilities exclusively for interacting with the operating environment for which these tools are intended.
Technological details of messageless event-driven architecture - the topic of a separate future chapter.
It may be true that "AGI components of the system act by reacting to various events", however the same cannot be said for natural intelligence. Our brains use a much more computationally efficient approach. We construct a prediction of what is to occur. As long as our prediction is not violated, there is no need to react. Confirming a prediction is computationally less expensive than being purely data driven. Our cognitive load is light until something occurs that was not predicted. Then we correct our prediction. Besides being computationally efficient, this approach does not suffer from the brittleness of reflexive responses.
This allows me to drive at 70 mph on the highway while chatting with a passenger...until I see red brake lights ahead. Then my conversation pauses as my attention and my entire cognitive faculty is redirected toward the road ahead.
Computers, light switches, and monosynaptic reflexes are all event/data driven. They are entirely reflexive...like the outdated model of behavioral psychology. Intelligent animals, on the other hand, operate within a continuous cycle of sensing, predicting, and acting within an environment or umwelt.
Great write-up. We also recently published an article on how to bridge Backend and Data Engineering teams using Event Driven Architecture - https://packagemain.tech/p/bridging-backend-and-data-engineering