Created
April 3, 2013 09:50
-
-
Save josher19/5299885 to your computer and use it in GitHub Desktop.
Ask questions about the weather using Fuzzy Logic and LiveScript
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
fuzzylogic = require 'fuzzylogic/lib/fuzzylogic' | |
temps = {"freezing": [ 'reverseGrade', 0, 5 ], "cold":["triangle", 0,15],"cool":["triangle",10,20],"roomTemp":["triangle",16,26],"warm":["triangle",21,32],"hot":["grade",27,32]} | |
temps.is = (temp, description, verbose) -> | |
[fuzfcn,...args] = this[description]; | |
fcn = fuzzylogic[fuzfcn] || fuzzylogic.triangle; | |
args.unshift(temp); | |
args=[temp,args[1],(args[1]+args[2])/2,args[2]] if args.length==3 && fcn && fcn.length == 4; | |
if verbose | |
[fcn.apply(fuzzylogic,args),fuzfcn,args, fcn == fuzzylogic.triangle] | |
else | |
fcn.apply(fuzzylogic,args) | |
temps.toF = (c) -> c * 9/5 + 32 | |
temps.toC = (f) -> (f - 32) * 5/9 | |
temps.ofList = (d) -> [["Fahrenheit", this.toF(d)]].concat([ [temp,this.is(d, temp)] if typeof this[temp] != "function" for temp of this]) | |
temps.of = (d) -> | |
res={}; | |
for own temp of this | |
res[temp] = this.is(d, temp) if typeof this[temp] != "function"; | |
res | |
very = (x) -> x*x | |
somewhat = (x) -> Math.pow(x, 0.5) | |
propositions = { very: very, somewhat: somewhat } | |
truthiness = (prop) -> | |
| prop >= 1 => "definitely" | |
| prop <= 0 => "definitely not" | |
| prop >= 0.75 => "yes" | |
| prop <= 0.25 => "no" | |
| prop >= 0.67 => "probably" | |
| prop <= 0.33 => "probably not" | |
| otherwise => "maybe" | |
temps.ask = (msg) -> msg.match(/\s*(\w+)\s+(-?\d+\.?\d*)(\s+degrees\s*)?\s*(F\s*|C\s+|celsius\s+)?(somewhat|very)?\s*(\w+)?/i) | |
answer = (msg, dom=temps) -> | |
wtype = [] | |
try [message, q, deg, degrees, ForC, prep, weather ] = dom.ask msg | |
wtype = [weather] if weather? | |
deg = dom.toC(deg) if dom.toC && ForC && ForC.charAt(0).toUpperCase() == "F" | |
prob = dom[q]?(deg, weather) | |
if prob?.shift | |
wtype = prob | |
prob = wtype.shift() | |
mod = propositions[prep] | |
prob = mod prob if typeof mod is "function" | |
[ prob, truthiness(prob) ].concat(wtype) | |
temps.highest = (choices) -> | |
max = -Infinity | |
weatherType = null | |
for own temp, deg of choices | |
if deg > max | |
max = deg | |
weatherType = temp | |
[max, weatherType] | |
temps.find = (deg, weather) -> | |
choices = this.of(deg); | |
choices[weather] or this.highest(choices); | |
# TODO: seperate domain and verbs, fuzzification | |
domain = (low, hi, desc, width) -> | |
range = hi - low; | |
width = width or (range / (desc.length-1)); | |
chunks = [['triangle', here - width, here, here + width] for here from low to hi by width]; | |
chunks[0] = ['reverseGrade', low, low + width] | |
chunks[chunks.length-1] = ['grade', hi - width, hi] | |
dom = Object.create(temps) || {}; | |
i=0; | |
for d in desc then dom[d] = chunks[i++]; | |
dom; | |
/** | |
livescript> answer "is 31 degrees hot?" | |
[ 0.7999999999999998, | |
'yes', | |
'hot' ] | |
livescript> answer "is 32 degrees hot?" | |
[ 1, 'definitely', 'hot' ] | |
livescript> answer "is 31 F hot?" | |
[ 0, 'definitely not', 'hot' ] | |
livescript> answer "is 31 F cold?" | |
[ 0, 'definitely not', 'cold' ] | |
livescript> answer "find 31 F ?" | |
[ 1, 'definitely', 'freezing' ] | |
livescript> answer "find 32?" | |
[ 1, 'definitely', 'hot' ] | |
livescript> d = domain(0,42,["freezing","cold","cool","roomTemp","warm","hot","blazing"]) | |
{ freezing: [ 'reverseGrade', 0, 7 ], | |
cold: [ 'triangle', 0, 7, 14 ], | |
cool: [ 'triangle', 7, 14, 21 ], | |
roomTemp: [ 'triangle', 14, 21, 28 ], | |
warm: [ 'triangle', 21, 28, 35 ], | |
hot: [ 'triangle', 28, 35, 42 ], | |
blazing: [ 'grade', 35, 42 ] } | |
livescript> d.is(40, "blazing") | |
0.7142857142857144 | |
livescript> answer "is 40 blazing", d | |
[ 0.7142857142857144, | |
'probably', | |
'blazing' ] | |
*/ | |
module?.exports = answer | |
answer.is = temps.is.bind(temps) | |
answer.find = temps.find.bind(temps) | |
answer.temperatures = temps | |
answer.domain = domain |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment