that's exponential growth, every value results in 2 output values
input "1" x1, get "2" x2, "3" x4, "4" x8, "5" x16, ...
also your use of goroutines to send mean you'll still run out of memory at 
some point

On Sunday, November 14, 2021 at 2:29:26 PM UTC Serge Hulne wrote:

> Hi,
>
> I am trying to code an observer pattern or a publish/submit pattern for a 
> sort of cellular automaton.
>
> The classical observer pattern does not to the trick because if a cell A 
> subscribes to changes in a cell B and vice-versa, the application will run 
> out of stack owing to the recursive approach (B.update() will call 
> A.update() and so on and the app will run out of stack). 
>
> So I though about using a publish/subscribe pattern where respective cells 
> pass each other messages, rather than calling each other's update() methods.
>
> Here is a simple example with two cells A and B:
>
> ```
> package main
>
> import (
> "fmt"
> ps "publish/pubsub"
> )
>
> func main() {
>
> fmt.Printf("Starting\n")
>
> chEnd := make(chan int)
>
> // initialize
> a := ps.NewNode(1, 0)
> b := ps.NewNode(2, 0)
>
> // connect nodes
> a.Connect(b.ChOut)
> b.Connect(a.ChOut)
>
> // Start listening
> a.Listen()
> b.Listen()
>
> // Start sending data on one arbitrary node
> // to start the process.
> a.ChIn <- 10
>
> <-chEnd
> }
> ```
> and the corresponding lib
>
> ```package lib
>
> import (
> "fmt"
> )
>
> type Node struct {
> Id int
> State int
> ChOut chan int
> ChIn chan int
> }
>
> func NewNode(id int, state int) Node {
> chout := make(chan int)
> var chin chan int
> return Node{id, state, chout, chin}
> }
>
> func (p *Node) Broadcast(inItem int) {
> p.ChOut <- inItem + 1
> //time.Sleep(100 * time.Millisecond)
> }
>
> func (p *Node) Listen() {
> go func() {
> for {
> select {
> case inItem := <-p.ChIn:
> fmt.Printf("%d: %d\n", p.Id, inItem)
> p.Broadcast(inItem)
> }
> }
> }()
> }
>
> func (p *Node) Connect(ch chan int) {
> p.ChIn = ch
> }
> ```
> Each node has a input and an output channe.
> The input channel of B is the output channel of A and vice-versa.
>
> Every update consists merely of incrementing the data passed by the other 
> cell.
>
> It seems to work. So far, so good.
>
> I tried to with a set of 4 cells A, B, C, D, in order to simulate a one 
> dimensional cellular automaton of sorts.
>
> In this second attempt, 
>
>    - each cell has two input channels (let and right) to listen to its 
>    closest left- and right-hand neighbour, respectively (ChinL and ChinR).
>    - each cell has to output channels to communicate its latest updated 
>    state to its closest neighbours (ChoutL and ChoutR).
>
> I must have done something wrong in the implementation of that scheme with 
> 4 cells, because it yields odd results : the values passed back and forth 
> between the 4 cells seem to hit a threshold instead of increasing at every 
> consecutive step: here is the code:
>
> ```
> package main
>
> import (
> "fmt"
> ps "publish/pubsub"
> )
>
> func main() {
>
> fmt.Printf("Starting\n")
>
> chEnd := make(chan int)
>
> // initialize
> a := ps.NewNode(1, 0)
> b := ps.NewNode(2, 0)
> c := ps.NewNode(3, 0)
> d := ps.NewNode(4, 0)
>
> // connect nodes
> a.ChInL = d.ChOutR
> a.ChInR = b.ChOutL
>
> b.ChInL = a.ChOutR
> b.ChInR = c.ChOutL
>
> c.ChInL = b.ChOutR
> c.ChInR = d.ChOutL
>
> d.ChInL = c.ChOutR
> d.ChInR = a.ChOutL
>
> // Start listening
> go a.Listen()
> go b.Listen()
> go c.Listen()
> go d.Listen()
>
> go a.Broadcast()
> go b.Broadcast()
> go c.Broadcast()
> go d.Broadcast()
>
> // Start sending data on one arbitrary node
> // to start the process.
> a.ChInL <- 1
>
> // Dummy read on channel to make main() wait
> <-chEnd
> }
>
> /*
> A B C D
> LR LR LR LR
> */
>
> ```
>
> and the corresponding lib
>
> ```
> package main
>
> import (
> "fmt"
> ps "publish/pubsub"
> )
>
> func main() {
>
> fmt.Printf("Starting\n")
>
> chEnd := make(chan int)
>
> // initialize
> a := ps.NewNode(1, 0)
> b := ps.NewNode(2, 0)
> c := ps.NewNode(3, 0)
> d := ps.NewNode(4, 0)
>
> // connect nodes
> a.ChInL = d.ChOutR
> a.ChInR = b.ChOutL
>
> b.ChInL = a.ChOutR
> b.ChInR = c.ChOutL
>
> c.ChInL = b.ChOutR
> c.ChInR = d.ChOutL
>
> d.ChInL = c.ChOutR
> d.ChInR = a.ChOutL
>
> // Start listening
> go a.Listen()
> go b.Listen()
> go c.Listen()
> go d.Listen()
>
> go a.Broadcast()
> go b.Broadcast()
> go c.Broadcast()
> go d.Broadcast()
>
> // Start sending data on one arbitrary node
> // to start the process.
> a.ChInL <- 1
>
> // Dummy read on channel to make main() wait
> <-chEnd
> }
>
> /*
> A B C D
> LR LR LR LR
> */
>
> ```
>
> package pubsub
>
> import (
> "fmt"
> "strings"
> )
>
> type Node struct {
> Id int
> State int
> ChOutL chan int
> ChOutR chan int
> ChInL chan int
> ChInR chan int
> ChIO chan int
> }
>
> func NewNode(id int, state int) Node {
> choutL := make(chan int)
> choutR := make(chan int)
> var chinL chan int
> var chinR chan int
> chIO := make(chan int)
> return Node{id, state, choutL, choutR, chinL, chinR, chIO}
> }
>
> func (p *Node) Broadcast() {
> for item := range p.ChIO {
> p.ChOutL <- item + 1
> p.ChOutR <- item + 1
> fmt.Printf("%d: %d %s\n", p.Id, item, strings.Repeat("*", item))
> }
> }
>
> func (p *Node) Listen() {
> for {
> //time.Sleep(100 * time.Millisecond)
> select {
> case inItem := <-p.ChInL:
> go func() {
> p.ChIO <- inItem
> }()
> case inItem := <-p.ChInR:
> go func() {
> p.ChIO <- inItem
> }()
> }
> }
> }
>
> ```
>
>
>
>
>
>
>

-- 
You received this message because you are subscribed to the Google Groups 
"golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to golang-nuts+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/golang-nuts/0bbc3729-a187-4af0-aca1-599e1369d4b0n%40googlegroups.com.

Reply via email to