Module: FuzzyRealty

Defined in:
lib/fuzzy_realty.rb,
lib/classes.rb,
lib/weights.rb,
lib/rulebase.rb,
lib/scores_table.rb

Overview

If set this flag will turn on debugging printouts $debug = true;

Defined Under Namespace

Classes: ExpertSystem, Listing, Parameter, Query

Constant Summary collapse

WEIGHTS =

class Parameter uses this hash to determine what is a valid type.

  • This must be matched by a rule in rulebase.rb

{
  :sqft => 15, 
  :price => 10, 
  :location => 25,
  :style => 18
}
RULES =
lambda do
  rules = {
    # Not yet implemented
    #:bathrooms => ,
    #:bedrooms => ,
    #:garage => ,
    #:deck => ,
  
    # Price is match when desired is 90-105%  of actual. Otherwise give a
    # reduced factor.
    :price => 
      lambda do |listing,desired| 
        puts "Called price" if $debug
        actual = listing.price.to_f
        result = if (desired*0.90..desired*1.05) === actual
          1.0
        else 
          1 - ((desired - actual) / actual).abs
        end
        puts result if $debug
        result
      end,

    # Location calc. does lookup to find score for desired and actual
    ## Currently just return 1 if exact, 0 otherwise
    :location => 
      lambda do |listing,desired|
        puts "Called location" if $debug
        # Perform a quick lookup (i.e. FuzzyRealty::LOCN[:A][:A] => 1.0)
        puts FuzzyRealty::LOCN[desired.to_sym][listing.location.to_sym] if $debug
        FuzzyRealty::LOCN[desired.to_sym][listing.location.to_sym]
      end,
    
    :sqft => 
      lambda do |listing,desired|
                puts "Called sqft" if $debug
        actual = listing.sqft
        result = if (actual + 50) >= desired
          1.0
        elsif (actual + 150) >= desired
          0.8
        elsif (actual + 300) >= desired
          0.5
        else
          0.0
        end
        puts result if $debug
        result
      end,
    # Style's follow lookup table similar to Location

    :style => 
      lambda do |listing,desired|
                puts "Called style" if $debug
        desired = FuzzyRealty::STYLE[:Symbol][desired]
        actual  = FuzzyRealty::STYLE[:Symbol][listing.style]
        puts FuzzyRealty::STYLE[desired][actual] if $debug
        FuzzyRealty::STYLE[desired][actual]
      end
  }
  rules.default = lambda {|a,b| raise "Invalid type used in rule lookup"}
  rules
end.call
LOCN =

Table for looking up score of relative locations

A is a high-class suburb B is a middle-class area C is an older middle-class area D is a “ghetto”

A    B      C   D

A 1.0 0.75 0.2 0.0 B 0.75 1.00 0.4 0.1 C 0.2 0.4 1.0 0.6 D 0.0 0.1 0.6 1.0

Hash.new(0).merge({
  :A => {:A => 1.0,  :B => 0.75, :C => 0.2, :D => 0.0}, 
  :B => {:A => 0.75, :B => 1.0,  :C => 0.4, :D => 0.1},
  :C => {:A => 0.2,  :B => 0.4,  :C => 1.0, :D => 0.6},
  :D => {:A => 0.0,  :B => 0.1,  :C => 0.6, :D => 1.0}
})
STYLE =

Table for lookup of score of desired and actual styles

  • Arbitrary values provied by my wife, at present the leanings aren’t quite right

Bu = Bungalow, Bi = Bilevel, Sp = Splitlevel, Tw = Two Story, Co = Condo | | Bu | Sp | Tw | Bi | Co | | Bu | 1 | 0.4 | 0.8 | 0.65 | 0.1 | | Sp | 0.5 | 1 | 0.7 | 0.95 | 0.2 | | Tw | 0.0 | 0.6 | 1 | 0.5 | 0.0 | | Bi | 0.75 | 0.6 | 0.8 | 1 | 0.0 | | Co | 0.7 | 0.0 | 0.0 | 0.0 | 1 |

Hash.new(0).merge({
  :Symbol => {"Bungalow" => :Bu, "Bi-level" => :Bi, "Split-level" => :Sp,
              "Two-story" => :Tw, "Condominium" => :Co},
  :Bu => { :Bu => 1,   :Sp => 0.4, :Tw => 0.8, :Bi => 0.65, :Co => 0.1 },
  :Sp => { :Bu => 0.5, :Sp => 1.0, :Tw => 0.7, :Bi => 0.95, :Co => 0.2 },
  :Tw => { :Bu => 0.0, :Sp => 0.6, :Tw => 1.0, :Bi => 0.5,  :Co => 0.0 },
  :Bi => { :Bu => 0.75,:Sp => 0.6, :Tw => 0.8, :Bi => 1.0,  :Co => 0.0 },
  :Co => { :Bu => 0.7, :Sp => 0.0, :Tw => 0.0, :Bi => 0.0,  :Co => 1.0 }
})

Class Method Summary collapse

Class Method Details

.max_scoreObject

Easy way to sum the max score (for testing)



17
18
19
# File 'lib/weights.rb', line 17

def self.max_score
  WEIGHTS.inject(0) {|sum,n| sum + n[1]}
end