Class: FuzzyAssociativeMemory::Ruleset

Inherits:
Object
  • Object
show all
Defined in:
lib/fuzzy_associative_memory/ruleset.rb

Overview

Copyright 2013, Prylis Incorporated.

This file is part of The Ruby Fuzzy Associative Memory github.com/cpowell/fuzzy-associative-memory You can redistribute and/or modify this software only in accordance with the terms found in the “LICENSE” file included with the library.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(name, implication_mechanism) ⇒ Ruleset

Returns a new instance of Ruleset.

Raises:

  • (ArgumentError)


15
16
17
18
19
20
21
# File 'lib/fuzzy_associative_memory/ruleset.rb', line 15

def initialize(name, implication_mechanism)
  raise ArgumentError, 'invalid implication mechanism' unless [:larsen, :mamdani].include? implication_mechanism
  @name  = name
  @rules = []
  @implication = implication_mechanism
  @consequent_mus   = {}
end

Instance Attribute Details

#implicationObject (readonly)

Returns the value of attribute implication.



13
14
15
# File 'lib/fuzzy_associative_memory/ruleset.rb', line 13

def implication
  @implication
end

#nameObject (readonly)

Returns the value of attribute name.



12
13
14
# File 'lib/fuzzy_associative_memory/ruleset.rb', line 12

def name
  @name
end

#rulesObject

Returns the value of attribute rules.



11
12
13
# File 'lib/fuzzy_associative_memory/ruleset.rb', line 11

def rules
  @rules
end

Instance Method Details

#add_rule(rule) ⇒ Object



23
24
25
# File 'lib/fuzzy_associative_memory/ruleset.rb', line 23

def add_rule(rule)
  @rules << rule
end

#calculate(*input_values) ⇒ Object



27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
# File 'lib/fuzzy_associative_memory/ruleset.rb', line 27

def calculate(*input_values)
  # puts ">>> Firing all rules..." if $verbosity
  for rule in @rules
    # Fire each rule to determine the µ value (degree of fit).
    # Gather the µ vals by consequent, since each consequent may in fact
    # have been fired more than once and we'll need that knowledge in a
    # moment...
    mu = rule.fire(input_values)
    cons = rule.consequent

    # Since any given consequent may have been activated more than once, we
    # need to get just a single µ value out -- we only care about the 'best'
    # µ. A popular way of doing so is to OR the values together, i.e. keep the
    # maximum µ value and discard the others.
    curr_best = @consequent_mus[cons]
    @consequent_mus[cons] = mu if curr_best.nil? || mu > curr_best
  end

  # Using each µ value, alter the consequent fuzzy set's polgyon. This is
  # called implication, and 'weights' the consequents properly. There are
  # several common ways of doing it, such as Larsen (scaling) and Mamdani
  # (clipping).
  numerator=0
  denominator=0

  @consequent_mus.each do |cons, mu|
    case @implication
    when :mamdani
      tmp = cons.mamdani(mu)
    when :larsen
      tmp = cons.larsen(mu)
    else
      raise RuntimeError, "I must have been passed an unknown implication mechanism: #{@implication}"
    end

    # Defuzzify into a discrete & usable value by adding up the weighted
    # consequents' contributions to the output. Again there are several ways
    # of doing it, such as computing the centroid of the combined 'mass', or
    # the 'mean of maximum' of the tallest set(s). Here we use the "Average
    # of Maxima" summation mechanism. MaxAv is defined as:
    # (∑ representative value * height) / (∑ height) for all output sets
    # where 'representative value' is shape-dependent.
    numerator += tmp.centroid_x * tmp.height
    denominator += tmp.height
  end

  @consequent_mus.clear

  return numerator/denominator
end