fuzzy_associative_memory 1.3.1 → 1.3.2
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +3 -0
- data/CHANGELOG.md +3 -0
- data/Guardfile +24 -0
- data/Rakefile +23 -5
- data/fuzzy_associative_memory.gemspec +17 -0
- data/lib/fuzzy_associative_memory/linguistic_variable.rb +1 -1
- data/lib/fuzzy_associative_memory/rule.rb +5 -12
- data/lib/fuzzy_associative_memory/triangle.rb +1 -3
- data/spec/spec_helper.rb +19 -0
- data/spec/trapezoid_spec.rb +189 -0
- data/spec/triangle_spec.rb +97 -0
- metadata +52 -17
- data/test/all_suite.rb +0 -11
- data/test/trapezoid_test.rb +0 -96
- data/test/triangle_test.rb +0 -64
data/.gitignore
ADDED
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,8 @@
|
|
1
1
|
# Changelog for fuzzy-associative-memory
|
2
2
|
|
3
|
+
## 1.3.2, 12 September 2013
|
4
|
+
* Correct a regression in Rule
|
5
|
+
|
3
6
|
## 1.3.1, 2 September 2013
|
4
7
|
* Massive performance and efficiency effort. This version of the Gem clocks in at 3.5x the speed of my 1.1 series in synthetic benchmarks. If you use the FAM in a tight loop, this will help a lot.
|
5
8
|
|
data/Guardfile
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
# A sample Guardfile
|
2
|
+
# More info at https://github.com/guard/guard#readme
|
3
|
+
|
4
|
+
guard :rspec, :all_on_start => true, :all_after_pass => true do
|
5
|
+
watch(%r{^spec/.+_spec\.rb$})
|
6
|
+
watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
|
7
|
+
watch('spec/spec_helper.rb') { "spec" }
|
8
|
+
|
9
|
+
# Rails example
|
10
|
+
watch(%r{^app/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
|
11
|
+
watch(%r{^app/(.*)(\.erb|\.haml)$}) { |m| "spec/#{m[1]}#{m[2]}_spec.rb" }
|
12
|
+
watch(%r{^app/controllers/(.+)_(controller)\.rb$}) { |m| ["spec/routing/#{m[1]}_routing_spec.rb", "spec/#{m[2]}s/#{m[1]}_#{m[2]}_spec.rb", "spec/acceptance/#{m[1]}_spec.rb"] }
|
13
|
+
watch(%r{^spec/support/(.+)\.rb$}) { "spec" }
|
14
|
+
watch('config/routes.rb') { "spec/routing" }
|
15
|
+
watch('app/controllers/application_controller.rb') { "spec/controllers" }
|
16
|
+
|
17
|
+
# Capybara features specs
|
18
|
+
watch(%r{^app/views/(.+)/.*\.(erb|haml)$}) { |m| "spec/features/#{m[1]}_spec.rb" }
|
19
|
+
|
20
|
+
# Turnip features and steps
|
21
|
+
watch(%r{^spec/acceptance/(.+)\.feature$})
|
22
|
+
watch(%r{^spec/acceptance/steps/(.+)_steps\.rb$}) { |m| Dir[File.join("**/#{m[1]}.feature")][0] || 'spec/acceptance' }
|
23
|
+
end
|
24
|
+
|
data/Rakefile
CHANGED
@@ -1,8 +1,26 @@
|
|
1
|
-
require 'rake/testtask'
|
1
|
+
# require 'rake/testtask'
|
2
2
|
|
3
|
-
task :default => [:test]
|
3
|
+
# task :default => [:test]
|
4
4
|
|
5
|
-
desc "Run the test suite once"
|
6
|
-
task :test do
|
7
|
-
|
5
|
+
# desc "Run the test suite once"
|
6
|
+
# task :test do
|
7
|
+
# ruby "test/all_suite.rb"
|
8
|
+
# end
|
9
|
+
|
10
|
+
require 'rspec/core/rake_task'
|
11
|
+
|
12
|
+
desc 'Default: run specs.'
|
13
|
+
task :default=>:spec
|
14
|
+
|
15
|
+
desc "Run specs"
|
16
|
+
RSpec::Core::RakeTask.new do |t|
|
17
|
+
t.pattern = "./spec/**/*_spec.rb" # don't need this, it's default.
|
18
|
+
# Put spec opts in a file named .rspec in root
|
19
|
+
end
|
20
|
+
|
21
|
+
desc "Generate code coverage"
|
22
|
+
RSpec::Core::RakeTask.new(:coverage) do |t|
|
23
|
+
t.pattern = "./spec/**/*_spec.rb" # don't need this, it's default.
|
24
|
+
t.rcov = true
|
25
|
+
t.rcov_opts = ['--exclude', 'spec']
|
8
26
|
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
Gem::Specification.new do |s|
|
2
|
+
s.name = 'fuzzy_associative_memory'
|
3
|
+
s.version = '1.3.2'
|
4
|
+
s.date = '2013-09-12'
|
5
|
+
s.summary = "A fuzzy logic 'Fuzzy Associative Memory' (FAM) for fuzzy control systems, decision-making, artificial intelligence / AI, game agents & bots, etc."
|
6
|
+
s.description = <<-EOF
|
7
|
+
A Fuzzy Associative Memory (FAM for short) is a Fuzzy Logic tool for decision making. Fuzzy logic FAMs have a wide range of practical applications: Control systems, such as governing a fan to keep a room at the "just right" temperature; Game AI, such as imbuing bots with human-like decision-making behavior; Prediction systems, linking causes with effects. A FAM uses Fuzzy Sets to establish a set of rules that are linguistic in nature. The linguistic rules, and the fuzzy sets they contain, are defined by a human "expert" (presumably, you). The rules therefore codify intelligence and map this knowledge from the human domain to the digital.
|
8
|
+
EOF
|
9
|
+
s.authors = ["Chris Powell"]
|
10
|
+
s.email = 'cpowell@prylis.com'
|
11
|
+
s.files = `git ls-files`.split($/)
|
12
|
+
s.homepage = 'http://github.com/cpowell/fuzzy-associative-memory'
|
13
|
+
s.license = 'LGPL'
|
14
|
+
s.rdoc_options = ["--main", "README.md"]
|
15
|
+
s.add_development_dependency 'rspec'
|
16
|
+
s.add_development_dependency "rake"
|
17
|
+
end
|
@@ -80,7 +80,7 @@ class FuzzyAssociativeMemory::LinguisticVariable
|
|
80
80
|
)
|
81
81
|
|
82
82
|
if opts[:logarithmic_x]
|
83
|
-
commands += "set xr [
|
83
|
+
commands += "set xr [#{[min, 1].max}:#{max}]\nset logscale x\n"
|
84
84
|
else
|
85
85
|
commands += "set xr [#{min}:#{max}]\n"
|
86
86
|
end
|
@@ -37,6 +37,7 @@ class FuzzyAssociativeMemory::Rule
|
|
37
37
|
@antecedents = antecedent_array
|
38
38
|
@consequent = consequent
|
39
39
|
@boolean = boolean
|
40
|
+
@mus = []
|
40
41
|
end
|
41
42
|
|
42
43
|
# Triggers the rule. The antecedent(s) is/are fired with the supplied inputs
|
@@ -52,23 +53,15 @@ class FuzzyAssociativeMemory::Rule
|
|
52
53
|
raise ArgumentError, "value array must be an collection of inputs but is a #{value_array.class}" unless value_array.is_a? Array
|
53
54
|
raise ArgumentError, "value array passed to Rule::fire() cannot be empty" if value_array.empty?
|
54
55
|
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
for i in 0..ant_len-1
|
59
|
-
v = @antecedents[i].mu(value_array[i])
|
60
|
-
@max = v if @max.nil? || v > @max
|
61
|
-
@min = v if @min.nil? || v < @min
|
56
|
+
for i in 0..@antecedents.size-1
|
57
|
+
@mus[i] = @antecedents[i].mu(value_array[i])
|
62
58
|
end
|
63
59
|
|
64
60
|
if @boolean==:and
|
65
|
-
return @min # AND / Intersection == minimum
|
61
|
+
return @mus.min # AND / Intersection == minimum
|
66
62
|
else
|
67
|
-
return @max # OR / Union == maximum
|
63
|
+
return @mus.max # OR / Union == maximum
|
68
64
|
end
|
69
|
-
|
70
|
-
# puts "Fired rule '#{@natural_language}': µ choices are [#{@mus.join(',')}], final µ is #{mu}" if $verbosity
|
71
|
-
# [@consequent, mu]
|
72
65
|
end
|
73
66
|
|
74
67
|
end
|
@@ -44,12 +44,10 @@ class FuzzyAssociativeMemory::Triangle < FuzzyAssociativeMemory::FuzzySet
|
|
44
44
|
end
|
45
45
|
|
46
46
|
def mamdani(clip_height)
|
47
|
-
left = @left
|
48
47
|
top_left = @left + (clip_height * (@center - @left))
|
49
48
|
top_right = @right - (clip_height * (@right - @center))
|
50
|
-
right = @right
|
51
49
|
|
52
|
-
FuzzyAssociativeMemory::Trapezoid.new(left, top_left, top_right, right, clip_height)
|
50
|
+
FuzzyAssociativeMemory::Trapezoid.new(@left, top_left, top_right, @right, clip_height)
|
53
51
|
end
|
54
52
|
|
55
53
|
def to_s
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
# This file was generated by the `rspec --init` command. Conventionally, all
|
2
|
+
# specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
|
3
|
+
# Require this file using `require "spec_helper"` to ensure that it is only
|
4
|
+
# loaded once.
|
5
|
+
#
|
6
|
+
# See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
|
7
|
+
require 'fuzzy_associative_memory'
|
8
|
+
|
9
|
+
RSpec.configure do |config|
|
10
|
+
config.treat_symbols_as_metadata_keys_with_true_values = true
|
11
|
+
config.run_all_when_everything_filtered = true
|
12
|
+
config.filter_run :focus
|
13
|
+
|
14
|
+
# Run specs in random order to surface order dependencies. If you find an
|
15
|
+
# order dependency and want to debug it, you can fix the order by providing
|
16
|
+
# the seed, which is printed after each run.
|
17
|
+
# --seed 1234
|
18
|
+
config.order = 'random'
|
19
|
+
end
|
@@ -0,0 +1,189 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "Trapezoid" do
|
4
|
+
before :all do
|
5
|
+
# per-context setup
|
6
|
+
end
|
7
|
+
|
8
|
+
before do
|
9
|
+
# per-example setup
|
10
|
+
@t = FuzzyAssociativeMemory::Trapezoid.new(7, 10, 13, 16)
|
11
|
+
end
|
12
|
+
|
13
|
+
after do
|
14
|
+
# per-example teardown
|
15
|
+
end
|
16
|
+
|
17
|
+
after :all do
|
18
|
+
# per-context teardown
|
19
|
+
end
|
20
|
+
|
21
|
+
it "has centroid where expected" do
|
22
|
+
expect(@t.centroid_x).to eq(11.5)
|
23
|
+
end
|
24
|
+
|
25
|
+
it "has DOM 0 outside left bound" do
|
26
|
+
expect(@t.mu(2)).to eq(0)
|
27
|
+
end
|
28
|
+
|
29
|
+
it "has DOM 0 outside right bound" do
|
30
|
+
expect(@t.mu(17)).to eq(0)
|
31
|
+
end
|
32
|
+
|
33
|
+
it "has DOM 1 at peak" do
|
34
|
+
expect(@t.mu(12)).to eq(1.0)
|
35
|
+
end
|
36
|
+
|
37
|
+
it "has DOM 1 at top left" do
|
38
|
+
expect(@t.mu(10)).to eq(1.0)
|
39
|
+
end
|
40
|
+
|
41
|
+
it "has DOM 1 at top right" do
|
42
|
+
expect(@t.mu(13)).to eq(1.0)
|
43
|
+
end
|
44
|
+
|
45
|
+
it "has DOM 0.5 at half right offset" do
|
46
|
+
expect(@t.mu(14.5)).to eq(0.5)
|
47
|
+
end
|
48
|
+
|
49
|
+
it "has DOM 0.5 at half left offset" do
|
50
|
+
expect(@t.mu(8.5)).to eq(0.5)
|
51
|
+
end
|
52
|
+
|
53
|
+
it "has DOM 0 at right" do
|
54
|
+
expect(@t.mu(16)).to eq(0)
|
55
|
+
end
|
56
|
+
|
57
|
+
it "has DOM 0 at left" do
|
58
|
+
expect(@t.mu(7)).to eq(0)
|
59
|
+
end
|
60
|
+
|
61
|
+
it "has correct DOM at 3/5 offset" do
|
62
|
+
@t = FuzzyAssociativeMemory::Triangle.new(0, 5, 10)
|
63
|
+
expect(@t.mu(3.0)).to eq(0.6)
|
64
|
+
end
|
65
|
+
|
66
|
+
it "has correct DOM at 7/10 offset" do
|
67
|
+
@t = FuzzyAssociativeMemory::Triangle.new(0, 5, 10)
|
68
|
+
expect(@t.mu(7.0)).to eq(0.6)
|
69
|
+
end
|
70
|
+
|
71
|
+
context "Centroid calculation" do
|
72
|
+
it "has a proper centroid 1" do
|
73
|
+
@t=FuzzyAssociativeMemory::Trapezoid.new(0, 20, 50, 50)
|
74
|
+
expect(@t.centroid_x).to be_within(0.0005).of(29.583)
|
75
|
+
end
|
76
|
+
|
77
|
+
it "has a proper centroid 2" do
|
78
|
+
@t=FuzzyAssociativeMemory::Trapezoid.new(0, 10, 20, 30)
|
79
|
+
expect(@t.centroid_x).to eq(15)
|
80
|
+
end
|
81
|
+
|
82
|
+
it "has a proper centroid 3" do
|
83
|
+
@t=FuzzyAssociativeMemory::Trapezoid.new(50, 80, 100, 100)
|
84
|
+
expect(@t.centroid_x).to be_within(0.0005).of(81.4283)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
it "has the correct DOM when fully positive" do
|
89
|
+
@t = FuzzyAssociativeMemory::Trapezoid.new(20, 30, 40, 50)
|
90
|
+
expect(@t.mu(41)).to eq(0.9)
|
91
|
+
end
|
92
|
+
|
93
|
+
context "Larsen implication" do
|
94
|
+
before do
|
95
|
+
@scaled = @t.larsen(0.15)
|
96
|
+
end
|
97
|
+
|
98
|
+
it "stays a trapezoid" do
|
99
|
+
expect(@scaled).to be_a(FuzzyAssociativeMemory::Trapezoid)
|
100
|
+
end
|
101
|
+
|
102
|
+
it "takes the height of the larsen value" do
|
103
|
+
expect(@scaled.height).to eq(0.15)
|
104
|
+
end
|
105
|
+
|
106
|
+
it "keeps same corner points" do
|
107
|
+
expect(@scaled.left).to eq(7)
|
108
|
+
expect(@scaled.top_left).to eq(10)
|
109
|
+
expect(@scaled.top_right).to eq(13)
|
110
|
+
expect(@scaled.right).to eq(16)
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
context "Mamdani implication" do
|
115
|
+
before do
|
116
|
+
@scaled = @t.mamdani(0.83)
|
117
|
+
end
|
118
|
+
|
119
|
+
it "stays a trapezoid" do
|
120
|
+
expect(@scaled).to be_a(FuzzyAssociativeMemory::Trapezoid)
|
121
|
+
end
|
122
|
+
|
123
|
+
it "keeps same left and right corner points" do
|
124
|
+
expect(@scaled.left).to eq(7)
|
125
|
+
expect(@scaled.right).to eq(16)
|
126
|
+
end
|
127
|
+
|
128
|
+
it "takes the height of the mamdani value" do
|
129
|
+
expect(@scaled.height).to eq(0.83)
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
context "Mamdani with one point at zero" do
|
134
|
+
before do
|
135
|
+
@t = FuzzyAssociativeMemory::Trapezoid.new(0, 30, 100, 110)
|
136
|
+
@scaled = @t.mamdani(0.83)
|
137
|
+
end
|
138
|
+
|
139
|
+
it "stays a trapezoid" do
|
140
|
+
expect(@scaled).to be_a(FuzzyAssociativeMemory::Trapezoid)
|
141
|
+
end
|
142
|
+
|
143
|
+
it "keeps same left and right corner points" do
|
144
|
+
expect(@scaled.left).to eq(0)
|
145
|
+
expect(@scaled.right).to eq(110)
|
146
|
+
end
|
147
|
+
|
148
|
+
it "gets the correct new top left" do
|
149
|
+
expect(@scaled.top_left).to eq(24.9)
|
150
|
+
end
|
151
|
+
|
152
|
+
it "gets the correct new top right" do
|
153
|
+
expect(@scaled.top_right).to eq(101.7)
|
154
|
+
end
|
155
|
+
|
156
|
+
it "takes the height of the mamdani value" do
|
157
|
+
expect(@scaled.height).to eq(0.83)
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
context "Mamdani with all points positive" do
|
162
|
+
before do
|
163
|
+
@t = FuzzyAssociativeMemory::Trapezoid.new(50, 80, 150, 160)
|
164
|
+
@scaled = @t.mamdani(0.83)
|
165
|
+
end
|
166
|
+
|
167
|
+
it "stays a trapezoid" do
|
168
|
+
expect(@scaled).to be_a(FuzzyAssociativeMemory::Trapezoid)
|
169
|
+
end
|
170
|
+
|
171
|
+
it "keeps same left and right corner points" do
|
172
|
+
expect(@scaled.left).to eq(50)
|
173
|
+
expect(@scaled.right).to eq(160)
|
174
|
+
end
|
175
|
+
|
176
|
+
it "gets the correct new top left" do
|
177
|
+
expect(@scaled.top_left).to eq(74.9)
|
178
|
+
end
|
179
|
+
|
180
|
+
it "gets the correct new top right" do
|
181
|
+
expect(@scaled.top_right).to eq(151.7)
|
182
|
+
end
|
183
|
+
|
184
|
+
it "takes the height of the mamdani value" do
|
185
|
+
expect(@scaled.height).to eq(0.83)
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "Triangle" do
|
4
|
+
before :all do
|
5
|
+
# per-context setup
|
6
|
+
end
|
7
|
+
|
8
|
+
before do
|
9
|
+
# per-example setup
|
10
|
+
@t = FuzzyAssociativeMemory::Triangle.new(7, 10, 13)
|
11
|
+
end
|
12
|
+
|
13
|
+
after do
|
14
|
+
# per-example teardown
|
15
|
+
end
|
16
|
+
|
17
|
+
after :all do
|
18
|
+
# per-context teardown
|
19
|
+
end
|
20
|
+
|
21
|
+
it "has centroid of peak for isoceles triangle" do
|
22
|
+
expect(@t.centroid_x).to eq(10)
|
23
|
+
end
|
24
|
+
|
25
|
+
it "has DOM 0 outside left bound" do
|
26
|
+
expect(@t.mu(2)).to eq(0)
|
27
|
+
end
|
28
|
+
|
29
|
+
it "has DOM 0 outside right bound" do
|
30
|
+
expect(@t.mu(15)).to eq(0)
|
31
|
+
end
|
32
|
+
|
33
|
+
it "has DOM 1 at peak" do
|
34
|
+
expect(@t.mu(10)).to eq(1.0)
|
35
|
+
end
|
36
|
+
|
37
|
+
it "has DOM 0.5 at half right offset" do
|
38
|
+
expect(@t.mu(11.5)).to eq(0.5)
|
39
|
+
end
|
40
|
+
|
41
|
+
it "has DOM 0.5 at half left offset" do
|
42
|
+
expect(@t.mu(8.5)).to eq(0.5)
|
43
|
+
end
|
44
|
+
|
45
|
+
it "has correct DOM at 3/5 offset" do
|
46
|
+
@t = FuzzyAssociativeMemory::Triangle.new(0, 5, 10)
|
47
|
+
expect(@t.mu(3.0)).to eq(0.6)
|
48
|
+
end
|
49
|
+
|
50
|
+
it "has correct DOM at 7/10 offset" do
|
51
|
+
@t = FuzzyAssociativeMemory::Triangle.new(0, 5, 10)
|
52
|
+
expect(@t.mu(7.0)).to eq(0.6)
|
53
|
+
end
|
54
|
+
|
55
|
+
context "Larsen implication" do
|
56
|
+
before do
|
57
|
+
@scaled = @t.larsen(0.15)
|
58
|
+
end
|
59
|
+
|
60
|
+
it "takes the height of the larsen value" do
|
61
|
+
expect(@scaled.height).to eq(0.15)
|
62
|
+
end
|
63
|
+
|
64
|
+
it "keeps right, left and center" do
|
65
|
+
expect(@scaled.left).to eq(7)
|
66
|
+
expect(@scaled.right).to eq(13)
|
67
|
+
expect(@scaled.center).to eq(10)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
context "Mamdani implication" do
|
72
|
+
before do
|
73
|
+
@scaled = @t.mamdani(0.83)
|
74
|
+
end
|
75
|
+
|
76
|
+
it "becomes a trapezoid" do
|
77
|
+
expect(@scaled).to be_a(FuzzyAssociativeMemory::Trapezoid)
|
78
|
+
end
|
79
|
+
|
80
|
+
it "keeps left and right" do
|
81
|
+
expect(@scaled.left).to eq(7)
|
82
|
+
expect(@scaled.right).to eq(13)
|
83
|
+
end
|
84
|
+
|
85
|
+
it "gets a proper top left" do
|
86
|
+
expect(@scaled.top_left).to eq(9.49)
|
87
|
+
end
|
88
|
+
|
89
|
+
it "gets a proper top right" do
|
90
|
+
expect(@scaled.top_right).to eq(10.51)
|
91
|
+
end
|
92
|
+
|
93
|
+
it "takes the height of the mamdani value" do
|
94
|
+
expect(@scaled.height).to eq(0.83)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fuzzy_associative_memory
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.3.
|
4
|
+
version: 1.3.2
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,8 +9,40 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-09-
|
13
|
-
dependencies:
|
12
|
+
date: 2013-09-12 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: rspec
|
16
|
+
version_requirements: !ruby/object:Gem::Requirement
|
17
|
+
requirements:
|
18
|
+
- - '>='
|
19
|
+
- !ruby/object:Gem::Version
|
20
|
+
version: '0'
|
21
|
+
none: false
|
22
|
+
requirement: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - '>='
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
none: false
|
28
|
+
prerelease: false
|
29
|
+
type: :development
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: rake
|
32
|
+
version_requirements: !ruby/object:Gem::Requirement
|
33
|
+
requirements:
|
34
|
+
- - '>='
|
35
|
+
- !ruby/object:Gem::Version
|
36
|
+
version: '0'
|
37
|
+
none: false
|
38
|
+
requirement: !ruby/object:Gem::Requirement
|
39
|
+
requirements:
|
40
|
+
- - '>='
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
version: '0'
|
43
|
+
none: false
|
44
|
+
prerelease: false
|
45
|
+
type: :development
|
14
46
|
description: |2
|
15
47
|
A Fuzzy Associative Memory (FAM for short) is a Fuzzy Logic tool for decision making. Fuzzy logic FAMs have a wide range of practical applications: Control systems, such as governing a fan to keep a room at the "just right" temperature; Game AI, such as imbuing bots with human-like decision-making behavior; Prediction systems, linking causes with effects. A FAM uses Fuzzy Sets to establish a set of rules that are linguistic in nature. The linguistic rules, and the fuzzy sets they contain, are defined by a human "expert" (presumably, you). The rules therefore codify intelligence and map this knowledge from the human domain to the digital.
|
16
48
|
email: cpowell@prylis.com
|
@@ -18,13 +50,12 @@ executables: []
|
|
18
50
|
extensions: []
|
19
51
|
extra_rdoc_files: []
|
20
52
|
files:
|
21
|
-
-
|
22
|
-
-
|
23
|
-
-
|
24
|
-
-
|
25
|
-
-
|
26
|
-
-
|
27
|
-
- lib/fuzzy_associative_memory/triangle.rb
|
53
|
+
- .gitignore
|
54
|
+
- CHANGELOG.md
|
55
|
+
- Guardfile
|
56
|
+
- LICENSE
|
57
|
+
- README.md
|
58
|
+
- Rakefile
|
28
59
|
- bin/hvac_system_example.rb
|
29
60
|
- bin/plot of distance to target.png
|
30
61
|
- bin/plot of distance to target.svg
|
@@ -37,13 +68,17 @@ files:
|
|
37
68
|
- bin/plot of weapon desirability.png
|
38
69
|
- bin/plot of weapon desirability.svg
|
39
70
|
- bin/weapon_choice_example.rb
|
40
|
-
-
|
41
|
-
-
|
42
|
-
-
|
43
|
-
-
|
44
|
-
-
|
45
|
-
-
|
46
|
-
-
|
71
|
+
- fuzzy_associative_memory.gemspec
|
72
|
+
- lib/fuzzy_associative_memory.rb
|
73
|
+
- lib/fuzzy_associative_memory/linguistic_variable.rb
|
74
|
+
- lib/fuzzy_associative_memory/rule.rb
|
75
|
+
- lib/fuzzy_associative_memory/ruleset.rb
|
76
|
+
- lib/fuzzy_associative_memory/set.rb
|
77
|
+
- lib/fuzzy_associative_memory/trapezoid.rb
|
78
|
+
- lib/fuzzy_associative_memory/triangle.rb
|
79
|
+
- spec/spec_helper.rb
|
80
|
+
- spec/trapezoid_spec.rb
|
81
|
+
- spec/triangle_spec.rb
|
47
82
|
homepage: http://github.com/cpowell/fuzzy-associative-memory
|
48
83
|
licenses:
|
49
84
|
- LGPL
|
data/test/all_suite.rb
DELETED
data/test/trapezoid_test.rb
DELETED
@@ -1,96 +0,0 @@
|
|
1
|
-
gem 'minitest'
|
2
|
-
require 'minitest/autorun'
|
3
|
-
|
4
|
-
$:.push File.expand_path('../../lib/', __FILE__)
|
5
|
-
require 'fuzzy_associative_memory'
|
6
|
-
|
7
|
-
# ruby ./test/trapezoid_test.rb
|
8
|
-
|
9
|
-
class TrapezoidTest < MiniTest::Unit::TestCase
|
10
|
-
def setup
|
11
|
-
@t = FuzzyAssociativeMemory::Trapezoid.new(7, 10, 13, 16)
|
12
|
-
end
|
13
|
-
|
14
|
-
def test_dom_is_zero_outside_left_bound
|
15
|
-
assert_equal(0, @t.mu(2))
|
16
|
-
end
|
17
|
-
|
18
|
-
def test_dom_is_zero_at_left
|
19
|
-
assert_equal(0, @t.mu(7))
|
20
|
-
end
|
21
|
-
|
22
|
-
def test_dom_is_half_at_half_left_offset
|
23
|
-
assert_equal(0.5, @t.mu(8.5))
|
24
|
-
end
|
25
|
-
|
26
|
-
def test_dom_is_one_at_top_left
|
27
|
-
assert_equal(1.0, @t.mu(10))
|
28
|
-
end
|
29
|
-
|
30
|
-
def test_dom_is_one_at_top_right
|
31
|
-
assert_equal(1.0, @t.mu(13))
|
32
|
-
end
|
33
|
-
|
34
|
-
def test_dom_is_half_at_half_right_offset
|
35
|
-
assert_equal(0.5, @t.mu(14.5))
|
36
|
-
end
|
37
|
-
|
38
|
-
def test_dom_is_zero_at_right
|
39
|
-
assert_equal(0, @t.mu(16))
|
40
|
-
end
|
41
|
-
|
42
|
-
def test_dom_is_zero_outside_right_bound
|
43
|
-
assert_equal(0, @t.mu(17))
|
44
|
-
end
|
45
|
-
|
46
|
-
def test_dom_is_correct_at_three_fifths_offset
|
47
|
-
t = FuzzyAssociativeMemory::Trapezoid.new(0, 5, 10, 15)
|
48
|
-
assert_equal(0.6, t.mu(3.0))
|
49
|
-
end
|
50
|
-
|
51
|
-
def test_dom_is_correct_at_seven_tenths_offset
|
52
|
-
t = FuzzyAssociativeMemory::Trapezoid.new(0, 5, 10, 15)
|
53
|
-
assert_equal(0.6, t.mu(12.0))
|
54
|
-
end
|
55
|
-
|
56
|
-
def test_centroid_calculation_1
|
57
|
-
t = FuzzyAssociativeMemory::Trapezoid.new(0, 20, 50, 50)
|
58
|
-
assert_equal(29.583333333333332, t.centroid_x)
|
59
|
-
end
|
60
|
-
|
61
|
-
def test_centroid_calculation_2
|
62
|
-
t = FuzzyAssociativeMemory::Trapezoid.new(0, 10, 20, 30)
|
63
|
-
assert_equal(15.0, t.centroid_x)
|
64
|
-
end
|
65
|
-
|
66
|
-
def test_centroid_calculation_when_not_starting_at_zero
|
67
|
-
t = FuzzyAssociativeMemory::Trapezoid.new(50, 80, 100, 100)
|
68
|
-
assert_equal(81.42857142857143, t.centroid_x)
|
69
|
-
end
|
70
|
-
|
71
|
-
def test_dom_1
|
72
|
-
t = FuzzyAssociativeMemory::Trapezoid.new(20, 30, 40, 50)
|
73
|
-
assert_equal(0.9, t.mu(41))
|
74
|
-
end
|
75
|
-
|
76
|
-
def test_mamdani_clipping_1
|
77
|
-
t = FuzzyAssociativeMemory::Trapezoid.new(0, 30, 100, 110)
|
78
|
-
t2 = t.mamdani(0.83)
|
79
|
-
assert_equal(0, t2.left)
|
80
|
-
assert_equal(24.9, t2.top_left)
|
81
|
-
assert_equal(101.7, t2.top_right)
|
82
|
-
assert_equal(110, t2.right)
|
83
|
-
assert_equal(0.83, t2.height)
|
84
|
-
end
|
85
|
-
|
86
|
-
def test_mamdani_clipping_2
|
87
|
-
t = FuzzyAssociativeMemory::Trapezoid.new(50, 80, 150, 160)
|
88
|
-
t2 = t.mamdani(0.83)
|
89
|
-
assert_equal(50, t2.left)
|
90
|
-
assert_equal(74.9, t2.top_left)
|
91
|
-
assert_equal(151.7, t2.top_right)
|
92
|
-
assert_equal(160, t2.right)
|
93
|
-
assert_equal(0.83, t2.height)
|
94
|
-
end
|
95
|
-
|
96
|
-
end
|
data/test/triangle_test.rb
DELETED
@@ -1,64 +0,0 @@
|
|
1
|
-
gem 'minitest'
|
2
|
-
require 'minitest/autorun'
|
3
|
-
|
4
|
-
$:.push File.expand_path('../../lib/', __FILE__)
|
5
|
-
require 'fuzzy_associative_memory'
|
6
|
-
|
7
|
-
# ruby ./test/triangle_test.rb
|
8
|
-
|
9
|
-
class TriangleTest < MiniTest::Unit::TestCase
|
10
|
-
def setup
|
11
|
-
@t = FuzzyAssociativeMemory::Triangle.new(7, 10, 13)
|
12
|
-
end
|
13
|
-
|
14
|
-
def test_dom_is_zero_outside_left_bound
|
15
|
-
assert_equal(0, @t.mu(2))
|
16
|
-
end
|
17
|
-
|
18
|
-
def test_dom_is_zero_outside_right_bound
|
19
|
-
assert_equal(0, @t.mu(15))
|
20
|
-
end
|
21
|
-
|
22
|
-
def test_dom_is_one_at_peak
|
23
|
-
assert_equal(1.0, @t.mu(10))
|
24
|
-
end
|
25
|
-
|
26
|
-
def test_dom_is_half_at_half_right_offset
|
27
|
-
assert_equal(0.5, @t.mu(11.5))
|
28
|
-
end
|
29
|
-
|
30
|
-
def test_dom_is_half_at_half_left_offset
|
31
|
-
assert_equal(0.5, @t.mu(8.5))
|
32
|
-
end
|
33
|
-
|
34
|
-
def test_dom_is_correct_at_three_fifths_offset
|
35
|
-
t = FuzzyAssociativeMemory::Triangle.new(0, 5, 10)
|
36
|
-
assert_equal(0.6, t.mu(3.0))
|
37
|
-
end
|
38
|
-
|
39
|
-
def test_dom_is_correct_at_seven_tenths_offset
|
40
|
-
t = FuzzyAssociativeMemory::Triangle.new(0, 5, 10)
|
41
|
-
assert_equal(0.6, t.mu(7.0))
|
42
|
-
end
|
43
|
-
|
44
|
-
def test_centroid_calculation
|
45
|
-
t = FuzzyAssociativeMemory::Triangle.new(5, 10, 15)
|
46
|
-
assert_equal(10.0, t.centroid_x)
|
47
|
-
end
|
48
|
-
|
49
|
-
def test_larsen_scaling
|
50
|
-
scaled = @t.larsen(0.15)
|
51
|
-
assert_equal(0.15, scaled.height)
|
52
|
-
end
|
53
|
-
|
54
|
-
def test_mamdani_clipping_1
|
55
|
-
t2 = @t.mamdani(0.83)
|
56
|
-
assert(t2.is_a? FuzzyAssociativeMemory::Trapezoid)
|
57
|
-
assert_equal(7, t2.left)
|
58
|
-
assert_equal(9.49, t2.top_left)
|
59
|
-
assert_equal(10.51, t2.top_right)
|
60
|
-
assert_equal(13, t2.right)
|
61
|
-
assert_equal(0.83, t2.height)
|
62
|
-
end
|
63
|
-
|
64
|
-
end
|