Skip to content

Commit

Permalink
basic XOR proof-of-concept
Browse files Browse the repository at this point in the history
Initial commit including the XOR proof-of-concept example using only
the classic helpers.
  • Loading branch information
Brian H committed Jul 30, 2015
1 parent 67b3063 commit 1213eda
Show file tree
Hide file tree
Showing 32 changed files with 4,512 additions and 4 deletions.
3 changes: 1 addition & 2 deletions LICENSE
@@ -1,4 +1,4 @@
Copyright (c) 2015, rqme
Copyright (c) 2015, Brian Hummer (brian@redq.me)
All rights reserved.

Redistribution and use in source and binary forms, with or without
Expand All @@ -21,4 +21,3 @@ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

65 changes: 63 additions & 2 deletions README.md
@@ -1,2 +1,63 @@
# neat
Go implementation of NEAT
NEAT for Go
###########

This a Go implementation of NeuralEvolution of Augmenting Topologies (NEAT). From the [NEAT F.A.Q](http://www.cs.ucf.edu/~kstanley/neat.html#FAQ1).

NEAT stands for NeuroEvolution of Augmenting Topologies. It is a method for evolving artificial neural networks with a genetic algorithm. NEAT implements the idea that it is most effective to start evolution with small, simple networks and allow them to become increasingly complex over generations. That way, just as organisms in nature increased in complexity since the first cell, so do neural networks in NEAT. This process of continual elaboration allows finding highly sophisticated and complex neural networks.

The core of this library, often called Classic in the code, was written from the ground up using Dr. Kenneth Stanley's [PhD dissertation](http://nn.cs.utexas.edu/keyword?stanley:phd04) as a guide. NEAT has changed a bit since that paper and I have made some adjustments based on the F.A.Q. I have also add some flexibility in the desing to allow for growing the library via helpers which will provide for adding HyperNEAT, Novelty Search, etc. to the library without changing the core API.

The library and proof-of-concept experiments utilizes SVG to visualize the network of the best genome as well as the experiment's history. This visualization is based on the [NeuroEvolution Visualization Toolkit (NEVT)](http://nevt.sourceforge.net). Each image is output into an .html file for viewing from your desktop or presented through a web server.

# How to use

## Installation

```sh
go get github.com/rqme/neat
```

## Run the XOR experiment

# Create a configuration file

```json
{
"AddConnProbability": 0.025,
"AddNodeProbability": 0.015,
"CompatibilityModifier": 0.3,
"CompatibilityThreshold": 3.0,
"DisjointCoefficient": 1,
"EnableProbability": 0.2,
"ExcessCoefficient": 1,
"ExperimentName": "xor",
"FitnessType": 0,
"HiddenActivation": 2,
"InterspeciesMatingRate": 0.001,
"Iterations": 100,
"MateByAveragingProbability": 0.4,
"MaxStagnation": 15,
"MutateOnlyProbability": 0.25,
"MutateSettingProbability": 0,
"MutateTraitProbability": 0,
"MutateWeightProbability": 0.9,
"NetworkIterations": 1,
"NumInputs": 2,
"NumOutputs": 1,
"OutputActivation": 2,
"PopulationSize": 150,
"ReplaceSettingProbability": 0,
"ReplaceTraitProbability": 0,
"ReplaceWeightProbability": 0.2,
"SurvivalThreshold": 0.2,
"TargetNumberOfSpecies": 15,
"WeightCoefficient": 0.4,
"WeightRange": 2.5
}
```

```sh
go build github.com/rqme/neat/x/proof/xor
xor --config-path "." --archive-path "/tmp" --archive-name "xor" --web-path "/tmp"
```

148 changes: 148 additions & 0 deletions archiver/file.go
@@ -0,0 +1,148 @@
/*
Copyright (c) 2015, Brian Hummer (brian@redq.me)
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

package archiver

import (
. "github.com/rqme/errors"
"github.com/rqme/neat"

"bufio"
"bytes"
"fmt"
"io"
"os"
"path"
)

type File struct {
ArchivePath string
ArchiveName string
}

// Archives the configuration extracted from an item to a file
func (a File) Archive(item neat.Configurable) error {

errs := new(Errors)
for _, suffix := range []string{"config", "state"} {

// Extract the configuration for this tag
c, err := neat.Extract(item, fmt.Sprintf("neat.%s", suffix))
if err != nil {
errs.Add(fmt.Errorf("archiver.File.Archive - Error extracting for %s : %v", suffix, err))
continue
}

// Ensure the directory
if _, err := os.Stat(a.ArchivePath); os.IsNotExist(err) {
if err = os.Mkdir(a.ArchivePath, os.ModePerm); err != nil {
errs.Add(fmt.Errorf("Could not create archive path %s: %v", a.ArchivePath, err))
}
}

// Identify the path
var p string
if a.ArchiveName == "" {
p = path.Join(a.ArchivePath, fmt.Sprintf("%s.json", suffix))
} else {
p = path.Join(a.ArchivePath, fmt.Sprintf("%s-%s.json", a.ArchiveName, suffix))
}

// Create the file
f, err := os.Create(p)
if err != nil {
errs.Add(fmt.Errorf("archiver.File.Archive - Error creating file for %s : %v", suffix, err))
continue
}

// Write the config to the file
_, err = f.WriteString(c)
if err != nil {
errs.Add(fmt.Errorf("archiver.File.Archive - Error writing to file for %s : %v", suffix, err))
continue
}
f.Close()

}

return errs.Err()
}

// Restores an item from the configuration stored in a file
func (a File) Restore(item neat.Configurable) error {

errs := new(Errors)
for _, suffix := range []string{"config", "state"} {

// Identify the path
var p string
if a.ArchiveName == "" {
p = path.Join(a.ArchivePath, fmt.Sprintf("%s.json", suffix))
} else {
p = path.Join(a.ArchivePath, fmt.Sprintf("%s-%s.json", a.ArchiveName, suffix))
}

// Open the file
f, err := os.Open(p)
if err != nil {
if os.IsNotExist(err) {
continue // Nothing to restore
}
errs.Add(fmt.Errorf("archiver.File.Restore - Error opening file for %s : %v", suffix, err))
continue
}

// Read the config to the file
b := bytes.NewBufferString("")
r := bufio.NewReader(f)
for {
s, err := r.ReadBytes('\n')
if err != nil && err != io.EOF {
break
} else {
b.Write(s)
b.WriteString("\n")
if err != nil && err == io.EOF {
break
}
}
}
if err != nil && err != io.EOF {
errs.Add(fmt.Errorf("archiver.File.Restore - Error reading from file for %s : %v", suffix, err))
continue
}
f.Close()

// Configure the item
err = item.Configure(b.String())
if err != nil {
errs.Add(fmt.Errorf("archiver.File.Restore - Error Configuring for %s : %v", suffix, err))
continue
}

}
return errs.Err()
}
78 changes: 78 additions & 0 deletions attributes.go
@@ -0,0 +1,78 @@
/*
Copyright (c) 2015, Brian Hummer (brian@redq.me)
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

package neat

// Configurable helpers can have their state or settings changed by passing in a JSON record
type Configurable interface {
Configure(string) error
}

// Allows the helper to set IDs from a common sequence
type Identifies interface {
SetIDs(IDSequence)
}

// Allows the helper to mark new connections
type Marks interface {
SetMarker(Marker)
}

// Indicates that the helper can validate itself
type Validatable interface {
// Returns any validation error
Validate() error
}

// Provides setup actions in the helper's lifestyle
type Setupable interface {
// Sets up the helper
Setup() error
}

// Provides takedown actions in the helper's lifecycle
type Takedownable interface {
// Takes down the helper
Takedown() error
}

// A helper that would like to see the population
type Populatable interface {
// Provides the population to the helper
SetPopulation(Population) error
}

// A helper that would like to see the active phenomes
type Phenomable interface {
// Provides the phenomes to the helper
SetPhenomes(Phenomes) error
}

// Behaviorable describes an item tracks behaviors expressed during evaluation
type Behaviorable interface {
// Returns the expressed behaviors
Behavior() []float64
}

0 comments on commit 1213eda

Please sign in to comment.