package grow import "io" import "gopkg.in/yaml.v2" import "github.com/firestuff/subcoding/vm" type Definition struct { GlobalMemorySize uint64 `yaml:"global_memory_size"` FunctionMemorySize uint64 `yaml:"function_memory_size"` InstructionLimit uint64 `yaml:"instruction_limit"` Samples []*Sample `yaml:"samples"` } func NewDefinition(r io.Reader) (*Definition, error) { dec := yaml.NewDecoder(r) dec.SetStrict(true) def := &Definition{} err := dec.Decode(def) if err != nil { return nil, err } return def, nil } func (def *Definition) Grow(statusChan chan<- Status) (*vm.Program, error) { status := Status{ TargetScore: def.sumOuts(), } if statusChan != nil { statusChan <- status } prog := &vm.Program{ GlobalMemorySize: def.GlobalMemorySize, FunctionMemorySize: def.FunctionMemorySize, InstructionLimit: def.InstructionLimit, Functions: []*vm.Function{ &vm.Function{}, }, } for { status.Attempts++ Mutate(prog) score, err := def.score(prog) if err != nil { // Can never get best score continue } if score > status.BestScore { status.BestScore = score status.BestProgram = prog if statusChan != nil { statusChan <- status } if status.BestScore == status.TargetScore { err = def.minifyProgram(prog) if err != nil { if statusChan != nil { close(statusChan) } return nil, err } if statusChan != nil { statusChan <- status } if statusChan != nil { close(statusChan) } return prog, nil } } } } func (def *Definition) score(prog *vm.Program) (uint64, error) { score := uint64(0) for _, sample := range def.Samples { state, err := vm.NewState(prog) if err != nil { return 0, err } sample.SetInputs(state) err = state.Execute() if err != nil { return 0, err } score += sample.matchingOuts(state) } return score, nil } func (def *Definition) sumOuts() uint64 { sum := uint64(0) for _, sample := range def.Samples { sum += uint64(len(sample.Out)) } return sum } func (def *Definition) minifyProgram(prog *vm.Program) error { for f := 0; f < len(prog.Functions); f++ { err := def.minifyFunction(prog, f) if err != nil { return err } } return nil } func (def *Definition) minifyFunction(prog *vm.Program, f int) error { baseScore, err := def.score(prog) if err != nil { return err } for loop := true; loop; { loop = false for i := 0; i < len(prog.Functions[f].Instructions); i++ { origInstructions := prog.Functions[f].Instructions tmp := make([]*vm.Instruction, len(prog.Functions[f].Instructions)) copy(tmp, prog.Functions[f].Instructions) prog.Functions[f].Instructions = append(tmp[:i], tmp[i+1:]...) newScore, err := def.score(prog) if err == nil && newScore >= baseScore { loop = true break } else { prog.Functions[f].Instructions = origInstructions } } } return nil }