Skip to content

A Golang library to help implement kurobako's solvers and problems

License

Notifications You must be signed in to change notification settings

sile/kurobako-go

Repository files navigation

kurobako-go

Software License GoDoc Go Report Card Actions Status

A Golang library to help implement kurobako's solvers and problems.

Usage Examples

1. Define a solver based on random search

// file: random-solver.go
package main

import (
	"math"
	"math/rand"

	"github.com/sile/kurobako-go"
)

type randomSolverFactory struct{}

func (r *randomSolverFactory) Specification() (*kurobako.SolverSpec, error) {
	spec := kurobako.NewSolverSpec("Random Search")
	return &spec, nil
}

func (r *randomSolverFactory) CreateSolver(seed int64, problem kurobako.ProblemSpec) (kurobako.Solver, error) {
	rng := rand.New(rand.NewSource(seed))
	return &randomSolver{rng, problem}, nil
}

type randomSolver struct {
	rng     *rand.Rand
	problem kurobako.ProblemSpec
}

func (r *randomSolver) sampleUniform(low float64, high float64) float64 {
	return r.rng.Float64()*(high-low) + low
}

func (r *randomSolver) sampleLogUniform(low float64, high float64) float64 {
	return math.Exp(r.sampleUniform(math.Log(low), math.Log(high)))
}

func (r *randomSolver) Ask(idg *kurobako.TrialIDGenerator) (kurobako.NextTrial, error) {
	var trial kurobako.NextTrial

	for _, p := range r.problem.Params {
		if p.Distribution == kurobako.Uniform {
			value := r.sampleUniform(p.Range.Low(), p.Range.High())
			trial.Params = append(trial.Params, &value)
		} else {
			value := r.sampleLogUniform(p.Range.Low(), p.Range.High())
			trial.Params = append(trial.Params, &value)
		}
	}

	trial.TrialID = idg.Generate()
	trial.NextStep = r.problem.Steps.Last()
	return trial, nil
}

func (r *randomSolver) Tell(trial kurobako.EvaluatedTrial) error {
	return nil
}

func main() {
	runner := kurobako.NewSolverRunner(&randomSolverFactory{})
	if err := runner.Run(); err != nil {
		panic(err)
	}
}

2. Define a solver based on Goptuna

// file: goptuna-solver.go
package main

import (
	"github.com/c-bata/goptuna"
	"github.com/c-bata/goptuna/tpe"
	"github.com/sile/kurobako-go"
	"github.com/sile/kurobako-go/goptuna/solver"
)

func createStudy(seed int64) (*goptuna.Study, error) {
	sampler := tpe.NewSampler(tpe.SamplerOptionSeed(seed))
	return goptuna.CreateStudy("example-study", goptuna.StudyOptionSampler(sampler))
}

func main() {
	factory := solver.NewGoptunaSolverFactory(createStudy)
	runner := kurobako.NewSolverRunner(&factory)
	if err := runner.Run(); err != nil {
		panic(err)
	}
}

3. Define a problem that represents a quadratic function x**2 + y

// file: quadratic-problem.go
package main

import (
	"github.com/sile/kurobako-go"
)

type quadraticProblemFactory struct {
}

func (r *quadraticProblemFactory) Specification() (*kurobako.ProblemSpec, error) {
	spec := kurobako.NewProblemSpec("Quadratic Function")

	x := kurobako.NewVar("x")
	x.Range = kurobako.ContinuousRange{-10.0, 10.0}.ToRange()

	y := kurobako.NewVar("y")
	y.Range = kurobako.DiscreteRange{-3, 3}.ToRange()

	spec.Params = []kurobako.Var{x, y}

	spec.Values = []kurobako.Var{kurobako.NewVar("x**2 + y")}

	return &spec, nil
}

func (r *quadraticProblemFactory) CreateProblem(seed int64) (kurobako.Problem, error) {
	return &quadraticProblem{}, nil
}

type quadraticProblem struct {
}

func (r *quadraticProblem) CreateEvaluator(params []float64) (kurobako.Evaluator, error) {
	x := params[0]
	y := params[1]
	return &quadraticEvaluator{x, y}, nil
}

type quadraticEvaluator struct {
	x float64
	y float64
}

func (r *quadraticEvaluator) Evaluate(nextStep uint64) (uint64, []float64, error) {
	values := []float64{r.x*r.x + r.y}
	return 1, values, nil
}

func main() {
	runner := kurobako.NewProblemRunner(&quadraticProblemFactory{})
	if err := runner.Run(); err != nil {
		panic(err)
	}
}

4. Run a benchmark that uses the above solver and problem

// Define solver and problem.
$ SOLVER1=$(kurobako solver command go run random-solver.go)
$ SOLVER2=$(kurobako solver command go run goptuna-solver.go)
$ PROBLEM=$(kurobako problem command go run quadratic-problem.go)

// Execute benchmark.
$ kurobako studies --solvers $SOLVER1 $SOLVER2 --problems $PROBLEM | kurobako run > result.json

// Generate Markdown format report and visualization image.
$ cat result.json | kurobako report
$ cat result.json | kurobako plot curve

About

A Golang library to help implement kurobako's solvers and problems

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages