brain 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/History.txt +10 -0
- data/README.txt +53 -0
- data/lib/brain.rb +18 -0
- data/lib/brain/hopfield.rb +75 -0
- data/lib/brain/hopfield/sample.rb +107 -0
- data/lib/brain/version.rb +9 -0
- data/spec/brain/hopfield/sample_spec.rb +87 -0
- data/spec/brain/hopfield_spec.rb +43 -0
- data/spec/spec.opts +1 -0
- data/spec/spec_helper.rb +11 -0
- metadata +77 -0
data/History.txt
ADDED
data/README.txt
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
= brain
|
2
|
+
|
3
|
+
* http://brain.rubyforge.org
|
4
|
+
* http://github.com/brainopia/brain
|
5
|
+
|
6
|
+
== DESCRIPTION:
|
7
|
+
|
8
|
+
Implements several types of Neural Networks such as multilayer perceptron (data classification), Kohonen net (data clusterization), Hopfield net (data association).
|
9
|
+
|
10
|
+
== FEATURES:
|
11
|
+
|
12
|
+
Currently supports:
|
13
|
+
* Hopfield net
|
14
|
+
|
15
|
+
== SYNOPSIS:
|
16
|
+
|
17
|
+
Basic examples:
|
18
|
+
|
19
|
+
* Hopfield net
|
20
|
+
|
21
|
+
sample = Brain::Hopfield[[-1, -1, -1, -1], [1, 1, 1, 1]].associate [1, 1, -1, 1]
|
22
|
+
sample.run until sample.associated?
|
23
|
+
sample.current # => [1, 1, 1, 1]
|
24
|
+
|
25
|
+
|
26
|
+
== INSTALL:
|
27
|
+
|
28
|
+
sudo gem install brain
|
29
|
+
|
30
|
+
== LICENSE:
|
31
|
+
|
32
|
+
(The MIT License)
|
33
|
+
|
34
|
+
Copyright (c) 2008 Ravil Bayramgalin
|
35
|
+
|
36
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
37
|
+
a copy of this software and associated documentation files (the
|
38
|
+
'Software'), to deal in the Software without restriction, including
|
39
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
40
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
41
|
+
permit persons to whom the Software is furnished to do so, subject to
|
42
|
+
the following conditions:
|
43
|
+
|
44
|
+
The above copyright notice and this permission notice shall be
|
45
|
+
included in all copies or substantial portions of the Software.
|
46
|
+
|
47
|
+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
48
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
49
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
50
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
51
|
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
52
|
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
53
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/lib/brain.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
=begin rdoc
|
2
|
+
Defines Brain module.
|
3
|
+
=end
|
4
|
+
|
5
|
+
$:.unshift(File.dirname(__FILE__)) unless
|
6
|
+
$:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
|
7
|
+
|
8
|
+
require 'mathn'
|
9
|
+
|
10
|
+
=begin rdoc
|
11
|
+
Contains neural network classes: Brain::Hopfield, Brain::Kohonen and Brain::Perceptron.
|
12
|
+
|
13
|
+
Classes are autoloaded with the first invoking.
|
14
|
+
=end
|
15
|
+
|
16
|
+
module Brain
|
17
|
+
autoload 'Hopfield', 'brain/hopfield'
|
18
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
=begin rdoc
|
2
|
+
Defines Brain::Hopfield class.
|
3
|
+
=end
|
4
|
+
|
5
|
+
=begin rdoc
|
6
|
+
Represents a Hopfield net.
|
7
|
+
|
8
|
+
net = Brain::Hopfield[[-1, -1, -1, -1], [1, 1, 1, 1]]
|
9
|
+
sample = net.associate [1, 1, -1, 1]
|
10
|
+
sample.run until sample.associated?
|
11
|
+
sample.current # => [1, 1, 1, 1]
|
12
|
+
sample.iterations # => 2
|
13
|
+
|
14
|
+
In this example, it can take up to 4 iterations to associate the sample (actual value depends on a random order of updating neurons).
|
15
|
+
=end
|
16
|
+
class Brain::Hopfield
|
17
|
+
require 'brain/hopfield/sample'
|
18
|
+
|
19
|
+
# Shortcut for creation of a new Hopfield object.
|
20
|
+
def self.[](*learning_samples)
|
21
|
+
new learning_samples
|
22
|
+
end
|
23
|
+
|
24
|
+
# Learning samples must be not empty and have same dimension.
|
25
|
+
def initialize(learning_samples)
|
26
|
+
@learning_samples = learning_samples
|
27
|
+
learning_samples_must_be_not_empty!
|
28
|
+
|
29
|
+
@dimension = @learning_samples.first.size
|
30
|
+
learning_samples_must_have_same_dimension!
|
31
|
+
|
32
|
+
calculate_weight_matrix
|
33
|
+
end
|
34
|
+
|
35
|
+
# Returns a Brain::Hopfield::Sample object which can be used for an association of given sample.
|
36
|
+
def associate(sample)
|
37
|
+
Sample.new self, sample
|
38
|
+
end
|
39
|
+
|
40
|
+
# Learning samples attribute.
|
41
|
+
def learning_samples
|
42
|
+
@learning_samples
|
43
|
+
end
|
44
|
+
|
45
|
+
# Weights attribute.
|
46
|
+
def weights
|
47
|
+
@weights
|
48
|
+
end
|
49
|
+
|
50
|
+
# Dimension attribute.
|
51
|
+
def dimension
|
52
|
+
@dimension
|
53
|
+
end
|
54
|
+
|
55
|
+
protected
|
56
|
+
|
57
|
+
def learning_samples_must_be_not_empty!
|
58
|
+
raise ArgumentError if learning_samples.empty?
|
59
|
+
end
|
60
|
+
|
61
|
+
def learning_samples_must_have_same_dimension!
|
62
|
+
raise ArgumentError unless learning_samples.all? {|sample| sample.size == dimension }
|
63
|
+
end
|
64
|
+
|
65
|
+
def calculate_weight_matrix
|
66
|
+
@weights = Matrix.zero(dimension)
|
67
|
+
|
68
|
+
learning_samples.each do |sample|
|
69
|
+
vector = Matrix.row_vector sample
|
70
|
+
@weights += vector.transpose * vector
|
71
|
+
end
|
72
|
+
|
73
|
+
@weights = Matrix[*@weights.to_a.each_with_index {|row, i| row[i] = 0 }]
|
74
|
+
end
|
75
|
+
end
|
@@ -0,0 +1,107 @@
|
|
1
|
+
=begin rdoc
|
2
|
+
Defines Brain::Hopfield::Sample class.
|
3
|
+
=end
|
4
|
+
|
5
|
+
=begin rdoc
|
6
|
+
Uses a given Hopfield object for a successive accosiation with a given sample.
|
7
|
+
|
8
|
+
When there is too much noise in the initial sample, it can associate it with an inverse version of a learning sample. Example:
|
9
|
+
|
10
|
+
net = Brain::Hopfield[[1, 1, 1, 1]]
|
11
|
+
sample = net.associate [1, -1, -1, -1]
|
12
|
+
sample.run until sample.associated?
|
13
|
+
sample.current # => [-1, -1, -1, -1]
|
14
|
+
|
15
|
+
Initial sample [1, -1, -1, -1] containes too much noise to be comparable with [1, 1, 1, 1]. So sample is associated with the inverse version of [1, 1, 1, 1] which equals [-1, -1, -1, -1].
|
16
|
+
=end
|
17
|
+
class Brain::Hopfield::Sample
|
18
|
+
|
19
|
+
# A sample must have same dimension as a Hopfield object.
|
20
|
+
def initialize(net, sample)
|
21
|
+
@net, @initial, @indexes = net, sample, []
|
22
|
+
@current, @iterations, @associated = initial, 0, false
|
23
|
+
|
24
|
+
sample_must_have_same_dimension_as_net!
|
25
|
+
@associated = true if known_sample?
|
26
|
+
end
|
27
|
+
|
28
|
+
# Returns true if the current sample is accosiated.
|
29
|
+
def associated?
|
30
|
+
@associated
|
31
|
+
end
|
32
|
+
|
33
|
+
# Used to update a state of the current sample in a random order. A number of updated positions is controlled with a given parameter.
|
34
|
+
def run(number = 1)
|
35
|
+
number.times do
|
36
|
+
break if associated?
|
37
|
+
update_next_neuron
|
38
|
+
@associated = true if minimal_energy? or known_sample?
|
39
|
+
end
|
40
|
+
current
|
41
|
+
end
|
42
|
+
|
43
|
+
# Measure of closerness to learning samples. The least energy state corresponds to an association with a learning sample.
|
44
|
+
def energy
|
45
|
+
(Matrix.row_vector(current) * net.weights).row(0).inner_product current
|
46
|
+
end
|
47
|
+
|
48
|
+
# A corresponding Hopfield object.
|
49
|
+
def net
|
50
|
+
@net
|
51
|
+
end
|
52
|
+
|
53
|
+
# Initial state of sample.
|
54
|
+
def initial
|
55
|
+
@initial
|
56
|
+
end
|
57
|
+
|
58
|
+
# Current state of sample.
|
59
|
+
def current
|
60
|
+
@current
|
61
|
+
end
|
62
|
+
|
63
|
+
# Number of itererations.
|
64
|
+
def iterations
|
65
|
+
@iterations
|
66
|
+
end
|
67
|
+
|
68
|
+
protected
|
69
|
+
|
70
|
+
def sample_must_have_same_dimension_as_net!
|
71
|
+
raise ArgumentError unless current.size == net.dimension
|
72
|
+
end
|
73
|
+
|
74
|
+
def known_sample?
|
75
|
+
net.learning_samples.any? {|sample| sample == current }
|
76
|
+
end
|
77
|
+
|
78
|
+
def minimal_energy?
|
79
|
+
@energy_changed = true unless @previous_energy == energy
|
80
|
+
if @indexes.empty?
|
81
|
+
@energy_changed ? (@energy_changed = false) : true
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def activation_argument(neuron_index)
|
86
|
+
net.weights.row(neuron_index).inner_product current
|
87
|
+
end
|
88
|
+
|
89
|
+
def activation_function(neuron_index)
|
90
|
+
activation = activation_argument neuron_index
|
91
|
+
return 1 if activation > 0
|
92
|
+
return -1 if activation < 0
|
93
|
+
current[neuron_index]
|
94
|
+
end
|
95
|
+
|
96
|
+
def next_neuron
|
97
|
+
@indexes = Array.new(net.dimension) {|i| i } if @indexes.empty?
|
98
|
+
@indexes.delete_at rand(@indexes.size)
|
99
|
+
end
|
100
|
+
|
101
|
+
def update_next_neuron
|
102
|
+
@previous_energy = energy
|
103
|
+
neuron_index = next_neuron
|
104
|
+
current[neuron_index] = activation_function neuron_index
|
105
|
+
@iterations += 1
|
106
|
+
end
|
107
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../../spec_helper'
|
2
|
+
|
3
|
+
describe Brain::Hopfield::Sample do
|
4
|
+
it "should be initialized with a Hopfield net and a sample" do
|
5
|
+
lambda { Hopfield::Sample.new Hopfield[ [1, 1, 1] ], [-1, 1, -1] }.
|
6
|
+
should_not raise_error(ArgumentError)
|
7
|
+
end
|
8
|
+
|
9
|
+
it "should raise error if the sample has a different arity then the net" do
|
10
|
+
lambda { Hopfield::Sample.new Hopfield[ [1, 1, 1] ], [-1, 1, -1, 1] }.
|
11
|
+
should raise_error(ArgumentError)
|
12
|
+
end
|
13
|
+
|
14
|
+
it "should check if the sample belongs to learning samples" do
|
15
|
+
sample = Hopfield::Sample.new(Hopfield[ [1, 1, 1] ], [1, 1, 1])
|
16
|
+
sample.associated?.should == true
|
17
|
+
end
|
18
|
+
|
19
|
+
describe '(after initialization)' do
|
20
|
+
before(:each) do
|
21
|
+
@learned_sample = [1, -1, 1, -1, 1, -1, 1, -1, 1, -1]
|
22
|
+
@tested_sample = [-1, -1, -1, -1, -1, -1, 1, 1, 1, -1]
|
23
|
+
|
24
|
+
@net = Hopfield[ @learned_sample ]
|
25
|
+
@sample = Hopfield::Sample.new @net, @tested_sample
|
26
|
+
end
|
27
|
+
|
28
|
+
it "should start an iterations count with 0" do
|
29
|
+
@sample.iterations.should == 0
|
30
|
+
end
|
31
|
+
|
32
|
+
it "should return a status of training" do
|
33
|
+
@sample.associated?.should == false
|
34
|
+
end
|
35
|
+
|
36
|
+
it "should return a current associated sample" do
|
37
|
+
@sample.current.should == @tested_sample
|
38
|
+
end
|
39
|
+
|
40
|
+
it "should return an initial sample" do
|
41
|
+
@sample.initial.should == @tested_sample
|
42
|
+
end
|
43
|
+
|
44
|
+
it "should be ran a given number of times" do
|
45
|
+
@sample.run(50).should == @learned_sample
|
46
|
+
end
|
47
|
+
|
48
|
+
it "should increment iterations after an every run" do
|
49
|
+
@sample.stub!(:associated?).and_return(false)
|
50
|
+
3.times { @sample.run(3) }
|
51
|
+
@sample.iterations.should == 9
|
52
|
+
end
|
53
|
+
|
54
|
+
it "should stop incrementing iterations after it's associated" do
|
55
|
+
@sample.stub!(:associated?).and_return(false)
|
56
|
+
@sample.run(4)
|
57
|
+
@sample.stub!(:associated?).and_return(true)
|
58
|
+
@sample.run(4)
|
59
|
+
@sample.iterations.should == 4
|
60
|
+
end
|
61
|
+
|
62
|
+
it "should be ran by default one time" do
|
63
|
+
@sample.run
|
64
|
+
@sample.iterations.should == 1
|
65
|
+
end
|
66
|
+
|
67
|
+
it "should return an using net" do
|
68
|
+
@sample.net.should == @net
|
69
|
+
end
|
70
|
+
|
71
|
+
it "shouldn't increase energy" do
|
72
|
+
previous_energy = @sample.energy
|
73
|
+
until @sample.associated?
|
74
|
+
@sample.run
|
75
|
+
previous_energy.should_not > @sample.energy
|
76
|
+
previous_energy = @sample.energy
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
it "should return an inverse version of the learning sample if there is too much noise in the initial sample" do
|
81
|
+
net = Brain::Hopfield[[1, 1, 1, 1]]
|
82
|
+
sample = net.associate [1, -1, -1, -1]
|
83
|
+
sample.run until sample.associated?
|
84
|
+
sample.current.should == [-1, -1, -1, -1]
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../spec_helper'
|
2
|
+
|
3
|
+
describe Brain::Hopfield do
|
4
|
+
it "should be created with learning samples" do
|
5
|
+
lambda { Hopfield.new }.should raise_error(ArgumentError)
|
6
|
+
lambda { Hopfield.new [] }.should raise_error(ArgumentError)
|
7
|
+
lambda { Hopfield.new [[1, 1], [1, 1]] }.should_not raise_error
|
8
|
+
end
|
9
|
+
|
10
|
+
it "learning samples should have a same arity" do
|
11
|
+
lambda { Hopfield.new [[-1, -1], [1]] }.should raise_error(ArgumentError)
|
12
|
+
lambda { Hopfield.new [[-1, -1], [1, 1]] }.should_not raise_error
|
13
|
+
end
|
14
|
+
|
15
|
+
it "should have a shortcut [] for creation" do
|
16
|
+
Hopfield[[1, 1], [1, 1]].should be_instance_of(Hopfield)
|
17
|
+
end
|
18
|
+
|
19
|
+
describe '(after initialization)' do
|
20
|
+
before(:each) do
|
21
|
+
@net = Hopfield[ [-1, 1, -1], [1, -1, 1] ]
|
22
|
+
end
|
23
|
+
|
24
|
+
it "should return a weight matrix" do
|
25
|
+
@net.weights.should == Matrix[ [ 0, -2, 2],
|
26
|
+
[-2, 0, -2],
|
27
|
+
[ 2, -2, 0] ]
|
28
|
+
end
|
29
|
+
|
30
|
+
it "should return an array of learning samples" do
|
31
|
+
@net.learning_samples.should == [ [-1, 1, -1], [1, -1, 1] ]
|
32
|
+
end
|
33
|
+
|
34
|
+
it "should return an arity" do
|
35
|
+
@net.dimension.should == 3
|
36
|
+
end
|
37
|
+
|
38
|
+
it "should create an object for an association with a given sample" do
|
39
|
+
associated_sample = @net.associate([1, 1, 1])
|
40
|
+
associated_sample.should be_instance_of(Hopfield::Sample)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
data/spec/spec.opts
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--colour
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,77 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: brain
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.2
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Ravil Bayramgalin
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2008-07-12 00:00:00 +04:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: hoe
|
17
|
+
type: :development
|
18
|
+
version_requirement:
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 1.7.0
|
24
|
+
version:
|
25
|
+
description: Implementation of fundamental types of neural networks which includes multilayer perceptron, Kohonen net and Hopfield net.
|
26
|
+
email:
|
27
|
+
- ravwar@gmail.com
|
28
|
+
executables: []
|
29
|
+
|
30
|
+
extensions: []
|
31
|
+
|
32
|
+
extra_rdoc_files:
|
33
|
+
- History.txt
|
34
|
+
- README.txt
|
35
|
+
files:
|
36
|
+
- History.txt
|
37
|
+
- README.txt
|
38
|
+
- lib/brain.rb
|
39
|
+
- lib/brain/hopfield.rb
|
40
|
+
- lib/brain/hopfield/sample.rb
|
41
|
+
- lib/brain/version.rb
|
42
|
+
- spec/brain/hopfield/sample_spec.rb
|
43
|
+
- spec/brain/hopfield_spec.rb
|
44
|
+
- spec/spec.opts
|
45
|
+
- spec/spec_helper.rb
|
46
|
+
has_rdoc: true
|
47
|
+
homepage: http://brain.rubyforge.org
|
48
|
+
post_install_message: |-
|
49
|
+
|
50
|
+
For more information on brain, see http://brain.rubyforge.org
|
51
|
+
rdoc_options:
|
52
|
+
- --main
|
53
|
+
- README.txt
|
54
|
+
require_paths:
|
55
|
+
- lib
|
56
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
57
|
+
requirements:
|
58
|
+
- - ">="
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: "0"
|
61
|
+
version:
|
62
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
63
|
+
requirements:
|
64
|
+
- - ">="
|
65
|
+
- !ruby/object:Gem::Version
|
66
|
+
version: "0"
|
67
|
+
version:
|
68
|
+
requirements: []
|
69
|
+
|
70
|
+
rubyforge_project: brain
|
71
|
+
rubygems_version: 1.2.0
|
72
|
+
signing_key:
|
73
|
+
specification_version: 2
|
74
|
+
summary: Implementation of fundamental types of neural networks which includes multilayer perceptron, Kohonen net and Hopfield net.
|
75
|
+
test_files:
|
76
|
+
- spec/brain/hopfield/sample_spec.rb
|
77
|
+
- spec/brain/hopfield_spec.rb
|