Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

V2 library release #4

Open
wants to merge 58 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 14 commits
Commits
Show all changes
58 commits
Select commit Hold shift + click to select a range
dc2606a
Updated .gitignore to exclude GoLand project file
yaricom Apr 21, 2022
a2c7f61
Updated eshyperneat library version to v2. Fixed comments and typos.
yaricom Apr 21, 2022
8256a31
Updated funding
yaricom Apr 21, 2022
ab67b0b
Updated title of the README.md
yaricom Apr 21, 2022
6cd0db7
Updated release drafter configuration
yaricom Apr 22, 2022
cf93ed1
Updated README title
yaricom Apr 22, 2022
bdf2c8a
Updated README. Added linter exclusion rule README.md
yaricom Apr 22, 2022
f3fecb1
Updated CPPN implementation to use v2 of the goNEAT library.
yaricom Apr 22, 2022
fb8a0ec
Updated ES-HyperNEAT and HyperNEAT implementation to use v2 of the go…
yaricom Apr 22, 2022
c70a015
Updated experiment executor and implementation of the retina experime…
yaricom Apr 22, 2022
1b47db6
Updated go module definition
yaricom Apr 22, 2022
916bb0f
Fixed error strings format to avoid linter errors.
yaricom Apr 22, 2022
25c64b9
Fixed code duplication in evolvable_substrate.go. Added JSCPD thresho…
yaricom Apr 22, 2022
9e3729d
Updated JSCPD configuration
yaricom Apr 22, 2022
0bb00ae
Code deduplication
yaricom Apr 22, 2022
25821a2
Code deduplication
yaricom Apr 22, 2022
8a9b698
Updated super-linter configuration
yaricom Apr 22, 2022
0550168
Updated super-linter configuration
yaricom Apr 22, 2022
5d8d5fa
Updated linter configuration to use golangci-lint directly
yaricom Apr 22, 2022
339784e
Updated README to include UA badge
yaricom May 6, 2022
6a514bb
Updated to use v3 of the goNEAT library
yaricom Jun 5, 2022
4ea9c37
Updated experiment executor to use utilities to read NEAT options and…
yaricom Jun 5, 2022
6e8208f
Updated experiment executor and retina experiment sample to get ES-Hy…
yaricom Jun 5, 2022
51cca8e
Implemented support for soft stabilization of number of species in po…
yaricom Jun 5, 2022
c61db95
Updated retina configuration
yaricom Jun 5, 2022
5078887
Fixed bug in predictions evaluation. Added solver flushing.
yaricom Jun 7, 2022
ddc3f8d
Merge branch 'master' into v2
yaricom Jun 21, 2022
b12b8a0
Fixed bug with ineffectual assigment to err
yaricom Jun 21, 2022
adf78e4
Renamed parameters and variables for better clarity.
yaricom Jun 23, 2022
cbebfbe
Implemented check for valid network solver created
yaricom Jun 23, 2022
146f9da
Implemented support for LEO in the EvolvableSubstrate.CreateNetworkSo…
yaricom Jun 23, 2022
fc02c46
Fixed test genome configuration
yaricom Jun 23, 2022
0821682
Fixed TestEvolvableSubstrate_CreateNetworkSolver_LEO
yaricom Jun 23, 2022
d5e0a44
Updated goNeat dependency version
yaricom Jun 23, 2022
004ba27
Updated retina experiment runner to support LEO, CPPN bias, provide m…
yaricom Jun 23, 2022
cf7a9b5
Fixed CPPN genome of retina experiment to implement X-locality and Ge…
yaricom Jun 23, 2022
7d9d4ec
Fixed to use the latest version `goNEAT` library.
yaricom Apr 12, 2024
0afe4bb
Added new configuration options
yaricom Apr 15, 2024
a8b5f7a
Removed obsolete
yaricom Apr 15, 2024
fc50d1d
Implemented support for LEO threshold
yaricom Apr 15, 2024
5fa5fdd
Changed variance calculation to be more optimized
yaricom Apr 15, 2024
2b97627
Added support of Z coordinate by QuadTree
yaricom Apr 15, 2024
54e4e02
Fixed evolvable substrate generation. Fixed quad tree stringer. Fixed…
yaricom Apr 18, 2024
a9dad24
Fixed substrate to use 3d coordinates. Fixed substrate tests
yaricom Apr 18, 2024
d36021a
Fixed retina experiment and tests.
yaricom Apr 18, 2024
59b5d54
Implemented support for different activation types for hidden and out…
yaricom Apr 18, 2024
218fcb4
Implemented support for different activation types for hidden and out…
yaricom Apr 18, 2024
a51a7ef
Optimized loss calculation by flattening loop
yaricom Apr 19, 2024
ecd8f6a
Updated dependencies. Fixed deprecations
yaricom May 16, 2024
25b46a2
Changed retina solver activation routine
yaricom May 16, 2024
54552e3
Modified evolvable_substrate.go to support CPPN as Network
yaricom May 16, 2024
c384a24
Updated README to include correct links in references. Updated depend…
yaricom Dec 9, 2024
cac4617
Updated GitHub workflows
yaricom Dec 9, 2024
fa6f17f
Retina experiment configuration updates.
yaricom Dec 9, 2024
9302962
Fixed failing unit tests.
yaricom Dec 9, 2024
011dd11
Updated to use `ReadAll` from `io` package. Commented unused method
yaricom Dec 9, 2024
8d21ae9
Changed GO version for linter
yaricom Dec 9, 2024
632ee17
Updated workflow
yaricom Dec 9, 2024
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
1 change: 1 addition & 0 deletions .github/FUNDING.yml
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
# These are supported funding model platforms

patreon: io42
custom: ["https://www.buymeacoffee.com/io42"]
2 changes: 1 addition & 1 deletion .github/codecov.yml
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
ignore:
- "examples/**/*" # ignoring experiments folder
- "examples/**/*" # ignoring examples folder
10 changes: 10 additions & 0 deletions .github/linters/.jscpd.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"threshold": 20,
"reporters": [
"consoleFull"
],
"ignore": [
"**/__snapshots__/**"
],
"absolute": true
}
2 changes: 1 addition & 1 deletion .github/release-drafter.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name-template: 'v$RESOLVED_VERSION 🌈'
name-template: 'v$RESOLVED_VERSION 🇺🇦'
tag-template: 'v$RESOLVED_VERSION'
categories:
- title: '🚀 Features'
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/super-linter.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,5 @@ jobs:
env:
VALIDATE_ALL_CODEBASE: false
DEFAULT_BRANCH: master
FILTER_REGEX_EXCLUDE: .*README.md
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ vendor

# The IDEA project forlder
.idea
/goESHyperNEAT.iml

# The MacOS specific
.DS_Store
Expand All @@ -22,3 +23,4 @@ vendor

# Output of the go coverage tool, specifically when used with LiteIDE
*.out

2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ GORUN = $(GOCMD) run
# The common parameters
BINARY_NAME = eshyperneat
OUT_DIR = out
LOG_LEVEL = -1
LOG_LEVEL = info

#
# The retina experiment parameters
Expand Down
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
# goESHyperNEAT 🇺🇦

[![Build Status](https://travis-ci.org/yaricom/goESHyperNEAT.svg?branch=master)](https://travis-ci.org/yaricom/goESHyperNEAT) [![GoDoc](https://godoc.org/github.com/yaricom/goESHyperNEAT?status.svg)](https://godoc.org/github.com/yaricom/goESHyperNEAT)

## Overview
Expand All @@ -21,7 +23,7 @@ geometrical topology during training, producing regions with varying neural dens
for situating cognitive structures in the biological brains.


## References:
## References

1. The original C++ NEAT implementation created by Kenneth O. Stanley, see: [NEAT][1]
2. Other NEAT implementations can be found at [NEAT Software Catalog][2]
Expand Down
38 changes: 19 additions & 19 deletions cppn/cppn.go
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
// The package CPPN provides implementation of Compositional Pattern Producing Network
// Package cppn provides implementation of Compositional Pattern Producing Network
// which is a part of Hypercube-based NEAT algorithm implementation
package cppn

import (
"errors"
"github.com/yaricom/goNEAT/neat/genetics"
"github.com/yaricom/goNEAT/neat/network"
"github.com/yaricom/goNEAT/v2/neat/genetics"
"github.com/yaricom/goNEAT/v2/neat/network"
"math"
"os"
)

// Reads CPPN from specified genome and creates network solver
func ReadCPPFromGenomeFile(genomePath string) (network.NetworkSolver, error) {
// ReadCPPFromGenomeFile Reads CPPN from specified genome and creates network solver
func ReadCPPFromGenomeFile(genomePath string) (network.Solver, error) {
if genomeFile, err := os.Open(genomePath); err != nil {
return nil, err
} else if r, err := genetics.NewGenomeReader(genomeFile, genetics.YAMLGenomeEncoding); err != nil {
Expand All @@ -33,9 +33,9 @@ func createThresholdNormalizedLink(cppnOutput float64, srcIndex, dstIndex int, l
weight *= -1 // restore sign
}
link := network.FastNetworkLink{
Weight: weight,
SourceIndx: srcIndex,
TargetIndx: dstIndex,
Weight: weight,
SourceIndex: srcIndex,
TargetIndex: dstIndex,
}
return &link
}
Expand All @@ -45,15 +45,15 @@ func createLink(cppnOutput float64, srcIndex, dstIndex int, weightRange float64)
weight := cppnOutput
weight *= weightRange // scale to fit given weight range
link := network.FastNetworkLink{
Weight: weight,
SourceIndx: srcIndex,
TargetIndx: dstIndex,
Weight: weight,
SourceIndex: srcIndex,
TargetIndex: dstIndex,
}
return &link
}

// Calculates outputs of provided CPPN network solver with given hypercube coordinates.
func queryCPPN(coordinates []float64, cppn network.NetworkSolver) ([]float64, error) {
func queryCPPN(coordinates []float64, cppn network.Solver) ([]float64, error) {
// flush networks activation from previous run
if res, err := cppn.Flush(); err != nil {
return nil, err
Expand Down Expand Up @@ -82,18 +82,18 @@ func nodeVariance(node *QuadNode) float64 {
return 0.0
}

cppnVals := nodeCPPNValues(node)
cppnValues := nodeCPPNValues(node)
// calculate median and variance
m, v := 0.0, 0.0
for _, f := range cppnVals {
for _, f := range cppnValues {
m += f
}
m /= float64(len(cppnVals))
m /= float64(len(cppnValues))

for _, f := range cppnVals {
for _, f := range cppnValues {
v += math.Pow(f-m, 2)
}
v /= float64(len(cppnVals))
v /= float64(len(cppnValues))

return v
}
Expand All @@ -105,8 +105,8 @@ func nodeCPPNValues(n *QuadNode) []float64 {
accumulator := make([]float64, 0)
for _, p := range n.Nodes {
// go into child nodes
pVals := nodeCPPNValues(p)
accumulator = append(accumulator, pVals...)
cppnValues := nodeCPPNValues(p)
accumulator = append(accumulator, cppnValues...)
}
return accumulator
} else {
Expand Down
106 changes: 52 additions & 54 deletions cppn/evolvable_substrate.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@ package cppn

import (
"container/list"
"github.com/yaricom/goESHyperNEAT/eshyperneat"
"github.com/yaricom/goESHyperNEAT/v2/eshyperneat"
"math"

"fmt"
"github.com/yaricom/goNEAT/neat/network"
"github.com/yaricom/goNEAT/neat/utils"
neatmath "github.com/yaricom/goNEAT/v2/neat/math"
"github.com/yaricom/goNEAT/v2/neat/network"
)

// The evolvable substrate holds configuration of ANN produced by CPPN within hypecube where each 4-dimensional point
// EvolvableSubstrate The evolvable substrate holds configuration of ANN produced by CPPN within hypecube where each 4-dimensional point
// mark connection weight between two ANN units. The topology of ANN is not rigid as in plain substrate and can be evolved
// by introducing novel nodes to the ANN. This provides extra benefits that the topology of ANN should not be handcrafted
// by human, but produced during substrate generation from controlling CPPN and nodes locations may be arbitrary that suits
Expand All @@ -19,27 +19,28 @@ type EvolvableSubstrate struct {
// The layout of neuron nodes in this substrate
Layout EvolvableSubstrateLayout
// The activation function's type for neurons encoded
NodesActivation utils.NodeActivationType
NodesActivation neatmath.NodeActivationType

// The CPPN network solver to describe geometry of substrate
cppn network.NetworkSolver
cppn network.Solver
// The reusable coordinates buffer
coords []float64
}

// Creates new instance of evolvable substrate
func NewEvolvableSubstrate(layout EvolvableSubstrateLayout, nodesActivation utils.NodeActivationType) *EvolvableSubstrate {
// NewEvolvableSubstrate Creates new instance of evolvable substrate
func NewEvolvableSubstrate(layout EvolvableSubstrateLayout, nodesActivation neatmath.NodeActivationType) *EvolvableSubstrate {
return &EvolvableSubstrate{
coords: make([]float64, 4),
Layout: layout,
NodesActivation: nodesActivation,
}
}

// Creates network solver based on current substrate layout and provided Compositional Pattern Producing Network which
// CreateNetworkSolver Creates network solver based on current substrate layout and provided Compositional Pattern Producing Network which
// used to define connections between network nodes. Optional graph_builder can be provided to collect graph nodes and edges
// of created network solver. With graph builder it is possible to save/load network configuration as well as visualize it.
func (es *EvolvableSubstrate) CreateNetworkSolver(cppn network.NetworkSolver, graphBuilder SubstrateGraphBuilder, context *eshyperneat.ESHyperNEATContext) (network.NetworkSolver, error) {
func (es *EvolvableSubstrate) CreateNetworkSolver(cppn network.Solver, graphBuilder SubstrateGraphBuilder,
context *eshyperneat.Options) (network.Solver, error) {
es.cppn = cppn

// the network layers will be collected in order: bias, input, output, hidden
Expand Down Expand Up @@ -73,7 +74,7 @@ func (es *EvolvableSubstrate) CreateNetworkSolver(cppn network.NetworkSolver, gr
return nil, err
}
// add input node to graph
if _, err := addNodeToBuilder(graphBuilder, in, network.InputNeuron, utils.NullActivation, input); err != nil {
if _, err = addNodeToBuilder(graphBuilder, in, network.InputNeuron, neatmath.NullActivation, input); err != nil {
return nil, err
}

Expand All @@ -86,28 +87,15 @@ func (es *EvolvableSubstrate) CreateNetworkSolver(cppn network.NetworkSolver, gr
}
// iterate over quad points and add nodes/connections
for _, qp := range qPoints {
nodePoint := NewPointF(qp.X2, qp.Y2)
targetIndex := es.Layout.IndexOfHidden(nodePoint)
if targetIndex == -1 {
// add hidden node to the substrate layout
if targetIndex, err = es.Layout.AddHiddenNode(nodePoint); err != nil {
return nil, err
}

targetIndex += firstHidden // adjust index to the global indexes space
// add a node to the graph
if _, err := addNodeToBuilder(graphBuilder, targetIndex, network.HiddenNeuron, es.NodesActivation, nodePoint); err != nil {
return nil, err
}

} else {
// adjust index to the global indexes space
targetIndex += firstHidden
// add hidden node to the substrate layout if needed
targetIndex, err := es.addHiddenNode(qp, firstHidden, graphBuilder)
if err != nil {
return nil, err
}
// add connection
if link, ok := addConnection(qp.Value, in, targetIndex); ok {
// add an edge to the graph
if _, err := addEdgeToBuilder(graphBuilder, in, targetIndex, link.Weight); err != nil {
if _, err = addEdgeToBuilder(graphBuilder, in, targetIndex, link.Weight); err != nil {
return nil, err
}
}
Expand All @@ -133,27 +121,15 @@ func (es *EvolvableSubstrate) CreateNetworkSolver(cppn network.NetworkSolver, gr
}
// iterate over quad points and add nodes/connections
for _, qp := range qPoints {
nodePoint := NewPointF(qp.X2, qp.Y2)
targetIndex := es.Layout.IndexOfHidden(nodePoint)
if targetIndex == -1 {
// add hidden node to the substrate layout
if targetIndex, err = es.Layout.AddHiddenNode(nodePoint); err != nil {
return nil, err
}

targetIndex += firstHidden // adjust index to the global indexes space
// add a node to the graph
if _, err := addNodeToBuilder(graphBuilder, targetIndex, network.HiddenNeuron, es.NodesActivation, nodePoint); err != nil {
return nil, err
}
} else {
// adjust index to the global indexes space
targetIndex += firstHidden
// add hidden node to the substrate layout if needed
targetIndex, err := es.addHiddenNode(qp, firstHidden, graphBuilder)
if err != nil {
return nil, err
}
// add connection
if link, ok := addConnection(qp.Value, hi, targetIndex); ok {
// add an edge to the graph
if _, err := addEdgeToBuilder(graphBuilder, hi, targetIndex, link.Weight); err != nil {
if _, err = addEdgeToBuilder(graphBuilder, hi, targetIndex, link.Weight); err != nil {
return nil, err
}
}
Expand All @@ -173,7 +149,7 @@ func (es *EvolvableSubstrate) CreateNetworkSolver(cppn network.NetworkSolver, gr
return nil, err
}
// add output node to graph
if _, err := addNodeToBuilder(graphBuilder, oi, network.OutputNeuron, es.NodesActivation, output); err != nil {
if _, err = addNodeToBuilder(graphBuilder, oi, network.OutputNeuron, es.NodesActivation, output); err != nil {
return nil, err
}

Expand All @@ -196,7 +172,7 @@ func (es *EvolvableSubstrate) CreateNetworkSolver(cppn network.NetworkSolver, gr
// add connection
if link, ok := addConnection(qp.Value, sourceIndex, oi); ok {
// add an edge to the graph
if _, err := addEdgeToBuilder(graphBuilder, sourceIndex, oi, link.Weight); err != nil {
if _, err = addEdgeToBuilder(graphBuilder, sourceIndex, oi, link.Weight); err != nil {
return nil, err
}
}
Expand All @@ -207,11 +183,11 @@ func (es *EvolvableSubstrate) CreateNetworkSolver(cppn network.NetworkSolver, gr
totalNeuronCount := es.Layout.InputCount() + es.Layout.OutputCount() + es.Layout.HiddenCount()

// build activations
activations := make([]utils.NodeActivationType, totalNeuronCount)
activations := make([]neatmath.NodeActivationType, totalNeuronCount)
for i := 0; i < totalNeuronCount; i++ {
if i < firstOutput {
// input nodes - NULL activation
activations[i] = utils.NullActivation
activations[i] = neatmath.NullActivation
} else {
// hidden/output nodes - defined activation
activations[i] = es.NodesActivation
Expand All @@ -226,10 +202,32 @@ func (es *EvolvableSubstrate) CreateNetworkSolver(cppn network.NetworkSolver, gr
return solver, nil
}

func (es *EvolvableSubstrate) addHiddenNode(qp *QuadPoint, firstHidden int, graphBuilder SubstrateGraphBuilder) (targetIndex int, err error) {
nodePoint := NewPointF(qp.X2, qp.Y2)
targetIndex = es.Layout.IndexOfHidden(nodePoint)
if targetIndex == -1 {
// add hidden node to the substrate layout
if targetIndex, err = es.Layout.AddHiddenNode(nodePoint); err != nil {
return -1, err
}

targetIndex += firstHidden // adjust index to the global indexes space
// add a node to the graph
if _, err = addNodeToBuilder(graphBuilder, targetIndex, network.HiddenNeuron, es.NodesActivation, nodePoint); err != nil {
return -1, err
}
} else {
// adjust index to the global indexes space
targetIndex += firstHidden
}
return targetIndex, nil
}

// Divides and initialize the quadtree from provided coordinates of source (outgoing = true) or target node (outgoing = false) at (a, b).
// Returns quadtree, in which each quadnode at (x,y) stores CPPN activation level for its position. The initialized
// quadtree is used in the PruningAndExtraction phase to generate the actual ANN connections.
func (es *EvolvableSubstrate) quadTreeDivideAndInit(a, b float64, outgoing bool, context *eshyperneat.ESHyperNEATContext) (root *QuadNode, err error) {
func (es *EvolvableSubstrate) quadTreeDivideAndInit(a, b float64, outgoing bool,
context *eshyperneat.Options) (root *QuadNode, err error) {
root = NewQuadNode(0.0, 0.0, 1.0, 1)

queue := list.New()
Expand All @@ -239,7 +237,7 @@ func (es *EvolvableSubstrate) quadTreeDivideAndInit(a, b float64, outgoing bool,
// de-queue
p := queue.Remove(queue.Front()).(*QuadNode)

// Divide into sub-regions and assign children to parent
// Divide into subregions and assign children to parent
p.Nodes = []*QuadNode{
NewQuadNode(p.X-p.Width/2.0, p.Y-p.Width/2.0, p.Width/2.0, p.Level+1),
NewQuadNode(p.X-p.Width/2.0, p.Y+p.Width/2.0, p.Width/2.0, p.Level+1),
Expand Down Expand Up @@ -274,10 +272,10 @@ func (es *EvolvableSubstrate) quadTreeDivideAndInit(a, b float64, outgoing bool,

// Decides what regions should have higher neuron density based on variation and express new neurons and connections into
// these regions.
// Receives coordinates of source (outgoing = true) or target node (outgoing = false) at (a, b) and initialized quadtree node.
// Receive coordinates of source (outgoing = true) or target node (outgoing = false) at (a, b) and initialized quadtree node.
// Adds the connections that are in bands of the two-dimensional cross-section of the hypercube containing the source
// or target node to the connections list and return modified list.
func (es *EvolvableSubstrate) pruneAndExpress(a, b float64, connections []*QuadPoint, node *QuadNode, outgoing bool, context *eshyperneat.ESHyperNEATContext) ([]*QuadPoint, error) {
func (es *EvolvableSubstrate) pruneAndExpress(a, b float64, connections []*QuadPoint, node *QuadNode, outgoing bool, context *eshyperneat.Options) ([]*QuadPoint, error) {
// fast check
if len(node.Nodes) == 0 {
return connections, nil
Expand Down
Loading