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.
@@ -0,0 +1,10 @@
1
+ == 0.0.2 2008-07-10
2
+ * Implementation of Hopfield net:
3
+ * Specs
4
+ * Code
5
+ * RDoc
6
+
7
+ == 0.0.1 2008-06-26
8
+
9
+ * 1 major enhancement:
10
+ * Initial release
@@ -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.
@@ -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,9 @@
1
+ module Brain
2
+ module VERSION #:nodoc:
3
+ MAJOR = 0
4
+ MINOR = 0
5
+ TINY = 2
6
+
7
+ STRING = [MAJOR, MINOR, TINY].join('.')
8
+ end
9
+ 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
@@ -0,0 +1 @@
1
+ --colour
@@ -0,0 +1,11 @@
1
+ begin
2
+ require 'spec'
3
+ rescue LoadError
4
+ require 'rubygems'
5
+ gem 'rspec'
6
+ require 'spec'
7
+ end
8
+
9
+ $:.unshift(File.dirname(__FILE__) + '/../lib')
10
+ require 'brain'
11
+ include Brain
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