main.go raw
1 // Command bootstrap is the minimal self-reproducing kernel.
2 // It executes the full lifecycle: read spore, nucleate, grow,
3 // govern, sporulate, emit, evaluate. Nothing more.
4 //
5 // Usage:
6 //
7 // bootstrap abiogenesis + stdin input
8 // bootstrap -spore F germinate from spore file
9 // bootstrap -spore F input.txt germinate + file input
10 // bootstrap < input.txt abiogenesis + piped input
11 // bootstrap -strategy abiogenesis with Art of War DNA
12 package main
13
14 import (
15 "bytes"
16 "context"
17 _ "embed"
18 "flag"
19 "fmt"
20 "io"
21 "os"
22 "time"
23
24 "git.mleku.dev/mleku/dendrite/pkg/axiom"
25 "git.mleku.dev/mleku/dendrite/pkg/emit"
26 "git.mleku.dev/mleku/dendrite/pkg/enzyme"
27 "git.mleku.dev/mleku/dendrite/pkg/fitness"
28 "git.mleku.dev/mleku/dendrite/pkg/grow"
29 "git.mleku.dev/mleku/dendrite/pkg/hexagram"
30 "git.mleku.dev/mleku/dendrite/pkg/lattice"
31 "git.mleku.dev/mleku/dendrite/pkg/spore"
32 "git.mleku.dev/mleku/dendrite/pkg/strategy"
33 )
34
35 //go:embed main.go
36 var ownSource string
37
38 // tagConstraint is the simplest constraint: admits elements with matching type.
39 type tagConstraint struct{ tag string }
40
41 func (c tagConstraint) Tag() string { return c.tag }
42 func (c tagConstraint) Admits(e axiom.Element) bool { return e.Type() == c.tag }
43 func constraintFactory(tag string) axiom.Constraint { return tagConstraint{tag} }
44
45 var goRoot string
46
47 func init() {
48 goRoot = os.Getenv("GOROOT")
49 if goRoot == "" {
50 goRoot = "/usr/local/go"
51 }
52 }
53
54 func main() {
55 sporeFile := flag.String("spore", "", "spore file to germinate from")
56 outDir := flag.String("out", ".", "output directory for emitted files")
57 strategyMode := flag.Bool("strategy", false, "embed Art of War strategy layer")
58 flag.Parse()
59
60 os.MkdirAll(*outDir, 0755)
61
62 // 1. READ SPORE
63 var parent *spore.Spore
64 if *sporeFile != "" {
65 f, err := os.Open(*sporeFile)
66 if err != nil {
67 fatal("open spore: %v", err)
68 }
69 parent, err = spore.ReadSpore(f)
70 f.Close()
71 if err != nil {
72 fatal("read spore: %v", err)
73 }
74 fmt.Printf("germinate: gen=%d nodes=%d\n", parent.Generation, parent.TotalNodes)
75 }
76
77 // 2. NUCLEATE
78 var l *lattice.Lattice
79 if parent != nil {
80 size := parent.TotalNodes
81 if size < 64 {
82 size = 64
83 }
84 l = parent.Nucleate(size, constraintFactory)
85 } else {
86 l = abiogenesis()
87 }
88 fmt.Printf("lattice: %d nodes\n", l.Size())
89
90 // 3. STRATEGY LAYER
91 if *strategyMode {
92 strategy.Seed(l)
93 }
94
95 // 4. ACCEPT INPUT
96 solution := make(chan axiom.Element, 512)
97 go func() {
98 defer close(solution)
99 var r io.Reader
100 if len(flag.Args()) > 0 {
101 f, err := os.Open(flag.Arg(0))
102 if err != nil {
103 fmt.Fprintf(os.Stderr, "input: %v\n", err)
104 return
105 }
106 defer f.Close()
107 r = f
108 } else {
109 r = os.Stdin
110 }
111 for e := range (enzyme.Text{}).Digest(r) {
112 if e.Type() != "space" {
113 solution <- e
114 }
115 }
116 }()
117
118 // 5. GROW
119 growCtx, growCancel := context.WithTimeout(context.Background(), 3*time.Second)
120 growEv := make(chan grow.Event, 256)
121 go func() {
122 grow.Run(growCtx, l, solution, grow.Config{MaxSteps: 500, Workers: 4}, growEv)
123 close(growEv)
124 }()
125 bonded := 0
126 for ev := range growEv {
127 if ev.Type == grow.EventBonded {
128 bonded++
129 }
130 }
131 growCancel()
132 fmt.Printf("growth: %d bonded\n", bonded)
133
134 // 6. HEXAGRAM ENGINE
135 engSolution := make(chan axiom.Element, 128)
136 engCtx, engCancel := context.WithTimeout(context.Background(), 2*time.Second)
137 engEv := make(chan hexagram.Event, 256)
138 go func() {
139 hexagram.RunEngine(engCtx, l, hexagram.EngineConfig{
140 Interval: 16 * time.Millisecond, // 2^4 ms — epoch-aligns with dissolve at 10^2 ms
141 Solution: engSolution,
142 MaxNewSites: 4,
143 }, engEv)
144 close(engEv)
145 }()
146 ops := make(map[hexagram.Op]int)
147 for ev := range engEv {
148 ops[ev.Op]++
149 }
150 engCancel()
151 close(engSolution)
152 fmt.Printf("engine: %d operations\n", sumOps(ops))
153
154 // 7. SPORULATE
155 seed := spore.Extract(l, parent)
156 sporeOut := fmt.Sprintf("%s/bootstrap.gen%d.spore", *outDir, seed.Generation)
157 if sf, err := os.Create(sporeOut); err == nil {
158 seed.WriteTo(sf)
159 sf.Close()
160 }
161
162 // 8. EMIT GO SOURCE
163 files := emit.Harvest(l)
164 emitFile := ""
165 if len(files) > 0 {
166 var biggest string
167 var bc int
168 for k, v := range files {
169 if len(v) > bc {
170 biggest = k
171 bc = len(v)
172 }
173 }
174 emitFile = fmt.Sprintf("%s/bootstrap.gen%d.go", *outDir, seed.Generation)
175 var buf bytes.Buffer
176 emit.EmitGo(files[biggest], &buf)
177
178 // Apply polymorphic transformation.
179 polymorphed := Polymorph(buf.Bytes())
180 if f, err := os.Create(emitFile); err == nil {
181 f.Write(polymorphed)
182 f.Close()
183 fmt.Printf("emit: %s (%d fragments, polymorphed)\n", emitFile, bc)
184 }
185 }
186
187 // 9. EVALUATE FITNESS
188 if emitFile != "" {
189 emitted := readFile(emitFile)
190 score := fitness.Score{}
191 score.Source = fitness.SourceSimilarity(ownSource, emitted)
192 score.Compute()
193 seed.Fitness = &spore.FitnessScore{
194 Source: score.Source,
195 Binary: score.Binary,
196 Behav: score.Behav,
197 Overall: score.Overall,
198 }
199 fmt.Printf("fitness: src=%.3f overall=%.3f\n", score.Source.Float64(), score.Overall.Float64())
200 }
201
202 // Write final spore with fitness.
203 if sf, err := os.Create(sporeOut); err == nil {
204 seed.WriteTo(sf)
205 sf.Close()
206 }
207 fmt.Printf("spore: %s (gen=%d)\n", sporeOut, seed.Generation)
208 }
209
210 func abiogenesis() *lattice.Lattice {
211 l := lattice.New()
212 var all []*lattice.Node
213
214 // 48 word sites + 8 punct sites.
215 for range 48 {
216 n := l.AddNode([]axiom.Constraint{tagConstraint{"word"}})
217 n.SetEnergy(true)
218 all = append(all, n)
219 }
220 for range 8 {
221 n := l.AddNode([]axiom.Constraint{tagConstraint{"punct"}})
222 n.SetEnergy(true)
223 all = append(all, n)
224 }
225 for i, n := range all {
226 l.Connect(n, all[(i+1)%len(all)])
227 }
228 return l
229 }
230
231 func readFile(path string) string {
232 data, _ := os.ReadFile(path)
233 return string(data)
234 }
235
236 func fatal(f string, args ...any) {
237 fmt.Fprintf(os.Stderr, f+"\n", args...)
238 os.Exit(1)
239 }
240
241 func sumOps(m map[hexagram.Op]int) int {
242 n := 0
243 for _, v := range m {
244 n += v
245 }
246 return n
247 }
248