Files
subcoding/grow/definition.go

163 lines
2.9 KiB
Go
Raw Normal View History

2021-11-20 19:38:31 -10:00
package grow
2021-11-20 18:51:19 -10:00
import "io"
import "gopkg.in/yaml.v2"
2021-11-20 20:17:56 -10:00
import "github.com/firestuff/subcoding/vm"
2021-11-20 18:51:19 -10:00
type Definition struct {
GlobalMemorySize uint64 `yaml:"global_memory_size"`
FunctionMemorySize uint64 `yaml:"function_memory_size"`
2021-11-20 19:25:16 -10:00
InstructionLimit uint64 `yaml:"instruction_limit"`
2021-11-20 18:51:19 -10:00
Samples []*Sample `yaml:"samples"`
}
func NewDefinition(r io.Reader) (*Definition, error) {
2021-11-20 18:51:19 -10:00
dec := yaml.NewDecoder(r)
dec.SetStrict(true)
def := &Definition{}
err := dec.Decode(def)
if err != nil {
return nil, err
}
return def, nil
}
2021-11-20 20:17:56 -10:00
func (def *Definition) Grow(statusChan chan<- Status) (*vm.Program, error) {
status := Status{
TargetScore: def.sumOuts(),
2021-11-20 20:17:56 -10:00
}
if statusChan != nil {
statusChan <- status
}
prog := &vm.Program{
GlobalMemorySize: def.GlobalMemorySize,
FunctionMemorySize: def.FunctionMemorySize,
InstructionLimit: def.InstructionLimit,
Functions: []*vm.Function{
&vm.Function{},
},
}
2021-11-20 20:17:56 -10:00
for {
status.Attempts++
Mutate(def, prog)
2021-11-20 20:17:56 -10:00
score, err := def.score(prog)
2021-11-20 20:17:56 -10:00
if err != nil {
// Can never get best score
continue
2021-11-20 20:17:56 -10:00
}
if score > status.BestScore {
status.BestScore = score
status.BestProgram = prog.Copy()
2021-11-20 20:17:56 -10:00
if statusChan != nil {
statusChan <- status
}
if status.BestScore == status.TargetScore {
2021-11-22 21:34:55 -08:00
err = def.minifyProgram(prog)
if err != nil {
if statusChan != nil {
close(statusChan)
}
return nil, err
}
status.BestProgram = prog.Copy()
2021-11-22 21:34:55 -08:00
if statusChan != nil {
statusChan <- status
}
if statusChan != nil {
close(statusChan)
}
2021-11-20 20:17:56 -10:00
return prog, nil
}
}
}
}
func (def *Definition) score(prog *vm.Program) (uint64, error) {
2021-11-20 20:17:56 -10:00
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
}
2021-11-20 20:17:56 -10:00
score += sample.matchingOuts(state)
2021-11-20 20:17:56 -10:00
}
return score, nil
}
func (def *Definition) sumOuts() uint64 {
sum := uint64(0)
for _, sample := range def.Samples {
sum += uint64(len(sample.Out))
}
return sum
}
2021-11-22 21:34:55 -08:00
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
2021-11-22 21:34:55 -08:00
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
}