fuzzyrb 1.0.0 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/History.txt CHANGED
@@ -1,3 +1,9 @@
1
+ == 1.1.0 / 2007-11-15
2
+ * Added Takegi-Sugeno rules
3
+ * Added first minimum defuziffication method
4
+
5
+ * Changed inference to implementation
6
+ * Changed weightCenter to centerOfGravity
1
7
  == 1.0.0 / 2007-11-09
2
8
 
3
9
  * 1 major enhancement
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/fuzzy_inference.rb
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/test_fuzzy_inference.rb
13
+ test/test_fuzzy_implication.rb
14
+ test/test_fuzzy_rule.rb
13
15
  test/test_fuzzy_set.rb
data/README.txt CHANGED
@@ -1,6 +1,6 @@
1
1
  fuzzyrb
2
2
  by Roman Kamyk
3
- http://fuzzyrb.rubyforge.org/
3
+ http://rubyforge.org/projects/fuzzyrb/
4
4
 
5
5
  == DESCRIPTION:
6
6
 
data/Rakefile CHANGED
@@ -4,14 +4,21 @@ require 'rubygems'
4
4
  require 'hoe'
5
5
  require './lib/fuzzy.rb'
6
6
 
7
- Hoe.new('fuzzyrb', Fuzzyrb::VERSION) do |p|
8
- p.rubyforge_name = 'fuzzyrb'
9
- p.author = 'Roman Kamyk'
10
- p.email = 'roman.kamyk@gmail.com'
11
- p.summary = 'Fuzzy Sets for Ruby'
12
- p.description = p.paragraphs_of('README.txt', 2..5).join("\n\n")
13
- p.url = p.paragraphs_of('README.txt', 0).first.split(/\n/)[1..-1]
14
- p.changes = p.paragraphs_of('History.txt', 0..1).join("\n\n")
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
@@ -22,8 +22,8 @@ require 'point'
22
22
  require 'line'
23
23
  require 'fuzzy_set'
24
24
  require 'fuzzy_rule'
25
- require 'fuzzy_inference'
25
+ require 'fuzzy_implication'
26
26
 
27
27
  module Fuzzyrb
28
- VERSION = "1.0.0"
29
- end
28
+ VERSION = "1.1.0"
29
+ end
@@ -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
- def minOfArguments(values)
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.min
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 toLines
19
- lines = []
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 weigthCenter()
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
@@ -4,4 +4,5 @@ require 'test/unit'
4
4
  require 'test/unit/ui/console/testrunner'
5
5
 
6
6
  require 'test_fuzzy_set'
7
- require 'test_fuzzy_inference'
7
+ require 'test_fuzzy_rule'
8
+ require 'test_fuzzy_implication'
@@ -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.0.0
7
- date: 2007-11-10 00:00:00 +01:00
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/fuzzy_inference.rb
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/test_fuzzy_inference.rb
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/test_fuzzy_inference.rb
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
@@ -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
-