hopfield 1.2 → 1.3

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 6f1e7bbc674b32b5f95647dcb42109ce6a37bc0b
4
- data.tar.gz: 083b4ff167702baf75a0dd050e3fd75de42f1c97
3
+ metadata.gz: eb3940e29051c8015264955b03947a57aca274bf
4
+ data.tar.gz: 52ad2e0455663abb7d345391d31383bad489daf9
5
5
  SHA512:
6
- metadata.gz: 110a161f19c05846bde6fa84d4775af490ec44c7c3352b71338ca4c436ce793ac3b27b09e410fc70b85b1337c33c15f59fd9eefd85c339b9a99c57032d1aebd3
7
- data.tar.gz: 56c9fb943f7be0e5d23983c5db41e8739b1c10118252828bfa9a21f40af5d42cf69aa59ae1437d28bd70e426b2bbb1e2aa7224dc7d51470345f46544a4d47759
6
+ metadata.gz: 0bf65127ea952843e26c0089e7f1e0eae112b336382b5e106726779f09d723312905e19d0add3971f6ce5e751c132302a5062e904dc645baa6e4ebb554a30aab
7
+ data.tar.gz: 8eaa5500db84c1891bded3e90035697782c6e610655a9ebad241d04af136f6e61ed9b14fec4fa961afcc15c1332486973241a89a02f299cd79bf569870b756bc
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Hopfield Network in Ruby
2
2
 
3
- A pure, albeit slow Ruby implementation of a Hopfield Network.
3
+ A short and simple Ruby implementation of a Hopfield Network. Includes a small C extension to speed up the CPU intensive loops.
4
4
 
5
5
  ## What is it?
6
6
  [Hopfield Networks](http://en.wikipedia.org/wiki/Hopfield_network) model the way humans recall memories, or more specific, how neurons recall the pattern. This means you first train the network with a set of known patterns and then pass an unknown or perturbed version of the pattern. The neurons will restore the missing information to create an exact match.
@@ -38,10 +38,65 @@ static VALUE hopfield_calculate_weights_hebbian(VALUE self, VALUE patterns, VALU
38
38
  return weights;
39
39
  }
40
40
 
41
+ static VALUE hopfield_transfer_activation(float activation) {
42
+ return INT2FIX((activation >= 0) ? 1 : -1);
43
+ }
44
+
45
+ static VALUE hopfield_calculate_neuron_state(VALUE self, VALUE neuron_index, VALUE neurons, VALUE weights) {
46
+ Check_Type(neuron_index, T_FIXNUM);
47
+ Check_Type(neurons, T_ARRAY);
48
+ Check_Type(weights, T_ARRAY);
49
+
50
+ float activation = 0.0;
51
+ int i = FIX2INT(neuron_index);
52
+ int neurons_count = (int) RARRAY_LEN(neurons);
53
+
54
+ for(int j = 0; j < neurons_count; j++) {
55
+ if (j == i)
56
+ continue;
57
+
58
+ int w_i = (i < j) ? i : j;
59
+ int w_j = (j > i) ? j : i;
60
+
61
+ activation += NUM2DBL(rb_ary_entry(rb_ary_entry(weights, w_i), w_j)) * NUM2DBL(rb_ary_entry(neurons, j));
62
+ }
63
+
64
+ return hopfield_transfer_activation(activation);
65
+ }
66
+
67
+ static VALUE hopfield_calculate_state_errors(VALUE self, VALUE state, VALUE patterns) {
68
+ Check_Type(state, T_ARRAY);
69
+ Check_Type(patterns, T_ARRAY);
70
+
71
+ // Compare state to patterns and calculate errors for each pattern
72
+ int patterns_count = (int) RARRAY_LEN(patterns);
73
+ int pattern_length = (int) RARRAY_LEN(state);
74
+
75
+ VALUE errors = rb_ary_new2(patterns_count);
76
+
77
+ for(int p = 0; p < patterns_count; p++) {
78
+ int sum = 0;
79
+
80
+ for(int c = 0; c < pattern_length; c++) {
81
+ int state_value = FIX2INT(rb_ary_entry(state, c));
82
+ int pattern_value = FIX2INT(rb_ary_entry(rb_ary_entry(patterns, p), c));
83
+ if (pattern_value != state_value)
84
+ sum++;
85
+ }
86
+
87
+ rb_ary_push(errors, INT2FIX(sum));
88
+ }
89
+
90
+ return errors;
91
+ }
92
+
41
93
  /* ruby calls this to load the extension */
42
94
  void Init_hopfield(void) {
43
95
 
44
96
  m_hopfield = rb_define_module("Hopfield");
45
97
 
46
98
  rb_define_module_function(m_hopfield, "calculate_weights_hebbian", hopfield_calculate_weights_hebbian, 2);
99
+ rb_define_module_function(m_hopfield, "calculate_neuron_state", hopfield_calculate_neuron_state, 3);
100
+
101
+ rb_define_module_function(m_hopfield, "calculate_state_errors", hopfield_calculate_state_errors, 2);
47
102
  }
@@ -1,12 +1,12 @@
1
1
  require 'hopfield/hopfield'
2
2
 
3
- require_relative 'hopfield/neuron'
4
3
  require_relative 'hopfield/training'
5
4
  require_relative 'hopfield/network'
6
5
 
7
6
  module Hopfield
8
- # Hopfield consists of three parts:
9
- # => Neuron (hopfield/neuron.rb)
7
+ # Hopfield consists of two parts:
10
8
  # => Training (hopfield/training.rb)
11
9
  # => Network (hopfield/network.rb)
10
+
11
+ USE_C_EXTENSION = true
12
12
  end
@@ -1,6 +1,6 @@
1
1
  module Hopfield
2
2
  class Network
3
- attr_accessor :neurons, :patterns, :weights, :state, :pattern_dimensions, :last_error, :runs
3
+ attr_accessor :neurons, :patterns, :weights, :state, :pattern_dimensions, :last_error, :runs, :random_pool, :random_pool_index
4
4
 
5
5
  def initialize(training, perturbed_pattern)
6
6
  unless training.class.to_s == 'Hopfield::Training'
@@ -20,9 +20,14 @@ module Hopfield
20
20
  self.pattern_dimensions = training.pattern_dimensions
21
21
 
22
22
  self.neurons.count.times do |i|
23
- self.neurons[i].state = perturbed_pattern[i]
23
+ self.neurons[i] = perturbed_pattern[i]
24
24
  end
25
25
 
26
+ # Create a semi random pool to improve performance
27
+ # This prevents propagation of the same neuron over and over again
28
+ self.random_pool = (0...self.neurons.count).to_a.shuffle
29
+ self.random_pool_index = rand(self.neurons.count)
30
+
26
31
  self.last_error = [1]
27
32
  self.runs = 0
28
33
  end
@@ -42,24 +47,39 @@ module Hopfield
42
47
 
43
48
  def propagate
44
49
  # Select random neuron
45
- i = rand(self.neurons.count)
50
+ if self.random_pool_index == self.random_pool.size - 1
51
+ self.random_pool_index = 0
52
+ self.random_pool.shuffle!
53
+ end
46
54
 
47
- activation = 0.0
55
+ i = self.random_pool[self.random_pool_index]
56
+ self.random_pool_index += 1
48
57
 
49
- self.neurons.each_with_index do |other, j|
50
- next if i == j
51
- activation += get_weight(i, j)*other.state
58
+ if USE_C_EXTENSION
59
+ output = Hopfield::calculate_neuron_state(i, self.neurons, self.weights)
60
+ else
61
+ # Ruby equivalent of calculate_neuron_state C function
62
+ activation = 0.0
63
+ self.neurons.each_with_index do |other, j|
64
+ next if i == j
65
+ activation += get_weight(i, j)*other
66
+ end
67
+ output = transfer(activation)
52
68
  end
53
69
 
54
- output = transfer(activation)
55
- change = output != self.neurons[i].state
56
- self.neurons[i].state = output
70
+ change = output != self.neurons[i]
71
+ self.neurons[i] = output
57
72
 
58
73
  # Compile state of outputs
59
- state = Array.new(self.neurons.count){ |i| self.neurons[i].state }
74
+ state = self.neurons
60
75
 
61
76
  # Calculate the current error
62
- self.last_error = calculate_error(state)
77
+ if USE_C_EXTENSION
78
+ self.last_error = Hopfield::calculate_state_errors(state, self.patterns)
79
+ else
80
+ # Ruby equivalent of calcuting the current error
81
+ self.last_error = calculate_error(state)
82
+ end
63
83
 
64
84
  # Convert state to binary and back to a multi dimensional array
65
85
  state = to_binary(state)
@@ -69,9 +89,9 @@ module Hopfield
69
89
  self.runs += 1
70
90
 
71
91
  return {
72
- :did_change => change,
73
- :state => self.state,
74
- :error => self.last_error
92
+ did_change: change,
93
+ state: self.state,
94
+ error: self.last_error
75
95
  }
76
96
  end
77
97
 
@@ -5,8 +5,6 @@ module Hopfield
5
5
  HEBBIAN_RULE = 1
6
6
  STORKEY_RULE = 2
7
7
 
8
- USE_C_EXTENSION = true
9
-
10
8
  class Training
11
9
  attr_accessor :patterns, :neurons, :weights, :pattern_dimensions, :rule
12
10
 
@@ -31,7 +29,7 @@ module Hopfield
31
29
  self.patterns = self.patterns.map { |pattern| pattern.map { |value| (value == 0 ? -1 : value) }}
32
30
 
33
31
  # Create neurons
34
- self.neurons = Array.new(self.patterns.first.length) { Neuron.new }
32
+ self.neurons = Array.new(self.patterns.first.length) { 0.0 }
35
33
 
36
34
  self.weights = Array.new
37
35
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hopfield
3
3
  version: !ruby/object:Gem::Version
4
- version: '1.2'
4
+ version: '1.3'
5
5
  platform: ruby
6
6
  authors:
7
7
  - Bart Olsthoorn
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-07-03 00:00:00.000000000 Z
11
+ date: 2013-07-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rspec
@@ -24,20 +24,6 @@ dependencies:
24
24
  - - '>='
25
25
  - !ruby/object:Gem::Version
26
26
  version: '0'
27
- - !ruby/object:Gem::Dependency
28
- name: chunky_png
29
- requirement: !ruby/object:Gem::Requirement
30
- requirements:
31
- - - '>='
32
- - !ruby/object:Gem::Version
33
- version: '0'
34
- type: :development
35
- prerelease: false
36
- version_requirements: !ruby/object:Gem::Requirement
37
- requirements:
38
- - - '>='
39
- - !ruby/object:Gem::Version
40
- version: '0'
41
27
  description: Hopfield networks can be used for smart pattern recollections. It's recalling
42
28
  patterns by modelling associative memory of a neural network
43
29
  email:
@@ -48,7 +34,6 @@ extensions:
48
34
  extra_rdoc_files: []
49
35
  files:
50
36
  - lib/hopfield/network.rb
51
- - lib/hopfield/neuron.rb
52
37
  - lib/hopfield/training.rb
53
38
  - lib/hopfield.rb
54
39
  - ext/hopfield/hopfield.c
@@ -1,5 +0,0 @@
1
- module Hopfield
2
- class Neuron
3
- attr_accessor :state
4
- end
5
- end