kurobako

package module
v0.0.0-...-95985b3 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 19, 2020 License: MIT Imports: 8 Imported by: 12

README

kurobako-go

Software License GoDoc Go Report Card Actions Status

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

Usage Examples

// 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

Documentation

Overview

A library to help implement solvers and problems of kurobako.

kurobako is a black-box optimization tool. Please see https://github.com/sile/kurobako for the details.

Index

Constants

This section is empty.

Variables

View Source
var ErrorUnevalableParams = errors.New("unevalable params")

ErrorUnevalableParams is an error that is used when an evaluator encounters an infeasible parameter set.

Functions

This section is empty.

Types

type Capabilities

type Capabilities int64

Capabilities of a solver.

const (
	// UniformContinuous indicates that the solver can handle numerical parameters that have uniform continuous range.
	UniformContinuous Capabilities = 1 << iota

	// UniformDiscrete indicates that the solver can handle numerical parameters that have uniform discrete range.
	UniformDiscrete

	// LogUniformContinuous indicates that the solver can handle numerical parameters that have log-uniform continuous range.
	LogUniformContinuous

	// LogUniformDiscrete indicates that the solver can handle numerical parameters that have log-uniform discrete range.
	LogUniformDiscrete

	// Categorical indicates that the solver can handle categorical parameters.
	Categorical

	// Conditional indicates that the solver can handle conditional parameters.
	Conditional

	// MultiObjective indicates that the solver supports multi-objective optimization.
	MultiObjective

	// Concurrent indicates that the solver supports concurrent invocations of the ask method.
	Concurrent

	// AllCapabilities represents all of the capabilities.
	AllCapabilities Capabilities = UniformContinuous | UniformDiscrete | LogUniformContinuous |
		LogUniformDiscrete | Categorical | Conditional | MultiObjective | Concurrent
)

func (Capabilities) MarshalJSON

func (r Capabilities) MarshalJSON() ([]byte, error)

MarshalJSON encodes a Capabilities value to JSON bytes.

func (*Capabilities) UnmarshalJSON

func (r *Capabilities) UnmarshalJSON(data []byte) error

UnmarshalJSON decodes a Capabilities value from JSON bytes.

type CategoricalRange

type CategoricalRange struct {
	// Choices is the possible values in the range.
	Choices []string `json:"choices"`
}

CategoricalRange represents a categorical range (choices).

func (CategoricalRange) ToRange

func (r CategoricalRange) ToRange() Range

ToRange creates a Range object that contains the receiver object.

type ContinuousRange

type ContinuousRange struct {
	// Low is the lower bound of the range (inclusive).
	Low float64 `json:"low"`

	// High is the upper bound of the range (exclusive).
	High float64 `json:"high"`
}

ContinuousRange represents a numerical continuous range.

func (ContinuousRange) MarshalJSON

func (r ContinuousRange) MarshalJSON() ([]byte, error)

MarshalJSON encodes a ContinuousRange object to JSON bytes.

func (ContinuousRange) ToRange

func (r ContinuousRange) ToRange() Range

ToRange creates a Range object that contains the receiver object.

func (*ContinuousRange) UnmarshalJSON

func (r *ContinuousRange) UnmarshalJSON(data []byte) error

UnmarshalJSON decodes a ContinuousRange object from JSON bytes.

type DiscreteRange

type DiscreteRange struct {
	// Low is the lower bound of the range (inclusive).
	Low int64 `json:"low"`

	// High is the upper bound of the range (exclusive).
	High int64 `json:"high"`
}

DiscreteRange represents a numerical discrete range.

func (DiscreteRange) ToRange

func (r DiscreteRange) ToRange() Range

ToRange create a Range object that contains the receiver object.

type Distribution

type Distribution int

Distribution of the values of a parameter.

const (
	// Uniform indicates the values of the parameter are uniformally distributed.
	Uniform Distribution = iota

	// LogUniform indicates the values of the parameter are log-uniformally distributed.
	LogUniform
)

func (Distribution) MarshalJSON

func (r Distribution) MarshalJSON() ([]byte, error)

MarshalJSON encodes a Distribution value to JSON bytes.

func (Distribution) String

func (r Distribution) String() string

String returns the string representation of a Distribution value.

func (*Distribution) UnmarshalJSON

func (r *Distribution) UnmarshalJSON(data []byte) error

UnmarshalJSON decodes a Distribution value from JSON bytes.

type EvaluatedTrial

type EvaluatedTrial struct {
	// TrialID is the identifier of the trial.
	TrialID uint64 `json:"id"`

	// Values is the evaluation result of the trial.
	//
	// Note that if this is an empty slice, it means the trial contained an unevalable parameter set.
	Values []float64 `json:"values"`

	// CurrentStep is the current step of the evaluation process.
	CurrentStep uint64 `json:"current_step"`
}

EvaluatedTrial contains information about an evaluated trial.

type Evaluator

type Evaluator interface {
	// evaluate executes an evaluation process, at least, until the given step.
	Evaluate(nextStep uint64) (currentStep uint64, values []float64, err error)
}

Evaluator allows to execute an evaluation process.

type NextTrial

type NextTrial struct {
	// TrialID is the identifier of the trial.
	TrialID uint64 `json:"id"`

	// Params are the parameters to be evaluated.
	Params []*float64 `json:"params"`

	// NextStep is the next evaluable step.
	//
	// The evaluator must go through the next evaluation process beyond this step.
	// Note that if the value is 0, it means the trial was pruned by solver.
	NextStep uint64 `json:"next_step"`
}

NextTrial contains information about a trial to be evaluated.

func (NextTrial) MarshalJSON

func (r NextTrial) MarshalJSON() ([]byte, error)

MarshalJSON encodes a NextTrial object to JSON bytes.

type Problem

type Problem interface {
	// CreateEvaluator creates a new evaluator to evaluate the given parameter set.
	CreateEvaluator(params []float64) (Evaluator, error)
}

Problem allows to create a new evaluator instance.

type ProblemFactory

type ProblemFactory interface {
	// Specification returns the specification of the problem.
	Specification() (*ProblemSpec, error)

	// CreateProblem creates a new problem instance with the given random seed.
	CreateProblem(seed int64) (Problem, error)
}

ProblemFactory allows to create a new problem instance.

type ProblemRunner

type ProblemRunner struct {
	// contains filtered or unexported fields
}

ProblemRunner runs a black-box optimization problem.

func NewProblemRunner

func NewProblemRunner(factory ProblemFactory) *ProblemRunner

NewProblemRunner creates a new ProblemRunner that runs the given problem.

func (*ProblemRunner) Run

func (r *ProblemRunner) Run() error

Run runs the problem.

type ProblemSpec

type ProblemSpec struct {
	// Name is the name of the problem.
	Name string `json:"name"`

	// Attrs is the attributes of the problem.
	Attrs map[string]string `json:"attrs"`

	// Params is the definition of the parameters domain of the problem.
	Params []Var `json:"params_domain"`

	// Values is the definition of the values domain of the problem.
	Values []Var `json:"values_domain"`

	// Steps is the sequence of the evaluation steps of the problem.
	Steps Steps `json:"steps"`
}

ProblemSpec is the specification of a black-box optimization problem.

func NewProblemSpec

func NewProblemSpec(name string) ProblemSpec

NewProblemSpec creates a new ProblemSpec instance.

type Range

type Range struct {
	// contains filtered or unexported fields
}

Range represents the range of a parameter.

func (*Range) AsCategoricalRange

func (r *Range) AsCategoricalRange() *CategoricalRange

AsCategoricalRange tries to return the inner object of the range as a CategoricalRange object.

func (*Range) AsContinuousRange

func (r *Range) AsContinuousRange() *ContinuousRange

AsContinuousRange tries to return the inner object of the range as a ContinuousRange object.

func (*Range) AsDiscreteRange

func (r *Range) AsDiscreteRange() *DiscreteRange

AsDiscreteRange tries to return the inner object of the range as a DiscreteRange object.

func (*Range) High

func (r *Range) High() float64

High is the upper bound of the range (exclusive).

func (*Range) Low

func (r *Range) Low() float64

Low is the lower bound of the range (inclusive).

func (Range) MarshalJSON

func (r Range) MarshalJSON() ([]byte, error)

MarshalJSON encodes a range object to JSON bytes.

func (*Range) UnmarshalJSON

func (r *Range) UnmarshalJSON(data []byte) error

UnmarshalJSON decodes a Range object from JSON bytes.

type Solver

type Solver interface {
	// Ask returns a NextTrial object that contains information about the next trial to be evaluated.
	Ask(idg *TrialIDGenerator) (NextTrial, error)

	// Tell takes an evaluation result of a trial and updates the state of the solver.
	Tell(trial EvaluatedTrial) error
}

Solver interface.

type SolverFactory

type SolverFactory interface {
	// Specification returns the specification of the solver.
	Specification() (*SolverSpec, error)

	// CreateSolver creates a new solver instance with the given random seed.
	//
	// The created solver will be used to solve a black-box optimization problem defined by the given ProblemSpec.
	CreateSolver(seed int64, problem ProblemSpec) (Solver, error)
}

SolverFactory allows to create a new solver instance.

type SolverRunner

type SolverRunner struct {
	// contains filtered or unexported fields
}

SolverRunner runs a solver.

func NewSolverRunner

func NewSolverRunner(factory SolverFactory) *SolverRunner

NewSolverRunner creates a new SolverRunner instance that handles the given solver.

func (*SolverRunner) Run

func (r *SolverRunner) Run() error

Run runs a solver.

type SolverSpec

type SolverSpec struct {
	// Name is the name of the solver.
	Name string `json:"name"`

	// Attrs is the attributes of the solver.
	Attrs map[string]string `json:"attrs"`

	// Capabilities is the capabilities of the solver.
	Capabilities Capabilities `json:"capabilities"`
}

SolverSpec is the specification of a solver.

func NewSolverSpec

func NewSolverSpec(name string) SolverSpec

NewSolverSpec creates a new SolverSpec instance.

type Steps

type Steps struct {
	// contains filtered or unexported fields
}

Steps represents a sequence of evaluable steps of a problem.

At each evaluable step, the evaluator of the problem can suspend the evaluation and return intermediate evaluation values at that step.

func NewSteps

func NewSteps(steps []uint64) (*Steps, error)

NewSteps creates a new Steps instance.

func (Steps) AsSlice

func (r Steps) AsSlice() []uint64

AsSlice returns the steps as slice.

func (Steps) Last

func (r Steps) Last() uint64

Last returns the last step.

func (Steps) MarshalJSON

func (r Steps) MarshalJSON() ([]byte, error)

MarshalJSON encodes a Steps object to JSON bytes.

func (*Steps) UnmarshalJSON

func (r *Steps) UnmarshalJSON(data []byte) error

UnmarshalJSON decodes a Steps object from JSON bytes.

type TrialIDGenerator

type TrialIDGenerator struct {
	NextID uint64
}

TrialIDGenerator generates identifiers of trials.

func (*TrialIDGenerator) Generate

func (r *TrialIDGenerator) Generate() uint64

Generate creates a new trial identifier.

type Var

type Var struct {
	// Name is the name of the variable.
	Name string `json:"name"`

	// Range is the value range of the variable.
	Range Range `json:"range"`

	// Distribution is the value distribution of the variable.
	Distribution Distribution `json:"distribution"`

	// Constraint is the constraint of the variable.
	//
	// A constraint is represented by a Lua script.
	// If the script returns true, it means the constraint is satisfied.
	//
	// If the constraint isn't satisfied, the variable won't be considered during the evaluation process.
	Constraint *string `json:"constraint"`
}

Var is a definition of a variable.

func NewVar

func NewVar(name string) Var

NewVar creates a new Var instance.

func (Var) IsConstraintSatisfied

func (r Var) IsConstraintSatisfied(vars []Var, vals []*float64) (bool, error)

IsConstraintSatisfied checks whether the constraint of the variable is satisfied under the given bound (i.e., already evaluated) variables.

Directories

Path Synopsis
examples
goptuna
solver
This package provides a solver base on Goptuna.
This package provides a solver base on Goptuna.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL