# CMP notions and questions

**URL:** <https://forum.thousandbrains.org/t/cmp-notions-and-questions/316>\
**Category:** Research and Theory\
**Created:** [December 17, 2024, 6:06pm UTC](https://forum.thousandbrains.org/t/cmp-notions-and-questions/316 "2024-12-17T18:06:46Z")\
**Posts on this page:** 19\
**Page:** 1

<div class="post-metadata">

**Author:** ![Rich\_Morin](https://yyz2.discourse-cdn.com/flex034/user_avatar/forum.thousandbrains.org/rich_morin/32/89_2.png) [@Rich\_Morin](https://forum.thousandbrains.org/u/Rich_Morin)\
**Post date:** [December 17, 2024, 6:06pm UTC](https://forum.thousandbrains.org/t/cmp-notions-and-questions/316/1 "2024-12-17T18:06:46Z")

</div>

While thinking about ways to make the CMP interoperable with programming languages other than Python (e.g., Elixir), I came up with some naive notions and questions. Be kind…

The CMP contains the fields `sender_id` and `sender_type`. It seems like the `sender_id` could be used as (part of) a “return address”, allowing the recipient to respond, etc.

Q: Is this part of the field’s intended purpose?  
Q: Are there other ways to address the sender?  
Q: Is there a way to add host (etc) routing info?

The `sender_type` (e.g., “SM”) says a bit about the nature of the sender, but it’s pretty vague. This makes me wonder whether other, more specific information could be useful. For example, might it help to know whether a sensor is auditory, tactile, or visual?

It could also help to know more about the message, e.g.:

- message type (e.g., control, voting)
- path type (e.g., lateral, skip, up/down)
- origin location and level (e.g., X, Y, Z)

Maintaining a global “clock” would be difficult, though a [CRDT](https://en.wikipedia.org/wiki/Conflict-free_replicated_data_type) might help. However, each process could certainly maintain and transmit a counter for received messages. This could allow the receiving process to detect some ordering issues.

-r

---

<div class="post-metadata">

**Author:** ![DLed](https://yyz2.discourse-cdn.com/flex034/user_avatar/forum.thousandbrains.org/dled/32/162_2.png) [@DLed](https://forum.thousandbrains.org/u/DLed)\
**Post date:** [December 17, 2024, 6:53pm UTC](https://forum.thousandbrains.org/t/cmp-notions-and-questions/316/2 "2024-12-17T18:53:44Z")

</div>

> [@Rich\_Morin](#):
>
> The CMP contains the fields `sender_id` and `sender_type`. It seems like the `sender_id` could be used as (part of) a “return address”, allowing the recipient to respond, etc.

I was also browsing the discussions around the “distributed CMP”, as one thing kept nagging at me at the back of the head: addressing. Whatever the implementation of distribution will be, if it crosses the boundaries of independent “entities” (threads, tasks, processes, OS processes, machines, clusters), it’ll be necessary to be able to:

- address messages to specific entities (actors, really! @tslominski 😄)
- pass addresses of these entities to other entities

So, in a sense, a 👍 @Rich_Morin

---

<div class="post-metadata">

**Author:** ![tslominski](https://yyz2.discourse-cdn.com/flex034/user_avatar/forum.thousandbrains.org/tslominski/32/5_2.png) [@tslominski](https://forum.thousandbrains.org/u/tslominski)\
**Post date:** [December 17, 2024, 7:04pm UTC](https://forum.thousandbrains.org/t/cmp-notions-and-questions/316/3 "2024-12-17T19:04:03Z")

</div>

I spent a lot of time thinking through actor addressing when distributed systems consumed me. The [Capability URI specification](https://github.com/capabilityio/capability-uri) would be my starting point for an address format.

---

<div class="post-metadata">

**Author:** ![Rich\_Morin](https://yyz2.discourse-cdn.com/flex034/user_avatar/forum.thousandbrains.org/rich_morin/32/89_2.png) [@Rich\_Morin](https://forum.thousandbrains.org/u/Rich_Morin)\
**Post date:** [December 17, 2024, 8:05pm UTC](https://forum.thousandbrains.org/t/cmp-notions-and-questions/316/4 "2024-12-17T20:05:06Z")

</div>

I took a quick look at the Capability URI specification and must confess that I don’t understand it at all. @tslominski, could you explain its motivations and (erm) capabilities?

That said, almost any language-neutral message addressing format would be fine with me, particularly if libraries are available for the sending and receiving actors.

FWIW, a distributed address in Elixir might look like:

```
<0.123.0>@node2@192.168.1.11

```

where `<0.123.0>` is the process ID (aka PID), `node2` is the BEAM (VM) instance, and `192.168.1.11` is an IP address for the CPU. I assume that a DNS address could be used instead of an IP address, as:

```
 <0.123.0>@node2@foo.bar.com

```

-r

---

<div class="post-metadata">

**Author:** ![tslominski](https://yyz2.discourse-cdn.com/flex034/user_avatar/forum.thousandbrains.org/tslominski/32/5_2.png) [@tslominski](https://forum.thousandbrains.org/u/tslominski)\
**Post date:** [December 17, 2024, 11:36pm UTC](https://forum.thousandbrains.org/t/cmp-notions-and-questions/316/5 "2024-12-17T23:36:59Z")

</div>

Capability URI is intended to be a simplified [RFC 3986 Uniform Resource Identifier](https://datatracker.ietf.org/doc/html/rfc3986#section-3).

```auto
The following are two example URIs and their component parts:

         foo://example.com:8042/over/there?name=ferret#nose
         \_/ \ ______________/\_________ / \ _________/ \__ /
          | | | | |
       scheme authority path query fragment
          | _____________________|__
         / \ / \
         urn:example:animal:ferret:nose

```

It is “simplified” in the sense that Capability URI skips `path` and `query` when `authority` is present (indicated by the presence of `//`).

I wouldn’t get caught up on capabilities. The main idea I want to convey is that we have an exhaustive uniform resource identifier standard, RFC 3986, that we can use.

---

<div class="post-metadata">

**Author:** ![Rich\_Morin](https://yyz2.discourse-cdn.com/flex034/user_avatar/forum.thousandbrains.org/rich_morin/32/89_2.png) [@Rich\_Morin](https://forum.thousandbrains.org/u/Rich_Morin)\
**Post date:** [December 18, 2024, 2:34am UTC](https://forum.thousandbrains.org/t/cmp-notions-and-questions/316/6 "2024-12-18T02:34:29Z")

</div>

So maybe the Python app could send to something like this?

```
urn:hostname:nodename:0.123.0

```

How should the Elixir app send messages back?

-r

---

<div class="post-metadata">

**Author:** ![tslominski](https://yyz2.discourse-cdn.com/flex034/user_avatar/forum.thousandbrains.org/tslominski/32/5_2.png) [@tslominski](https://forum.thousandbrains.org/u/tslominski)\
**Post date:** [December 18, 2024, 3:43am UTC](https://forum.thousandbrains.org/t/cmp-notions-and-questions/316/7 "2024-12-18T03:43:47Z")

</div>

In my mind, there is a distinction between messages, addresses, and transport.

CMP specifies what is in the messages.

A URI scheme specifies addresses.

Transport can be anything: in-memory, IPC, UDP, HTTP, MQTT, etc.

Since ~~it~~ transport can be anything, then whatever is easiest may be the best way to start? I don’t have enough Erlang experience to recommend what the easiest thing would be. But since I’m coming from the framing that the transport can be anything, searching for Python Erlang interop got me to [Pyrlang](https://github.com/Pyrlang) which seems like some sort of transport between the two.

A thought for later down the line… I think there may also be benefits to specifying how to marshall and unmarshall CMP into and from its “on-the-wire” representation. For example, [Apache Arrow](https://arrow.apache.org/docs/index.html) achieved desirable characteristics by zero-copy shared memory for analytical processing and coevolving storage format with in-memory format. By analogy, a similar thinking through Monty and CMP use cases and coevolving in-memory and serialized format may end up with desirable properties.

---

<div class="post-metadata">

**Author:** ![tslominski](https://yyz2.discourse-cdn.com/flex034/user_avatar/forum.thousandbrains.org/tslominski/32/5_2.png) [@tslominski](https://forum.thousandbrains.org/u/tslominski)\
**Post date:** [December 18, 2024, 3:57am UTC](https://forum.thousandbrains.org/t/cmp-notions-and-questions/316/8 "2024-12-18T03:57:03Z")

</div>

As specifics are being considered… I would consider [Real Logic’s Aeron](https://github.com/real-logic/aeron/wiki/Transport-Protocol-Specification) as one source of inspiration for how Monty could communicate at scale. It’s been a few years since I looked into it so maybe my memory is failing me. But, from what I remember, it may have desirable properties that might map well onto messaging patterns that Monty could end up with.

> Aeron attempts to address the following:
> 
> - high-throughput and low-latency communication for unicast and multicast
> - reliable multicast operation for modest receiver set size (\< 100 receivers)
> - multiple transmission media support (UDP & Shared Memory)
> - multiple streams that can provide different QoS
> - effective flow and congestion control for multicast and unicast
> - receiver application paced flow control on a per stream basis
> - easy monitoring of buffering on a per stream basis
> - flow control tied to message processing (as opposed to just delivery for processing later)

---

<div class="post-metadata">

**Author:** ![Rich\_Morin](https://yyz2.discourse-cdn.com/flex034/user_avatar/forum.thousandbrains.org/rich_morin/32/89_2.png) [@Rich\_Morin](https://forum.thousandbrains.org/u/Rich_Morin)\
**Post date:** [December 18, 2024, 6:20am UTC](https://forum.thousandbrains.org/t/cmp-notions-and-questions/316/9 "2024-12-18T06:20:17Z")

</div>

@tslominski seems to be quite focused on the speed of message transmission, promoting copy nothing approaches, shared memory, etc. Problem is, the BEAM is basically a “copy everything, share nothing system”. So, can anyone give me an idea of how important transfer speed is likely to be in a massively scaled up Monty implementation? Inquiring gnomes need to mine…

---

<div class="post-metadata">

**Author:** ![vclay](https://yyz2.discourse-cdn.com/flex034/user_avatar/forum.thousandbrains.org/vclay/32/4_2.png) [@vclay](https://forum.thousandbrains.org/u/vclay)\
**Post date:** [December 18, 2024, 9:21am UTC](https://forum.thousandbrains.org/t/cmp-notions-and-questions/316/10 "2024-12-18T09:21:24Z")

</div>

I’m not very familiar with a lot that you are discussing in this thread but just to add my thoughts on your original questions from a neuroscience (+Monty) perspective:

- First I’d like to highlight again what @tslominski said, that the CMP currently just specifies the message content, not how it is routed. We have thought a bit about how connectivity may be learned and how attention may factor into this but haven’t actually realized any of that in the implementation. We currently just specify the connectivity between LMs and SMs in the experiment config.

- The reason we are including sender\_id in the messages is so the receiving LM can correctly associate the incoming features to the features stored in its model. For instance, an LM may receive input from another LM as well as direct input from a sensor module and then needs to know which features correspond to what entries in its learned model. In the brain this would just be physical connections (so no need to transmit sender\_id).

- The reason we currently have sender\_type is more of a hack. We use it to check which features to use to define the pose (only sensor modules detect point\_normals and curvature\_directions). However, this could be rewritten to work without the sender\_type information. We included it in the state class since we thought it may be useful for weighting which information to rely on most (like prefer LM input if available, otherwise use SM input) but thinking about more I think this should be something the LM has to learn.

- In the brain, a cortical column has no idea where its input comes from and what it means. It has to learn over time how to interpret its inputs and uses a general process for this that works for input from any modality (or from other columns). To the columns all the inputs are just spikes and it makes no difference whether these correspond to information on the retina or a patch of skin. So I would argue against including even more information in the sender\_type.

- Since the brain doesn’t have sender\_id but just physical connections, I would be wary of a solution that requires the receiver to be able to talk back to the sender based on the sender\_id. Such bidirectional connectivity is not guaranteed in the brain.

- In the brain the different types of connectivity (voting vs. feed forward vs. feedback) originate and terminate in distinct layers of the cortical columns. Therefore the neuroanatomy directly conveys what type of message is being received and how it will be interpreted.

I hope this is useful.

- Viviane

---

<div class="post-metadata">

**Author:** ![Rich\_Morin](https://yyz2.discourse-cdn.com/flex034/user_avatar/forum.thousandbrains.org/rich_morin/32/89_2.png) [@Rich\_Morin](https://forum.thousandbrains.org/u/Rich_Morin)\
**Post date:** [December 18, 2024, 5:32pm UTC](https://forum.thousandbrains.org/t/cmp-notions-and-questions/316/11 "2024-12-18T17:32:09Z")

</div>

As a programmer, my tendency is to look for input data that might make the design easier to implement. However, I understand your desire to avoid giving your experiments too much help (in part because that might keep them from getting better at figuring things out on their own).

> [@vclay](#):
>
> In the brain the different types of connectivity (voting vs. feed forward vs. feedback) originate and terminate in distinct layers of the cortical columns. Therefore the neuroanatomy directly conveys what type of message is being received and how it will be interpreted.

In terms of Elixir messaging, there are two patterns for handling this sort of thing. The prevailing idiom uses a tuple for each message, as:

```
[:some_tag, ...message payload...]

```

Encoding things in `:some_tag` helps the BEAM to do pattern-based, prioritized dispatching. That is, it goes through each input pattern, ordered as they are in the source code, looking for the first matching tag. Putting things in the message payload forces the actor’s internal code to examine the input and decide what to do.

It seems to me that the first approach might be closer to the way the brain handles things: messages with a different type get automagically routed to the appropriate part of the column…

On a related note, I’m curious about how Monty is going to simulate the creation of connections between the columns. I understand that at least some of these are made during the life of the organism; are others predetermined by genetics? In any event, it seems like _something_ needs to let related columns get connected. What are your thoughts regarding this?

-r

---

<div class="post-metadata">

**Author:** ![tslominski](https://yyz2.discourse-cdn.com/flex034/user_avatar/forum.thousandbrains.org/tslominski/32/5_2.png) [@tslominski](https://forum.thousandbrains.org/u/tslominski)\
**Post date:** [December 18, 2024, 6:28pm UTC](https://forum.thousandbrains.org/t/cmp-notions-and-questions/316/12 "2024-12-18T18:28:56Z")

</div>

> [@Rich\_Morin](#):
>
> So, can anyone give me an idea of how important transfer speed is likely to be in a massively scaled up Monty implementation?

I don’t think we’ll really know until we have a massively scaled up Monty implementation. And if something is massively scaled, then there’ll probably be multiple tiers of transfers, each with its own speed. Ideally, we would try out multiple approaches in parallel and find suitable transports for specific use cases. Also, what’s suitable might change as Monty’s scale changes. I assume the importance of transfer speed is one of the things we’ll figure out as research continues.

---

<div class="post-metadata">

**Author:** ![Rich\_Morin](https://yyz2.discourse-cdn.com/flex034/user_avatar/forum.thousandbrains.org/rich_morin/32/89_2.png) [@Rich\_Morin](https://forum.thousandbrains.org/u/Rich_Morin)\
**Post date:** [December 18, 2024, 6:38pm UTC](https://forum.thousandbrains.org/t/cmp-notions-and-questions/316/13 "2024-12-18T18:38:44Z")

</div>

I often use a problem solving technique that involves studying a problem, then going off to do something else. Very often the “back office” will come up with an answer in a few hours or perhaps days. I suspect that a large-scale version of Monty might exhibit similar behavior. If so, the transfer speed for reporting the solution might not be all that critical, but the speed for finding it might be…

-r

---

<div class="post-metadata">

**Author:** ![DLed](https://yyz2.discourse-cdn.com/flex034/user_avatar/forum.thousandbrains.org/dled/32/162_2.png) [@DLed](https://forum.thousandbrains.org/u/DLed)\
**Post date:** [December 19, 2024, 12:05am UTC](https://forum.thousandbrains.org/t/cmp-notions-and-questions/316/14 "2024-12-19T00:05:00Z")

</div>

my only warning against aeron is that it’s a transport, and rather focused on Java (+ a c++ implementation).

Messaging wars is, however, a real thing. Perhaps, one should not jump right in immediately. Indeed, there are many distinct layers to messaging. Addressing things, transport and messaging patterns are three dimensions. Message serialization and deserialization another. Delivery guarantees, retries and other aspects come on top.

The number of option combination is enormous. As TBP has limited resources, I’d go with options that don’t require too much implementation, while delivering most value. To make sure, one doesn’t kill future options, I’d never couple to a specific messaging system (see e.g. [Hexagonal Architecture @ Netflix](https://netflixtechblog.com/ready-for-changes-with-hexagonal-architecture-b315ec967749)).

From the standpoint of application code, the most it needs to know is an api in the form `send(message)`, where, if necessary, an identity of a peer or a channel could be explicit, if necessary: `send(where, message)`. The rest is “infrastructure”. Assuming, correct error handling, of course.

When going this route, the messaging implementation can be replaced, e.g. swapped for local testing without additional infrastructure.

Addressing remote actors can be as simple as naming them, e.g. in static configuration or some form of registry.

For deciding on the messaging patterns I’d really recommend to look into the patterns described for [zeromq](https://learning-0mq-with-pyzmq.readthedocs.io/en/latest/pyzmq/patterns/patterns.html) as these generalize independent of the programming language.

As for simple options that have enough implementations in various technologies, brokered: [NATS](https://github.com/nats-io) seems to be the current runner-up, while brokerless or with hand-written brokers, [zeromq](https://zeromq.org/) is a safe cross-language choice. If one does choose the erlang way, no infrastructure is necessary, because erlang native clustering provides discovery, addressing, and, of course, messaging. [Whatsapp seems to know how to scale an Erlang cluster to 10k Nodes](https://codesync.global/media/maxim-fedorov-scaling-erlang-cluster-to-10-000-nodes/), meaning 10k nodes of potentially millions of processes each. Partisan is another [planet-scale](https://partisan.dev/#home) approach. That should be good enough for now, and running a small cluster is part of the demo in my initial post 😄.

Standards like MQTT or AMQP are good but with added complexities, which one would initially probably not need. With ports&adapters (“hexagonal” architecture), one can always switch to a more complex messaging infrastructure later.

Perhaps, one note on message guarantees. The brain is wet-ware, so, physically, there’s no delivery guarantee of messages. Even interference is highly likely to happen. Thus, perhaps, complex features, such as delivery guarantees are not as important for distributed Monty, as these are likely to couple that implementation detail, potentially closing the door on creative robust voting algorithms.

---

<div class="post-metadata">

**Author:** ![Rich\_Morin](https://yyz2.discourse-cdn.com/flex034/user_avatar/forum.thousandbrains.org/rich_morin/32/89_2.png) [@Rich\_Morin](https://forum.thousandbrains.org/u/Rich_Morin)\
**Post date:** [December 19, 2024, 1:29am UTC](https://forum.thousandbrains.org/t/cmp-notions-and-questions/316/15 "2024-12-19T01:29:18Z")

</div>

Hexagonal Architecture sounds very tasty, viewed from a distance. Might anyone here have Real World experience in using it? All too often an approach which works well for large corporations is too heavyweight for small projects, and vice versa).

FWIW, my preference is to start with simple, popular standards (e.g., JSON, UDP, URI), which are likely to have support libraries in any target language of interest, but are not tightly bound to any given implementation.

All of this is far above my pay grade, making me a confused puppy, so I asked ChatGPT for help:

> I’d like to find a set of language-neutral addressing, communication, and data formats for very large scale, but sparse message passing (e.g., among 100K Actors). The use case is the Thousand Brains Project’s “Monty” code base, which is currently coded in Python. The initial cross-language target is Elixir, but other languages may be involved over time. So, I’d like to base the initial implementation on extremely popular standards (e.g., JSON, UDP), but use something like the Hexagonal Architecture to allow flexibility going forward. Suggestions?

ChatGPT seems to agree with much of what has been said so far in this thread. Here is the summary from the [session](https://chatgpt.com/share/67637304-4e40-8005-b9ee-73effa8f943b):

> - **Transport** : Start with **UDP** or **ZeroMQ** for flexibility.
> - **Serialization** : Start with **JSON** , but abstract it to switch to **Protobuf** or **MessagePack** later.
> - **Architecture** : Implement a **Hexagonal Architecture** for modularity.
> - **Addressing** : Use URI-like addressing and a registry service for flexibility.
> 
> This approach will meet your immediate needs (Python to Elixir) while allowing scalability and adaptability to other languages and protocols in the future.

(ducks)

-r

---

<div class="post-metadata">

**Author:** ![DLed](https://yyz2.discourse-cdn.com/flex034/user_avatar/forum.thousandbrains.org/dled/32/162_2.png) [@DLed](https://forum.thousandbrains.org/u/DLed)\
**Post date:** [December 19, 2024, 8:58am UTC](https://forum.thousandbrains.org/t/cmp-notions-and-questions/316/16 "2024-12-19T08:58:06Z")

</div>

In this case hexagonal architecture (or rather ports and adapters) is a matter of introducing one variable. You can see how it enabled Netflix to change technology at a lower cost. If that term sounds too complicated, Dependency Inversion is the same thing - just don’t couple application code to external libraries or I/O, which messaging is.

---

<div class="post-metadata">

**Author:** ![DLed](https://yyz2.discourse-cdn.com/flex034/user_avatar/forum.thousandbrains.org/dled/32/162_2.png) [@DLed](https://forum.thousandbrains.org/u/DLed)\
**Post date:** [December 19, 2024, 3:10pm UTC](https://forum.thousandbrains.org/t/cmp-notions-and-questions/316/17 "2024-12-19T15:10:51Z")

</div>

> [@Rich\_Morin](#):
>
> **Transport** : Start with **UDP** or **ZeroMQ** for flexibility.

interestingly, here, the “approximation of life” mixes architectural levels. UDP is a protocol, while ZeroMQ is a messaging library (or a set of libraries, with a standardized API).

Supporting quote from [docs](http://wiki.zeromq.org/docs:features):

> Since version 4.2, libzmq [supports UDP](https://libzmq.readthedocs.io/en/latest/zmq_udp.html) in Unicast and Multicast modes.

example: [radio-dish.py](https://github.com/zeromq/pyzmq/blob/main/examples/draft/radio-dish.py)

Although, with ZeroMQ I’d first go for tcp. Several years ago I’ve benchmarked its throughput between a PC and a Raspberry PI 3 via LAN, and it was millions of messages in C, and an order of magnitude less than that in Python.

---

<div class="post-metadata">

**Author:** ![DLed](https://yyz2.discourse-cdn.com/flex034/user_avatar/forum.thousandbrains.org/dled/32/162_2.png) [@DLed](https://forum.thousandbrains.org/u/DLed)\
**Post date:** [December 19, 2024, 5:12pm UTC](https://forum.thousandbrains.org/t/cmp-notions-and-questions/316/18 "2024-12-19T17:12:45Z")

</div>

@tslominski @Rich_Morin here’s a little example repo to see Pyrlang/Elixir sending each other messages in action: [GitHub - d-led/pyrlang-elixir-example: A Pyrlang and Elixir interop example](https://github.com/d-led/pyrlang-elixir-example)

UPD: CI demo: [more streamlined feedback · d-led/pyrlang-elixir-example@3533d90 · GitHub](https://github.com/d-led/pyrlang-elixir-example/actions/runs/12433569306/job/34715398107#step:3:313)

---

<div class="post-metadata">

**Author:** ![dgreenberg](https://avatars.discourse-cdn.com/v4/letter/d/d6d6ee/32.png) [@dgreenberg](https://forum.thousandbrains.org/u/dgreenberg)\
**Post date:** [January 5, 2025, 1:36am UTC](https://forum.thousandbrains.org/t/cmp-notions-and-questions/316/19 "2025-01-05T01:36:25Z")

</div>

New here, in the middleware space so thought I could possibly add something.

Agree need for abstraction/wrapper layer between middleware and application.  
This allows decoupling app development from infra changes.  
Will require some thought as to node/entity setup and config.

Look at ROS2’s RMW layer that allows for multiple DDS/Zenoh implementations.

It has a lot of room for improvement but the concept is there.

Would lean to pub/sub pattern for one-to-many and many-to-one as well as async decoupling of processes.

Would lean towards decentralized vs a centralized broker for distributed process across multiple hosts re: actuators/sensors.

Questions/requirements to ask would be:

- API/Language support
- Transport support
- Discovery support
- Performance/scale factors such as entity/node quantity and message rate/frequency
