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"`
|
|
|
|
|
}
|
|
|
|
|
|
2021-11-20 19:17:35 -10:00
|
|
|
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{
|
2021-11-20 20:30:16 -10:00
|
|
|
TargetScore: def.sumOuts(),
|
2021-11-20 20:17:56 -10:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if statusChan != nil {
|
|
|
|
|
statusChan <- status
|
|
|
|
|
}
|
|
|
|
|
|
2021-11-22 20:33:22 -08:00
|
|
|
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++
|
|
|
|
|
|
2021-11-22 22:19:38 -08:00
|
|
|
Mutate(def, prog)
|
2021-11-20 20:17:56 -10:00
|
|
|
|
2021-11-20 20:30:16 -10:00
|
|
|
score, err := def.score(prog)
|
2021-11-20 20:17:56 -10:00
|
|
|
if err != nil {
|
2021-11-22 20:46:20 -08:00
|
|
|
// Can never get best score
|
|
|
|
|
continue
|
2021-11-20 20:17:56 -10:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if score > status.BestScore {
|
|
|
|
|
status.BestScore = score
|
2021-11-22 22:19:38 -08:00
|
|
|
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
|
|
|
|
|
}
|
2021-11-22 22:19:38 -08:00
|
|
|
status.BestProgram = prog.Copy()
|
2021-11-22 21:34:55 -08:00
|
|
|
|
|
|
|
|
if statusChan != nil {
|
|
|
|
|
statusChan <- status
|
|
|
|
|
}
|
|
|
|
|
|
2021-11-20 20:30:16 -10:00
|
|
|
if statusChan != nil {
|
|
|
|
|
close(statusChan)
|
|
|
|
|
}
|
|
|
|
|
|
2021-11-20 20:17:56 -10:00
|
|
|
return prog, nil
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-11-20 20:30:16 -10:00
|
|
|
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)
|
|
|
|
|
|
2021-11-22 20:46:20 -08:00
|
|
|
err = state.Execute()
|
|
|
|
|
if err != nil {
|
|
|
|
|
return 0, err
|
|
|
|
|
}
|
2021-11-20 20:17:56 -10:00
|
|
|
|
2021-11-20 20:30:16 -10:00
|
|
|
score += sample.matchingOuts(state)
|
2021-11-20 20:17:56 -10:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return score, nil
|
|
|
|
|
}
|
2021-11-20 20:30:16 -10:00
|
|
|
|
|
|
|
|
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 22:19:38 -08:00
|
|
|
|
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
|
|
|
|
|
}
|