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