fuzzyrb 1.0.0 → 1.1.0
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 +6 -0
- data/Manifest.txt +4 -2
- data/README.txt +1 -1
- data/Rakefile +15 -8
- data/index.html +12 -0
- data/lib/fuzzy.rb +3 -3
- data/lib/fuzzy_implication.rb +31 -0
- data/lib/fuzzy_rule.rb +23 -12
- data/lib/fuzzy_set.rb +46 -35
- data/test/test_fuzzy.rb +2 -1
- data/test/test_fuzzy_implication.rb +35 -0
- data/test/test_fuzzy_rule.rb +18 -0
- data.tar.gz.sig +0 -0
- metadata +8 -5
- metadata.gz.sig +0 -0
- data/lib/fuzzy_inference.rb +0 -19
- data/test/test_fuzzy_inference.rb +0 -27
data/History.txt
CHANGED
data/Manifest.txt
CHANGED
@@ -2,12 +2,14 @@ History.txt
|
|
2
2
|
Manifest.txt
|
3
3
|
README.txt
|
4
4
|
Rakefile
|
5
|
+
index.html
|
5
6
|
lib/fuzzy.rb
|
6
|
-
lib/
|
7
|
+
lib/fuzzy_implication.rb
|
7
8
|
lib/fuzzy_rule.rb
|
8
9
|
lib/fuzzy_set.rb
|
9
10
|
lib/line.rb
|
10
11
|
lib/point.rb
|
11
12
|
test/test_fuzzy.rb
|
12
|
-
test/
|
13
|
+
test/test_fuzzy_implication.rb
|
14
|
+
test/test_fuzzy_rule.rb
|
13
15
|
test/test_fuzzy_set.rb
|
data/README.txt
CHANGED
data/Rakefile
CHANGED
@@ -4,14 +4,21 @@ require 'rubygems'
|
|
4
4
|
require 'hoe'
|
5
5
|
require './lib/fuzzy.rb'
|
6
6
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
7
|
+
namespace :hoe do
|
8
|
+
Hoe.new('fuzzyrb', Fuzzyrb::VERSION) do |p|
|
9
|
+
p.rubyforge_name = 'fuzzyrb'
|
10
|
+
p.author = 'Roman Kamyk'
|
11
|
+
p.email = 'roman.kamyk@gmail.com'
|
12
|
+
p.summary = 'Fuzzy Sets for Ruby'
|
13
|
+
p.description = p.paragraphs_of('README.txt', 2..5).join("\n\n")
|
14
|
+
p.url = p.paragraphs_of('README.txt', 0).first.split(/\n/)[1..-1]
|
15
|
+
p.changes = p.paragraphs_of('History.txt', 0..1).join("\n\n")
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
task :publish => ['hoe:release', 'hoe:post_news', 'hoe:publish_docs'] do
|
20
|
+
sh "svn ci -m '#{@changes}'"
|
21
|
+
sh "hg ci -m '#{@changes}'"
|
15
22
|
end
|
16
23
|
|
17
24
|
# vim: syntax=Ruby
|
data/index.html
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
|
2
|
+
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
3
|
+
<html>
|
4
|
+
<head>
|
5
|
+
<meta http-equiv="Content-type" content="text/html; charset=utf-8">
|
6
|
+
<title>redirect</title>
|
7
|
+
<meta http-equiv="Refresh" content="1; URL=fuzzyrb/">
|
8
|
+
</head>
|
9
|
+
<body id="index">
|
10
|
+
Please see: <a href="http://fuzzyrb.rubyforge.org/fuzzyrb/">documentation</a>.
|
11
|
+
</body>
|
12
|
+
</html>
|
data/lib/fuzzy.rb
CHANGED
@@ -0,0 +1,31 @@
|
|
1
|
+
class FuzzyImplication
|
2
|
+
def initialize(rules)
|
3
|
+
@rules = rules
|
4
|
+
end
|
5
|
+
end
|
6
|
+
|
7
|
+
class TakagiSugenoImplication < FuzzyImplication
|
8
|
+
def evaluate(t_norm, values)
|
9
|
+
sum = 0
|
10
|
+
result = @rules.map { |rule|
|
11
|
+
rule.evaluate(t_norm, :takagiSugeno, values)
|
12
|
+
}.inject(0) { |s, rv| sum += rv[1]; s + rv[0] }
|
13
|
+
return 0 if sum == 0
|
14
|
+
result/sum
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
class MamdamiImplication < FuzzyImplication
|
19
|
+
def evaluate(t_norm, implication, defuzzification, values)
|
20
|
+
result = @rules.map { |rule|
|
21
|
+
rule.evaluate(t_norm, implication, values)
|
22
|
+
}.inject { |s, r| s + r }
|
23
|
+
if defuzzification == :CoG
|
24
|
+
return result.centerOfGravity
|
25
|
+
elsif defuzzification == :firstMin
|
26
|
+
return result.firstMinimum
|
27
|
+
else
|
28
|
+
raise Exception.new("Invalid deffuzification method")
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
data/lib/fuzzy_rule.rb
CHANGED
@@ -3,22 +3,33 @@ class FuzzyRule
|
|
3
3
|
@arguments = arguments
|
4
4
|
@result = result
|
5
5
|
end
|
6
|
+
|
7
|
+
def evaluate(t_norm, implication, values)
|
8
|
+
if t_norm == :min
|
9
|
+
val = argumentsValues(values).min
|
10
|
+
elsif t_norm == :mult
|
11
|
+
val = argumentsValues(values).inject(1) { |mult, v| mult*v}
|
12
|
+
elsif
|
13
|
+
raise Exception.new("Invalid t_norm")
|
14
|
+
end
|
15
|
+
if implication == :mamdani
|
16
|
+
return @result.min(val)
|
17
|
+
elsif implication == :larsen
|
18
|
+
return @result.scale(val)
|
19
|
+
elsif implication == :takagiSugeno
|
20
|
+
#rule value and certainity
|
21
|
+
return [@result.call(values), val]
|
22
|
+
else
|
23
|
+
raise Exception.new("Invalid type")
|
24
|
+
end
|
25
|
+
end
|
6
26
|
|
7
|
-
|
27
|
+
private
|
28
|
+
def argumentsValues(values)
|
8
29
|
tmp = []
|
9
30
|
for i in 0..(values.length-1)
|
10
31
|
tmp << @arguments[i][values[i]]
|
11
32
|
end
|
12
|
-
tmp
|
13
|
-
end
|
14
|
-
|
15
|
-
def larsen(values)
|
16
|
-
min = minOfArguments(values)
|
17
|
-
@result.scale(min)
|
18
|
-
end
|
19
|
-
|
20
|
-
def mandani(values)
|
21
|
-
min = minOfArguments(values)
|
22
|
-
@result.min(min)
|
33
|
+
tmp
|
23
34
|
end
|
24
35
|
end
|
data/lib/fuzzy_set.rb
CHANGED
@@ -1,10 +1,6 @@
|
|
1
1
|
EPSILON = 0.0001
|
2
2
|
SCALE = 1
|
3
3
|
class FuzzySet
|
4
|
-
def initialize(points)
|
5
|
-
@points = points.sort
|
6
|
-
end
|
7
|
-
|
8
4
|
def self.trapezoid(array)
|
9
5
|
raise Exception.new("Trapezoid must have array length 4") if array.length != 4
|
10
6
|
points = []
|
@@ -14,38 +10,11 @@ class FuzzySet
|
|
14
10
|
points << Point.new(array[3], 0)
|
15
11
|
FuzzySet.new(points)
|
16
12
|
end
|
17
|
-
|
18
|
-
def
|
19
|
-
|
20
|
-
for i in 1..@points.length-1
|
21
|
-
lines << Line.new(@points[i], @points[i-1])
|
22
|
-
end
|
23
|
-
lines
|
13
|
+
|
14
|
+
def initialize(points)
|
15
|
+
@points = points.sort
|
24
16
|
end
|
25
17
|
|
26
|
-
def intersections(other)
|
27
|
-
if other.is_a?(Line)
|
28
|
-
points = []
|
29
|
-
toLines.each { |mline|
|
30
|
-
points << mline.intersect(other)
|
31
|
-
}
|
32
|
-
points.select { |point| (self[point.x]-point.y).abs <= EPSILON }
|
33
|
-
elsif other.is_a?(FuzzySet)
|
34
|
-
myLines = toLines
|
35
|
-
points = []
|
36
|
-
other.toLines.each { |line|
|
37
|
-
myLines.each { |mline|
|
38
|
-
points << mline.intersect(line)
|
39
|
-
}
|
40
|
-
}
|
41
|
-
points.select { |point|
|
42
|
-
(self[point.x]-point.y).abs + (other[point.x]-point.y).abs <= EPSILON
|
43
|
-
}
|
44
|
-
else
|
45
|
-
raise Exception.new("Unable to count intersection")
|
46
|
-
end
|
47
|
-
end
|
48
|
-
|
49
18
|
def +(other)
|
50
19
|
points = [@points, other.points, intersections(other)].flatten.uniq.sort
|
51
20
|
res = points.reject { |point|
|
@@ -72,7 +41,7 @@ class FuzzySet
|
|
72
41
|
end
|
73
42
|
attr_reader :points
|
74
43
|
|
75
|
-
def
|
44
|
+
def centerOfGravity()
|
76
45
|
nominator = 0.0
|
77
46
|
denominator = 0.0
|
78
47
|
for i in 1..@points.length-1
|
@@ -85,6 +54,16 @@ class FuzzySet
|
|
85
54
|
nominator/denominator
|
86
55
|
end
|
87
56
|
|
57
|
+
def firstMinimum()
|
58
|
+
maxIdx = 0
|
59
|
+
for i in 0..@points.length-1
|
60
|
+
if @points[i].y > @points[maxIdx].y
|
61
|
+
maxIdx = i
|
62
|
+
end
|
63
|
+
end
|
64
|
+
@points[maxIdx].x
|
65
|
+
end
|
66
|
+
|
88
67
|
def scale(factor)
|
89
68
|
fs = FuzzySet.new(@points.map { |p| p.clone() })
|
90
69
|
fs.scale!(factor)
|
@@ -112,4 +91,36 @@ class FuzzySet
|
|
112
91
|
y2 = @points[idx].y
|
113
92
|
return 1.0*(y2 - y1)/(x2-x1) * (value - x1) + y1
|
114
93
|
end
|
94
|
+
|
95
|
+
def toLines
|
96
|
+
lines = []
|
97
|
+
for i in 1..@points.length-1
|
98
|
+
lines << Line.new(@points[i], @points[i-1])
|
99
|
+
end
|
100
|
+
lines
|
101
|
+
end
|
102
|
+
|
103
|
+
private
|
104
|
+
def intersections(other)
|
105
|
+
if other.is_a?(Line)
|
106
|
+
points = []
|
107
|
+
toLines.each { |mline|
|
108
|
+
points << mline.intersect(other)
|
109
|
+
}
|
110
|
+
points.select { |point| (self[point.x]-point.y).abs <= EPSILON }
|
111
|
+
elsif other.is_a?(FuzzySet)
|
112
|
+
myLines = toLines
|
113
|
+
points = []
|
114
|
+
other.toLines.each { |line|
|
115
|
+
myLines.each { |mline|
|
116
|
+
points << mline.intersect(line)
|
117
|
+
}
|
118
|
+
}
|
119
|
+
points.select { |point|
|
120
|
+
(self[point.x]-point.y).abs + (other[point.x]-point.y).abs <= EPSILON
|
121
|
+
}
|
122
|
+
else
|
123
|
+
raise Exception.new("Unable to count intersection")
|
124
|
+
end
|
125
|
+
end
|
115
126
|
end
|
data/test/test_fuzzy.rb
CHANGED
@@ -0,0 +1,35 @@
|
|
1
|
+
#!/usr/bin/ruby
|
2
|
+
$:.unshift(File.dirname(__FILE__) + "/../lib/")
|
3
|
+
require 'test/unit'
|
4
|
+
require 'fuzzy'
|
5
|
+
|
6
|
+
class TestFuzzyImplication < Test::Unit::TestCase
|
7
|
+
def setup
|
8
|
+
a11 = FuzzySet.trapezoid([4, 5, 5, 10])
|
9
|
+
a12 = FuzzySet.trapezoid([10, 19, 19, 20])
|
10
|
+
a21 = FuzzySet.trapezoid([4, 9, 9, 10])
|
11
|
+
a22 = FuzzySet.trapezoid([10, 12, 13, 20])
|
12
|
+
b1 = FuzzySet.trapezoid([20, 30, 30, 40])
|
13
|
+
b2 = FuzzySet.trapezoid([30, 45, 45, 50])
|
14
|
+
r1 = FuzzyRule.new([a11, a12], b1)
|
15
|
+
r2 = FuzzyRule.new([a21, a22], b2)
|
16
|
+
@fi = MamdamiImplication.new([r1, r2])
|
17
|
+
|
18
|
+
tr1 = FuzzyRule.new([a11, a12], Proc.new { |a, b| a+b })
|
19
|
+
tr2 = FuzzyRule.new([a21, a22], Proc.new { |a, b| a-b })
|
20
|
+
@tsi = TakagiSugenoImplication.new([tr1, tr2])
|
21
|
+
end
|
22
|
+
|
23
|
+
def test_mamdani
|
24
|
+
assert_in_delta 33.71, @fi.evaluate(:min, :mamdani, :CoG, [7, 18]), 0.005
|
25
|
+
end
|
26
|
+
|
27
|
+
def test_larsen
|
28
|
+
assert_in_delta 33.58, @fi.evaluate(:min, :larsen, :CoG, [7, 18]), 0.005
|
29
|
+
end
|
30
|
+
|
31
|
+
def test_takagi_sugeno
|
32
|
+
assert_equal 0, @tsi.evaluate(:min, [10, 20])
|
33
|
+
assert_equal 8.75, @tsi.evaluate(:min, [5, 19])
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
#!/usr/bin/ruby
|
2
|
+
$:.unshift(File.dirname(__FILE__) + "/../lib/")
|
3
|
+
require 'test/unit'
|
4
|
+
require 'fuzzy'
|
5
|
+
|
6
|
+
class TestFuzzyRule < Test::Unit::TestCase
|
7
|
+
def setup
|
8
|
+
a11 = FuzzySet.trapezoid([4, 5, 5, 10])
|
9
|
+
a12 = FuzzySet.trapezoid([8, 10, 12, 20])
|
10
|
+
@rule = FuzzyRule.new([a11, a12], Proc.new {|a, b| a+b})
|
11
|
+
end
|
12
|
+
|
13
|
+
def test_larsen
|
14
|
+
assert_equal [25, 0.25], @rule.evaluate(:min, :takagiSugeno, [7, 18])
|
15
|
+
assert_equal [16, 1], @rule.evaluate(:min, :takagiSugeno, [5, 11])
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
data.tar.gz.sig
CHANGED
Binary file
|
metadata
CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.9.4
|
|
3
3
|
specification_version: 1
|
4
4
|
name: fuzzyrb
|
5
5
|
version: !ruby/object:Gem::Version
|
6
|
-
version: 1.
|
7
|
-
date: 2007-11-
|
6
|
+
version: 1.1.0
|
7
|
+
date: 2007-11-15 00:00:00 +01:00
|
8
8
|
summary: Fuzzy Sets for Ruby
|
9
9
|
require_paths:
|
10
10
|
- lib
|
@@ -55,18 +55,21 @@ files:
|
|
55
55
|
- Manifest.txt
|
56
56
|
- README.txt
|
57
57
|
- Rakefile
|
58
|
+
- index.html
|
58
59
|
- lib/fuzzy.rb
|
59
|
-
- lib/
|
60
|
+
- lib/fuzzy_implication.rb
|
60
61
|
- lib/fuzzy_rule.rb
|
61
62
|
- lib/fuzzy_set.rb
|
62
63
|
- lib/line.rb
|
63
64
|
- lib/point.rb
|
64
65
|
- test/test_fuzzy.rb
|
65
|
-
- test/
|
66
|
+
- test/test_fuzzy_implication.rb
|
67
|
+
- test/test_fuzzy_rule.rb
|
66
68
|
- test/test_fuzzy_set.rb
|
67
69
|
test_files:
|
68
70
|
- test/test_fuzzy.rb
|
69
|
-
- test/
|
71
|
+
- test/test_fuzzy_implication.rb
|
72
|
+
- test/test_fuzzy_rule.rb
|
70
73
|
- test/test_fuzzy_set.rb
|
71
74
|
rdoc_options:
|
72
75
|
- --main
|
metadata.gz.sig
CHANGED
Binary file
|
data/lib/fuzzy_inference.rb
DELETED
@@ -1,19 +0,0 @@
|
|
1
|
-
class FuzzyInference
|
2
|
-
def initialize(rules)
|
3
|
-
@rules = rules
|
4
|
-
end
|
5
|
-
|
6
|
-
def mandani(values)
|
7
|
-
result = @rules.map { |rule|
|
8
|
-
rule.mandani(values)
|
9
|
-
}.inject { |s, r| s + r }
|
10
|
-
result.weigthCenter
|
11
|
-
end
|
12
|
-
|
13
|
-
def larsen(values)
|
14
|
-
result = @rules.map { |rule|
|
15
|
-
rule.larsen(values)
|
16
|
-
}.inject { |s, r| s + r }
|
17
|
-
result.weigthCenter
|
18
|
-
end
|
19
|
-
end
|
@@ -1,27 +0,0 @@
|
|
1
|
-
#!/usr/bin/ruby
|
2
|
-
$:.unshift(File.dirname(__FILE__) + "/../lib/")
|
3
|
-
require 'test/unit'
|
4
|
-
require 'fuzzy'
|
5
|
-
|
6
|
-
class TestFuzzyInference < Test::Unit::TestCase
|
7
|
-
def setup
|
8
|
-
a11 = FuzzySet.trapezoid([4, 5, 5, 10])
|
9
|
-
a12 = FuzzySet.trapezoid([10, 19, 19, 20])
|
10
|
-
a21 = FuzzySet.trapezoid([4, 9, 9, 10])
|
11
|
-
a22 = FuzzySet.trapezoid([10, 12, 13, 20])
|
12
|
-
b1 = FuzzySet.trapezoid([20, 30, 30, 40])
|
13
|
-
b2 = FuzzySet.trapezoid([30, 45, 45, 50])
|
14
|
-
r1 = FuzzyRule.new([a11, a12], b1)
|
15
|
-
r2 = FuzzyRule.new([a21, a22], b2)
|
16
|
-
@fi = FuzzyInference.new([r1, r2])
|
17
|
-
end
|
18
|
-
|
19
|
-
def test_mandani
|
20
|
-
assert_in_delta 33.71, @fi.mandani([7, 18]), 0.005
|
21
|
-
end
|
22
|
-
|
23
|
-
def test_larsen
|
24
|
-
assert_in_delta 33.58, @fi.larsen([7, 18]), 0.005
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|