fuzzyrb 1.0.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.tar.gz.sig +1 -0
- data/History.txt +5 -0
- data/Manifest.txt +13 -0
- data/README.txt +50 -0
- data/Rakefile +17 -0
- data/lib/fuzzy.rb +29 -0
- data/lib/fuzzy_inference.rb +19 -0
- data/lib/fuzzy_rule.rb +24 -0
- data/lib/fuzzy_set.rb +115 -0
- data/lib/line.rb +16 -0
- data/lib/point.rb +14 -0
- data/test/test_fuzzy.rb +7 -0
- data/test/test_fuzzy_inference.rb +27 -0
- data/test/test_fuzzy_set.rb +30 -0
- metadata +93 -0
- metadata.gz.sig +0 -0
data.tar.gz.sig
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
]�#,��^L�B0�ﳘ.q��O������:|��7r�����&�L���ն���Y���9������nts�#����/�=���u(X�����ԍu�a�[�$ga
|
data/History.txt
ADDED
data/Manifest.txt
ADDED
data/README.txt
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
fuzzyrb
|
2
|
+
by Roman Kamyk
|
3
|
+
http://fuzzyrb.rubyforge.org/
|
4
|
+
|
5
|
+
== DESCRIPTION:
|
6
|
+
|
7
|
+
Implements Fuzzy Sets in Ruby. I am very beginner at this topic, so it is very basic now. Any help will be appreciated.
|
8
|
+
|
9
|
+
== FEATURES/PROBLEMS:
|
10
|
+
|
11
|
+
* Fuzzy Sets defined as line segments
|
12
|
+
* Fuzzy Rules. Only conjunction of arguments is possible.
|
13
|
+
* No error handling.
|
14
|
+
* Deffuzification as center of gravity.
|
15
|
+
* Reasoning - apply matching rule and combine the results.
|
16
|
+
|
17
|
+
== SYNOPSIS:
|
18
|
+
|
19
|
+
Cannot be used from console. See test/ for sample usage.
|
20
|
+
|
21
|
+
== REQUIREMENTS:
|
22
|
+
|
23
|
+
* Ruby
|
24
|
+
|
25
|
+
== INSTALL:
|
26
|
+
|
27
|
+
sudo gem install fuzzyrb
|
28
|
+
|
29
|
+
== LICENSE:
|
30
|
+
|
31
|
+
(The GPL License)
|
32
|
+
|
33
|
+
Copyright (C) 2007 Roman Kamyk
|
34
|
+
|
35
|
+
This program is free software: you can redistribute it and/or modify
|
36
|
+
it under the terms of the GNU General Public License as published by
|
37
|
+
the Free Software Foundation, either version 3 of the License, or
|
38
|
+
(at your option) any later version.
|
39
|
+
|
40
|
+
This program is distributed in the hope that it will be useful,
|
41
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
42
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
43
|
+
GNU General Public License for more details.
|
44
|
+
|
45
|
+
You should have received a copy of the GNU General Public License
|
46
|
+
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
47
|
+
|
48
|
+
== Author
|
49
|
+
Roman 'MrStone' Kamyk (mailto:roman.kamyk@gmail.com),
|
50
|
+
Student of Poznan University Of Technology, Computing Science Institute, Inteligent Decision Support Systems
|
data/Rakefile
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
# -*- ruby -*-
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'hoe'
|
5
|
+
require './lib/fuzzy.rb'
|
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")
|
15
|
+
end
|
16
|
+
|
17
|
+
# vim: syntax=Ruby
|
data/lib/fuzzy.rb
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# Created by Roman Kamyk <roman.kamyk@gmail.com on 2007-11-09.
|
3
|
+
# Copyright (C) 2007 Roman Kamyk
|
4
|
+
#
|
5
|
+
# This program is free software: you can redistribute it and/or modify
|
6
|
+
# it under the terms of the GNU General Public License as published by
|
7
|
+
# the Free Software Foundation, either version 3 of the License, or
|
8
|
+
# (at your option) any later version.
|
9
|
+
#
|
10
|
+
# This program is distributed in the hope that it will be useful,
|
11
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
12
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
13
|
+
# GNU General Public License for more details.
|
14
|
+
#
|
15
|
+
# You should have received a copy of the GNU General Public License
|
16
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
17
|
+
|
18
|
+
require 'pp'
|
19
|
+
|
20
|
+
$:.unshift(File.dirname(__FILE__) + "/../lib/")
|
21
|
+
require 'point'
|
22
|
+
require 'line'
|
23
|
+
require 'fuzzy_set'
|
24
|
+
require 'fuzzy_rule'
|
25
|
+
require 'fuzzy_inference'
|
26
|
+
|
27
|
+
module Fuzzyrb
|
28
|
+
VERSION = "1.0.0"
|
29
|
+
end
|
@@ -0,0 +1,19 @@
|
|
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
|
data/lib/fuzzy_rule.rb
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
class FuzzyRule
|
2
|
+
def initialize(arguments, result)
|
3
|
+
@arguments = arguments
|
4
|
+
@result = result
|
5
|
+
end
|
6
|
+
|
7
|
+
def minOfArguments(values)
|
8
|
+
tmp = []
|
9
|
+
for i in 0..(values.length-1)
|
10
|
+
tmp << @arguments[i][values[i]]
|
11
|
+
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)
|
23
|
+
end
|
24
|
+
end
|
data/lib/fuzzy_set.rb
ADDED
@@ -0,0 +1,115 @@
|
|
1
|
+
EPSILON = 0.0001
|
2
|
+
SCALE = 1
|
3
|
+
class FuzzySet
|
4
|
+
def initialize(points)
|
5
|
+
@points = points.sort
|
6
|
+
end
|
7
|
+
|
8
|
+
def self.trapezoid(array)
|
9
|
+
raise Exception.new("Trapezoid must have array length 4") if array.length != 4
|
10
|
+
points = []
|
11
|
+
points << Point.new(array[0], 0)
|
12
|
+
points << Point.new(array[1], SCALE)
|
13
|
+
points << Point.new(array[2], SCALE) unless array[2] == array[1]
|
14
|
+
points << Point.new(array[3], 0)
|
15
|
+
FuzzySet.new(points)
|
16
|
+
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
|
24
|
+
end
|
25
|
+
|
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
|
+
def +(other)
|
50
|
+
points = [@points, other.points, intersections(other)].flatten.uniq.sort
|
51
|
+
res = points.reject { |point|
|
52
|
+
self[point.x]-EPSILON > point.y or other[point.x]-EPSILON > point.y
|
53
|
+
}
|
54
|
+
FuzzySet.new(res)
|
55
|
+
end
|
56
|
+
|
57
|
+
def min(value)
|
58
|
+
line = Line.new(Point.new(0, value), Point.new(1, value))
|
59
|
+
points = [@points, intersections(line)].flatten.uniq.sort
|
60
|
+
res = points.reject { |p| self[p.x] - EPSILON > value }
|
61
|
+
FuzzySet.new(res)
|
62
|
+
end
|
63
|
+
|
64
|
+
# Choose min of current and _other_ set
|
65
|
+
def &(other)
|
66
|
+
points = [@points, crosspoints(other)].flatten.uniq.sort
|
67
|
+
res = []
|
68
|
+
points.each { |point|
|
69
|
+
res << point if self[point.x]-EPSILON < point.y and self[point.x]+EPSILON > point.y and other[point.x]+EPSILON >= self[point.x]
|
70
|
+
}
|
71
|
+
FuzzySet.new(res)
|
72
|
+
end
|
73
|
+
attr_reader :points
|
74
|
+
|
75
|
+
def weigthCenter()
|
76
|
+
nominator = 0.0
|
77
|
+
denominator = 0.0
|
78
|
+
for i in 1..@points.length-1
|
79
|
+
line = Line.new(@points[i], @points[i-1])
|
80
|
+
x2 = points[i].x
|
81
|
+
x1 = points[i-1].x
|
82
|
+
nominator += line.a * x2**3/3 + line.b * x2**2/2 - line.a * x1**3/3 - line.b * x1**2/2
|
83
|
+
denominator += line.a * x2**2/2 + line.b * x2 - line.a * x1**2/2 - line.b * x1
|
84
|
+
end
|
85
|
+
nominator/denominator
|
86
|
+
end
|
87
|
+
|
88
|
+
def scale(factor)
|
89
|
+
fs = FuzzySet.new(@points.map { |p| p.clone() })
|
90
|
+
fs.scale!(factor)
|
91
|
+
end
|
92
|
+
|
93
|
+
def scale!(factor)
|
94
|
+
@points.each { |point| point.y *= factor / SCALE }
|
95
|
+
self
|
96
|
+
end
|
97
|
+
|
98
|
+
def [](value)
|
99
|
+
if value<@points[0].x
|
100
|
+
return 0
|
101
|
+
elsif value > @points.last.x
|
102
|
+
return 0
|
103
|
+
end
|
104
|
+
idx = 0
|
105
|
+
while (@points[idx].x < value)
|
106
|
+
idx += 1
|
107
|
+
end
|
108
|
+
return @points[idx].y if @points[idx].x == value
|
109
|
+
x1 = @points[idx-1].x
|
110
|
+
x2 = @points[idx].x
|
111
|
+
y1 = @points[idx-1].y
|
112
|
+
y2 = @points[idx].y
|
113
|
+
return 1.0*(y2 - y1)/(x2-x1) * (value - x1) + y1
|
114
|
+
end
|
115
|
+
end
|
data/lib/line.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
class Line
|
2
|
+
def initialize(p1, p2)
|
3
|
+
@a = 1.0*(p2.y-p1.y)/(p2.x-p1.x)
|
4
|
+
@b = 1.0*p1.y - @a*p1.x
|
5
|
+
# pp [p1, p2, @a, @b]
|
6
|
+
end
|
7
|
+
|
8
|
+
def intersect(other)
|
9
|
+
x = 1.0*(b-other.b)/(other.a-a)
|
10
|
+
y = 1.0*a*x+b
|
11
|
+
# pp [self, other, x, y]
|
12
|
+
Point.new(x, y)
|
13
|
+
end
|
14
|
+
|
15
|
+
attr_accessor :a, :b
|
16
|
+
end
|
data/lib/point.rb
ADDED
data/test/test_fuzzy.rb
ADDED
@@ -0,0 +1,27 @@
|
|
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
|
+
|
@@ -0,0 +1,30 @@
|
|
1
|
+
#!/usr/bin/ruby
|
2
|
+
require 'test/unit'
|
3
|
+
require 'fuzzy'
|
4
|
+
|
5
|
+
class TestFuzzySet < Test::Unit::TestCase
|
6
|
+
def test_trapezoid1
|
7
|
+
t = FuzzySet.trapezoid([4, 5, 5, 10])
|
8
|
+
assert_equal(0, t[4])
|
9
|
+
assert_equal(1, t[5])
|
10
|
+
assert_equal(0, t[10])
|
11
|
+
assert_equal(0.5, t[4.5])
|
12
|
+
assert_equal(0.8, t[6])
|
13
|
+
assert_equal(0.6, t[7])
|
14
|
+
end
|
15
|
+
|
16
|
+
def test_trapezoid2
|
17
|
+
t = FuzzySet.trapezoid([10, 12, 13, 20])
|
18
|
+
assert_equal(0, t[9])
|
19
|
+
assert_equal(0, t[10])
|
20
|
+
assert_equal(0.5, t[11])
|
21
|
+
assert_equal(0, t[-1000])
|
22
|
+
assert_equal(1, t[12])
|
23
|
+
assert_equal(1, t[12.5])
|
24
|
+
assert_equal(1, t[13])
|
25
|
+
assert_equal(0, t[20])
|
26
|
+
assert_equal(0, t[1000])
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
|
metadata
ADDED
@@ -0,0 +1,93 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
rubygems_version: 0.9.4
|
3
|
+
specification_version: 1
|
4
|
+
name: fuzzyrb
|
5
|
+
version: !ruby/object:Gem::Version
|
6
|
+
version: 1.0.0
|
7
|
+
date: 2007-11-10 00:00:00 +01:00
|
8
|
+
summary: Fuzzy Sets for Ruby
|
9
|
+
require_paths:
|
10
|
+
- lib
|
11
|
+
email: roman.kamyk@gmail.com
|
12
|
+
homepage: " by Roman Kamyk"
|
13
|
+
rubyforge_project: fuzzyrb
|
14
|
+
description: "== FEATURES/PROBLEMS: * Fuzzy Sets defined as line segments * Fuzzy Rules. Only conjunction of arguments is possible. * No error handling. * Deffuzification as center of gravity. * Reasoning - apply matching rule and combine the results. == SYNOPSIS: Cannot be used from console. See test/ for sample usage. == REQUIREMENTS:"
|
15
|
+
autorequire:
|
16
|
+
default_executable:
|
17
|
+
bindir: bin
|
18
|
+
has_rdoc: true
|
19
|
+
required_ruby_version: !ruby/object:Gem::Version::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">"
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 0.0.0
|
24
|
+
version:
|
25
|
+
platform: ruby
|
26
|
+
signing_key:
|
27
|
+
cert_chain:
|
28
|
+
- |
|
29
|
+
-----BEGIN CERTIFICATE-----
|
30
|
+
MIIDODCCAiCgAwIBAgIBADANBgkqhkiG9w0BAQUFADBCMRQwEgYDVQQDDAtyb21h
|
31
|
+
bi5rYW15azEVMBMGCgmSJomT8ixkARkWBWdtYWlsMRMwEQYKCZImiZPyLGQBGRYD
|
32
|
+
Y29tMB4XDTA3MTExMDA1MzUzM1oXDTA4MTEwOTA1MzUzM1owQjEUMBIGA1UEAwwL
|
33
|
+
cm9tYW4ua2FteWsxFTATBgoJkiaJk/IsZAEZFgVnbWFpbDETMBEGCgmSJomT8ixk
|
34
|
+
ARkWA2NvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMdV1ujoU4I2
|
35
|
+
daF4KANtDPTSjLYhXC1CiiyEgGEVA6GvieQ2NpNNsSXl+6tbWXGNUWFHj50rrLTC
|
36
|
+
e1dJSGGTZa9ZjI6fkeb/Gr13s71ncCJ+hBbpvktWIWdvOvzvNo9bdzNCKX00Rlk5
|
37
|
+
hQzxhm/ZxQ2VG4ZDYc/gWOCzKYH8aKrAzzdjRsxE/QMgnVbnirCGSPQTjPVhBvcX
|
38
|
+
pH2yDvZF9NOs3D89JvA4P50WRCe8/kKPx7TG9Qkd303/FmO8yDUvJn0KgiYkm1pc
|
39
|
+
Sb+kcDZnh2+2uvkygLLDQhV5m7DfFLLkgwb/t7R4tSNFqcHoa0829rnSVBbCZACg
|
40
|
+
mrXhThP3LX8CAwEAAaM5MDcwCQYDVR0TBAIwADALBgNVHQ8EBAMCBLAwHQYDVR0O
|
41
|
+
BBYEFGVgSLBvjD5kTd+1XMf58PK9llj6MA0GCSqGSIb3DQEBBQUAA4IBAQCGX43w
|
42
|
+
PspP+rmsfCKztiUwtfb4d+eqW62WaAUBT37KeW8IEm3UpAe5T1c3fFm46bxM3a2Y
|
43
|
+
wUeLqSMSquXNzb2fy+3vLAUYHc4UkR5nA5kB+F3RJwuc7LJCBGlkPsCfa91dE6j5
|
44
|
+
S80vqeRf4ITITHZbFLuVFFvQb/nPGe2LtyP4+neAktSu4r7rQ5vLbQQ/NSAliFrP
|
45
|
+
pJbWXmfjKQsDKGgs1TiISC3kfLcynhCgCcbLCek5Oc0U195z36e8x3aYEJSGFVmF
|
46
|
+
y8xfBxyZ4t0FP3lTPvGMfmSKOVOjcwT4OVpzdvRXWR8lghrQlAzNG5HdOxMzeBjb
|
47
|
+
Z2byiG0rlbybmXMS
|
48
|
+
-----END CERTIFICATE-----
|
49
|
+
|
50
|
+
post_install_message:
|
51
|
+
authors:
|
52
|
+
- Roman Kamyk
|
53
|
+
files:
|
54
|
+
- History.txt
|
55
|
+
- Manifest.txt
|
56
|
+
- README.txt
|
57
|
+
- Rakefile
|
58
|
+
- lib/fuzzy.rb
|
59
|
+
- lib/fuzzy_inference.rb
|
60
|
+
- lib/fuzzy_rule.rb
|
61
|
+
- lib/fuzzy_set.rb
|
62
|
+
- lib/line.rb
|
63
|
+
- lib/point.rb
|
64
|
+
- test/test_fuzzy.rb
|
65
|
+
- test/test_fuzzy_inference.rb
|
66
|
+
- test/test_fuzzy_set.rb
|
67
|
+
test_files:
|
68
|
+
- test/test_fuzzy.rb
|
69
|
+
- test/test_fuzzy_inference.rb
|
70
|
+
- test/test_fuzzy_set.rb
|
71
|
+
rdoc_options:
|
72
|
+
- --main
|
73
|
+
- README.txt
|
74
|
+
extra_rdoc_files:
|
75
|
+
- History.txt
|
76
|
+
- Manifest.txt
|
77
|
+
- README.txt
|
78
|
+
executables: []
|
79
|
+
|
80
|
+
extensions: []
|
81
|
+
|
82
|
+
requirements: []
|
83
|
+
|
84
|
+
dependencies:
|
85
|
+
- !ruby/object:Gem::Dependency
|
86
|
+
name: hoe
|
87
|
+
version_requirement:
|
88
|
+
version_requirements: !ruby/object:Gem::Version::Requirement
|
89
|
+
requirements:
|
90
|
+
- - ">="
|
91
|
+
- !ruby/object:Gem::Version
|
92
|
+
version: 1.3.0
|
93
|
+
version:
|
metadata.gz.sig
ADDED
Binary file
|