Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
110 changes: 50 additions & 60 deletions src/ai/ai.go
Original file line number Diff line number Diff line change
@@ -1,26 +1,23 @@
package ai

import (
"math/rand"
"time"
"math/rand"
"time"
)

/*
* Taken and inspired by appliedgo.net/perceptron
*/


/*
* The Input type to the perceptron breaks down any struct or type into a vector
* of features which function as the inputs to the perceptron. The features are
* either there or aren't, so they only take on a value of 1 or 0.
*/
type Input interface {
Features() []int
Features() []int
}



/*
* A simple perceptron type that acts in the form w * x + b > 0. This means that
* this Perceptron acts as a binary classifier with its given weight and bias
Expand All @@ -29,11 +26,10 @@ type Input interface {
* included together.
*/
type Perceptron struct {
weights []float32
bias float32
weights []float32
bias float32
}


/*
* Create a random perceptron that has n weights. The weight numbers are
* randomly given to start between the given numbers.
Expand All @@ -47,20 +43,19 @@ type Perceptron struct {
* A pointer to a Perceptron with n random weights and a random bias.
*/
func CreatePerceptron(n int, low, high float32) *Perceptron {
r := rand.New(rand.NewSource(time.Now().UnixNano()))
r := rand.New(rand.NewSource(time.Now().UnixNano()))

weights := make([]float32, n, n)
for i := range weights {
weights[i] = r.Float32() * (high - low) + low
}
weights := make([]float32, n, n)
for i := range weights {
weights[i] = r.Float32()*(high-low) + low
}

return &Perceptron {
weights,
r.Float32() * (high - low) + low,
}
return &Perceptron{
weights,
r.Float32()*(high-low) + low,
}
}


/*
* Process the given input and return a classification of either 1 or 0.
*
Expand All @@ -72,19 +67,18 @@ func CreatePerceptron(n int, low, high float32) *Perceptron {
* otherwise.
*/
func (p *Perceptron) Process(input Input) int {
s := p.bias
for i, input := range input.Features() {
s += float32(input) * p.weights[i]
}
s := p.bias
for i, input := range input.Features() {
s += float32(input) * p.weights[i]
}

if s > 0 {
return 1
}
if s > 0 {
return 1
}

return 0
return 0
}


/*
* Based on an array of inputs and a parallel array of expected answers, train
* the perceptron at the given rate.
Expand All @@ -95,15 +89,14 @@ func (p *Perceptron) Process(input Input) int {
* rate: The rate at which the Perceptron learns.
*/
func (p *Perceptron) Train(inputs []Input, expected []int, rate float32) {
for i, input := range inputs {
actual := p.Process(input)
del := expected[i] - actual
for i, input := range inputs {
actual := p.Process(input)
del := expected[i] - actual

p.adjust(input, del, rate)
}
p.adjust(input, del, rate)
}
}


/*
* Train the perceptron until a certain level of convergence. Basically this
* method keeps training the perceptron on the same data until the percent of
Expand All @@ -125,54 +118,51 @@ func (p *Perceptron) Train(inputs []Input, expected []int, rate float32) {
* otherwise.
*/
func (p *Perceptron) Converge(inputs []Input, expected []int,
rate, percent float32, maxIter int) bool {
thres := int(percent * float32(len(inputs)))
rate, percent float32, maxIter int) bool {
thres := int(percent * float32(len(inputs)))

iter := 0
wrong := thres + 1
for wrong > thres && iter < maxIter {
wrong = 0
iter := 0
wrong := thres + 1
for wrong > thres && iter < maxIter {
wrong = 0

for i, input := range inputs {
actual := p.Process(input)
del := expected[i] - actual
for i, input := range inputs {
actual := p.Process(input)
del := expected[i] - actual

p.adjust(input, del, rate)
p.adjust(input, del, rate)

if del != 0 {
wrong++
}
}
if del != 0 {
wrong++
}
}

iter++
}
iter++
}

return wrong <= thres
return wrong <= thres
}


/*
* Get the weights for a Perceptron.
*
* Returns:
* The weights of a Perceptron.
*/
func (p *Perceptron) Weights() []float32 {
return p.weights
return p.weights
}


/*
* Get the bias of a Perceptron.
*
* Returns:
* The bias field of a Perceptron.
*/
func (p *Perceptron) Bias() float32 {
return p.bias
return p.bias
}


/*
* Adjust a perceptron based on a given input, difference and learning rate. The
* input is what is given to the perceptron, delta is either 1, 0, or -1. It
Expand All @@ -189,9 +179,9 @@ func (p *Perceptron) Bias() float32 {
* learningRate: The rate at which to adjust the perceptron weights.
*/
func (p *Perceptron) adjust(input Input, delta int, learningRate float32) {
for i, input := range input.Features() {
p.weights[i] += float32(input) * float32(delta) * learningRate
}
for i, input := range input.Features() {
p.weights[i] += float32(input) * float32(delta) * learningRate
}

p.bias += float32(delta) * learningRate
p.bias += float32(delta) * learningRate
}
Loading