86 lines
2.3 KiB
Go
86 lines
2.3 KiB
Go
|
// CookieJar - A contestant's algorithm toolbox
|
||
|
// Copyright (c) 2014 Peter Szilagyi. All rights reserved.
|
||
|
//
|
||
|
// CookieJar is dual licensed: use of this source code is governed by a BSD
|
||
|
// license that can be found in the LICENSE file. Alternatively, the CookieJar
|
||
|
// toolbox may be used in accordance with the terms and conditions contained
|
||
|
// in a signed written agreement between you and the author(s).
|
||
|
|
||
|
package utility
|
||
|
|
||
|
import (
|
||
|
"math"
|
||
|
|
||
|
"gopkg.in/karalabe/cookiejar.v2/collections/bag"
|
||
|
)
|
||
|
|
||
|
// Data-source based utility, normalizing and transforming an input stream by an
|
||
|
// assigned curve.
|
||
|
type inputUtility struct {
|
||
|
curve Curve // Data transformation curve
|
||
|
min, max float64 // Normalization limits
|
||
|
nonZero bool // Flag whether absolute zero output is allowed
|
||
|
|
||
|
children *bag.Bag // Derived utilities based on the current one
|
||
|
|
||
|
reset bool // Flag whether the output is not yet calculated
|
||
|
input float64 // Input value which to o map to the curve
|
||
|
output float64 // Cached output utility value
|
||
|
}
|
||
|
|
||
|
// Creates a new data source utility and associated a transformation curve.
|
||
|
func newInputUtility(curve Curve, nonZero bool) *inputUtility {
|
||
|
return &inputUtility{
|
||
|
curve: curve,
|
||
|
nonZero: nonZero,
|
||
|
children: bag.New(),
|
||
|
reset: true,
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Sets the data limits used during normalization.
|
||
|
func (u *inputUtility) Limit(min, max float64) {
|
||
|
u.min, u.max = min, max
|
||
|
u.Reset()
|
||
|
}
|
||
|
|
||
|
// Updates the utility to a new data value.
|
||
|
func (u *inputUtility) Update(input float64) {
|
||
|
u.input = input
|
||
|
u.Reset()
|
||
|
}
|
||
|
|
||
|
// Resets the utility, requiring a reevaluation.
|
||
|
func (u *inputUtility) Reset() {
|
||
|
if !u.reset {
|
||
|
u.reset = true
|
||
|
u.children.Do(func(util interface{}) {
|
||
|
util.(*comboUtility).Reset()
|
||
|
})
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Adds a new dependency to the utility hierarchy.
|
||
|
func (u *inputUtility) Dependency(util utility) {
|
||
|
u.children.Insert(util)
|
||
|
}
|
||
|
|
||
|
// Returns the utility value for the set data point.
|
||
|
func (u *inputUtility) Evaluate() float64 {
|
||
|
// Recalculate the output value if not cached
|
||
|
if u.reset {
|
||
|
// Normalize the input and calculate the output
|
||
|
if diff := u.max - u.min; diff != 0 {
|
||
|
u.input = (u.input - u.min) / diff
|
||
|
}
|
||
|
u.output = math.Min(1, math.Max(0, u.curve(u.input)))
|
||
|
|
||
|
// If requested, prevent a result of absolute zero
|
||
|
if u.nonZero && u.output == 0 {
|
||
|
u.output = float64(1e-18)
|
||
|
}
|
||
|
u.reset = false
|
||
|
}
|
||
|
return u.output
|
||
|
}
|