ai4r 1.6.1 → 1.7

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.
@@ -24,5 +24,6 @@ require "ai4r/classifiers/zero_r"
24
24
  require "ai4r/classifiers/hyperpipes"
25
25
  # Neural networks
26
26
  require "ai4r/neural_network/backpropagation"
27
+ require "ai4r/neural_network/hopfield"
27
28
  # Genetic Algorithms
28
29
  require "ai4r/genetic_algorithm/genetic_algorithm"
@@ -0,0 +1,149 @@
1
+ # Author:: Sergio Fierens
2
+ # License:: MPL 1.1
3
+ # Project:: ai4r
4
+ # Url:: http://ai4r.rubyforge.org/
5
+ #
6
+ # You can redistribute it and/or modify it under the terms of
7
+ # the Mozilla Public License version 1.1 as published by the
8
+ # Mozilla Foundation at http://www.mozilla.org/MPL/MPL-1.1.txt
9
+
10
+ require File.dirname(__FILE__) + '/../data/parameterizable'
11
+
12
+ module Ai4r
13
+
14
+ module NeuralNetwork
15
+
16
+ # = Hopfield Net =
17
+ #
18
+ # A Hopfield Network is a recurrent Artificial Neural Network.
19
+ # Hopfield nets are able to memorize a set of patterns, and then evaluate
20
+ # an input, returning the most similar stored pattern (although
21
+ # convergence to one of the stored patterns is not guaranteed).
22
+ # Hopfield nets are great to deal with input noise. If a system accepts a
23
+ # discrete set of inputs, but inputs are subject to noise, you can use a
24
+ # Hopfield net to eliminate noise and identified the given input.
25
+ #
26
+ # = How to Use =
27
+ #
28
+ # data_set = Ai4r::Data::DataSet.new :data_items => array_of_patterns
29
+ # net = Ai4r::NeuralNetworks::Hopfield.new.train data_set
30
+ # net.eval input
31
+ # => one of the stored patterns in array_of_patterns
32
+ class Hopfield
33
+
34
+ include Ai4r::Data::Parameterizable
35
+
36
+ attr_reader :weights, :nodes
37
+
38
+ parameters_info :eval_iterations => "The network will run for a maximum "+
39
+ "of 'eval_iterations' iterations while evaluating an input. 500 by " +
40
+ "default.",
41
+ :active_node_value => "Default: 1",
42
+ :inactive_node_value => "Default: -1",
43
+ :threshold => "Default: 0"
44
+
45
+ def initialize
46
+ @eval_iterations = 500
47
+ @active_node_value = 1
48
+ @inactive_node_value = -1
49
+ @threshold = 0
50
+ end
51
+
52
+ # Prepares the network to memorize the given data set.
53
+ # Future calls to eval (should) return one of the memorized data items.
54
+ # A Hopfield network converges to a local minimum, but converge to one
55
+ # of the "memorized" patterns is not guaranteed.
56
+ def train(data_set)
57
+ @data_set = data_set
58
+ initialize_nodes(@data_set)
59
+ initialize_weights(@data_set)
60
+ return self
61
+ end
62
+
63
+ # You can use run instead of eval to propagate values step by step.
64
+ # With this you can verify the progress of the network output with
65
+ # each step.
66
+ #
67
+ # E.g.:
68
+ # pattern = input
69
+ # 100.times do
70
+ # pattern = net.run(pattern)
71
+ # puts pattern.inspect
72
+ # end
73
+ def run(input)
74
+ set_input(input)
75
+ propagate
76
+ return @nodes
77
+ end
78
+
79
+ # Propagates the input until the network returns one of the memorized
80
+ # patterns, or a maximum of "eval_iterations" times.
81
+ def eval(input)
82
+ set_input(input)
83
+ @eval_iterations.times do
84
+ propagate
85
+ break if @data_set.data_items.include?(@nodes)
86
+ end
87
+ return @nodes
88
+ end
89
+
90
+ protected
91
+ # Set all nodes state to the given input.
92
+ # inputs parameter must have the same dimension as nodes
93
+ def set_input(inputs)
94
+ raise ArgumentError unless inputs.length == @nodes.length
95
+ inputs.each_with_index { |input, i| @nodes[i] = input}
96
+ end
97
+
98
+ # Select a single node randomly and propagate its state to all other nodes
99
+ def propagate
100
+ sum = 0
101
+ i = (rand * @nodes.length).floor
102
+ @nodes.each_with_index {|node, j| sum += read_weight(i,j)*node }
103
+ @nodes[i] = (sum > @threshold) ? @active_node_value : @inactive_node_value
104
+ end
105
+
106
+ # Initialize all nodes with "inactive" state.
107
+ def initialize_nodes(data_set)
108
+ @nodes = Array.new(data_set.data_items.first.length,
109
+ @inactive_node_value)
110
+ end
111
+
112
+ # Create a partial weigth matrix:
113
+ # [
114
+ # [w(1,0)],
115
+ # [w(2,0)], [w(2,1)],
116
+ # [w(3,0)], [w(3,1)], [w(3,2)],
117
+ # ...
118
+ # [w(n-1,0)], [w(n-1,1)], [w(n-1,2)], ... , [w(n-1,n-2)]
119
+ # ]
120
+ # where n is the number of nodes.
121
+ #
122
+ # We are saving memory here, as:
123
+ #
124
+ # * w[i][i] = 0 (no node connects with itself)
125
+ # * w[i][j] = w[j][i] (weigths are symmetric)
126
+ #
127
+ # Use read_weight(i,j) to find out weight between node i and j
128
+ def initialize_weights(data_set)
129
+ @weights = Array.new(@nodes.length-1) {|l| Array.new(l+1)}
130
+ @nodes.each_index do |i|
131
+ i.times do |j|
132
+ @weights[i-1][j] = data_set.data_items.inject(0) { |sum, item| sum+= item[i]*item[j] }
133
+ end
134
+ end
135
+ end
136
+
137
+ # read_weight(i,j) reads the weigth matrix and returns weight between
138
+ # node i and j
139
+ def read_weight(index_a, index_b)
140
+ return 0 if index_a == index_b
141
+ index_a, index_b = index_b, index_a if index_b > index_a
142
+ return @weights[index_a-1][index_b]
143
+ end
144
+
145
+ end
146
+
147
+ end
148
+
149
+ end
@@ -0,0 +1,72 @@
1
+ # This is a unit test file for the hopfield neural network AI4r implementation
2
+ #
3
+ # Author:: Sergio Fierens
4
+ # License:: MPL 1.1
5
+ # Project:: ai4r
6
+ # Url:: http://ai4r.rubyforge.org/
7
+ #
8
+ # You can redistribute it and/or modify it under the terms of
9
+ # the Mozilla Public License version 1.1 as published by the
10
+ # Mozilla Foundation at http://www.mozilla.org/MPL/MPL-1.1.txt
11
+
12
+ require File.dirname(__FILE__) + '/../../lib/ai4r'
13
+ require 'test/unit'
14
+
15
+ Ai4r::NeuralNetwork::Hopfield.send(:public, *Ai4r::NeuralNetwork::Hopfield.protected_instance_methods)
16
+
17
+ module Ai4r
18
+
19
+ module NeuralNetwork
20
+
21
+
22
+ class HopfieldTest < Test::Unit::TestCase
23
+
24
+ def setup
25
+ @data_set = Ai4r::Data::DataSet.new :data_items => [
26
+ [1,1,-1,-1,1,1,-1,-1,1,1,-1,-1,1,1,-1,-1],
27
+ [-1,-1,1,1,-1,-1,1,1,-1,-1,1,1,-1,-1,1,1],
28
+ [-1,-1,-1,-1,-1,-1,-1,-1,1,1,1,1,1,1,1,1],
29
+ [1,1,1,1,1,1,1,1,-1,-1,-1,-1,-1,-1,-1,-1],
30
+ ]
31
+ end
32
+
33
+ def test_initialize_nodes
34
+ net = Hopfield.new
35
+ data_set = Ai4r::Data::DataSet.new :data_items => [[1,1,0,0,1,1,0,0]]
36
+ assert_equal [-1,-1,-1,-1,-1,-1,-1,-1], net.initialize_nodes(data_set)
37
+ end
38
+
39
+ def test_initialize_weights
40
+ net = Hopfield.new
41
+ net.initialize_nodes @data_set
42
+ net.initialize_weights(@data_set)
43
+ assert_equal 15, net.weights.length
44
+ net.weights.each_with_index {|w_row, i| assert_equal i+1, w_row.length}
45
+ end
46
+
47
+ def test_run
48
+ net = Hopfield.new
49
+ net.train @data_set
50
+ pattern = [1,1,-1,1,1,1,-1,-1,1,1,-1,-1,1,1,1,-1]
51
+ 100.times do
52
+ pattern = net.run(pattern)
53
+ end
54
+ assert_equal [1,1,-1,-1,1,1,-1,-1,1,1,-1,-1,1,1,-1,-1], pattern
55
+ end
56
+
57
+ def test_eval
58
+ net = Hopfield.new
59
+ net.train @data_set
60
+ p = [1,1,-1,1,1,1,-1,-1,1,1,-1,-1,1,1,1,-1]
61
+ assert_equal @data_set.data_items[0], net.eval(p)
62
+ p = [-1,-1,1,1,1,-1,1,1,-1,-1,1,-1,-1,-1,1,1]
63
+ assert_equal @data_set.data_items[1], net.eval(p)
64
+ p = [-1,-1,-1,-1,-1,-1,-1,-1,1,1,1,1,1,1,-1,-1]
65
+ assert_equal @data_set.data_items[2], net.eval(p)
66
+ p = [-1,-1,1,1,1,1,1,1,-1,-1,-1,-1,1,-1,-1,-1]
67
+ assert_equal @data_set.data_items[3], net.eval(p)
68
+ end
69
+
70
+ end
71
+ end
72
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ai4r
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.6.1
4
+ version: "1.7"
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sergio Fierens
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-04-09 00:00:00 +01:00
12
+ date: 2009-04-29 00:00:00 +01:00
13
13
  default_executable:
14
14
  dependencies: []
15
15
 
@@ -55,6 +55,7 @@ files:
55
55
  - lib/ai4r/experiment/classifier_evaluator.rb
56
56
  - lib/ai4r/neural_network
57
57
  - lib/ai4r/neural_network/backpropagation.rb
58
+ - lib/ai4r/neural_network/hopfield.rb
58
59
  - lib/ai4r/classifiers
59
60
  - lib/ai4r/classifiers/hyperpipes.rb
60
61
  - lib/ai4r/classifiers/multilayer_perceptron.rb
@@ -109,6 +110,7 @@ test_files:
109
110
  - test/clusterers/k_means_test.rb
110
111
  - test/clusterers/bisecting_k_means_test.rb
111
112
  - test/experiment/classifier_evaluator_test.rb
113
+ - test/neural_network/hopfield_test.rb
112
114
  - test/neural_network/backpropagation_test.rb
113
115
  - test/classifiers/zero_r_test.rb
114
116
  - test/classifiers/multilayer_perceptron_test.rb