Skip to content

Instantly share code, notes, and snippets.

@josher19
Last active January 3, 2016 20:19
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save josher19/8514536 to your computer and use it in GitHub Desktop.
Save josher19/8514536 to your computer and use it in GitHub Desktop.
Weather classification module using Fuzzy Logic. Default is Celsius. Ask whether the weather is very or somewhat hot, warm, cool, cold, or freezing.

Weather classification module using Fuzzy Logic. Default is Celsius.

npm install fuzzylogic node

> weather = require('./weather')
> weather("is 30 very hot?")
[0.36, 'maybe', 'hot']  # 36% correct -- maybe 30C is very hot
> weather("is 30 somewhat hot?")
[0.7746, 'yes', 'hot']  # 77.46% correct -- yes 30C is somewhat hot
> weather("is 30F very hot?")
[0, 'definitely not', 'hot'] # 0% correct -- 30F is definitely not hot
(function(){
var fuzzylogic, temps, very, somewhat, propositions, truthiness, answer, domain, slice$ = [].slice;
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 = function(temp, description, verbose){
var ref$, fuzfcn, args, fcn;
ref$ = this[description], fuzfcn = ref$[0], args = slice$.call(ref$, 1);
fcn = fuzzylogic[fuzfcn] || fuzzylogic.triangle;
args.unshift(temp);
if (args.length === 3 && fcn && fcn.length === 4) {
args = [temp, args[1], (args[1] + args[2]) / 2, args[2]];
}
if (verbose) {
return [fcn.apply(fuzzylogic, args), fuzfcn, args, fcn === fuzzylogic.triangle];
} else {
return fcn.apply(fuzzylogic, args);
}
};
temps.toF = function(c){
return c * 9 / 5 + 32;
};
temps.toC = function(f){
return (f - 32) * 5 / 9;
};
temps.ofList = function(d){
var temp;
return [["Fahrenheit", this.toF(d)]].concat((function(){
var results$ = [];
for (temp in this) {
if (typeof this[temp] !== "function") {
results$.push([temp, this.is(d, temp)]);
}
}
return results$;
}.call(this)));
};
temps.of = function(d){
var res, temp, own$ = {}.hasOwnProperty;
res = {};
for (temp in this) if (own$.call(this, temp)) {
if (typeof this[temp] !== "function") {
res[temp] = this.is(d, temp);
}
}
return res;
};
very = function(x){
return x * x;
};
somewhat = function(x){
return Math.pow(x, 0.5);
};
propositions = {
very: very,
somewhat: somewhat
};
truthiness = function(prop){
switch (false) {
case !(prop >= 1):
return "definitely";
case !(prop <= 0):
return "definitely not";
case !(prop >= 0.75):
return "yes";
case !(prop <= 0.25):
return "no";
case !(prop >= 0.67):
return "probably";
case !(prop <= 0.33):
return "probably not";
default:
return "maybe";
}
};
temps.ask = function(msg){
return msg.match(/\s*(\w+)\s+(-?\d+\.?\d*)(\s+degrees\s*)?\s*(F\s*|C\s+|celsius\s+)?(somewhat|very)?\s*(\w+)?/i);
};
answer = function(msg, dom){
var wtype, ref$, message, q, deg, degrees, ForC, prep, weather, prob, mod;
dom == null && (dom = temps);
wtype = [];
try {
ref$ = dom.ask(msg), message = ref$[0], q = ref$[1], deg = ref$[2], degrees = ref$[3], ForC = ref$[4], prep = ref$[5], weather = ref$[6];
} catch (e$) {}
if (weather != null) {
wtype = [weather];
}
if (dom.toC && ForC && ForC.charAt(0).toUpperCase() === "F") {
deg = dom.toC(deg);
}
prob = typeof dom[q] === 'function' ? dom[q](deg, weather) : void 8;
if (prob != null && prob.shift) {
wtype = prob;
prob = wtype.shift();
}
mod = propositions[prep];
if (typeof mod === "function") {
prob = mod(prob);
}
return [prob, truthiness(prob)].concat(wtype);
};
temps.highest = function(choices){
var max, weatherType, temp, deg, own$ = {}.hasOwnProperty;
max = -Infinity;
weatherType = null;
for (temp in choices) if (own$.call(choices, temp)) {
deg = choices[temp];
if (deg > max) {
max = deg;
weatherType = temp;
}
}
return [max, weatherType];
};
temps.find = function(deg, weather){
var choices;
choices = this.of(deg);
return choices[weather] || this.highest(choices);
};
domain = function(low, hi, desc, width){
var range, res$, here, chunks, dom, i, i$, len$, d;
range = hi - low;
width = width || range / (desc.length - 1);
res$ = [];
for (here = low; width < 0 ? here >= hi : here <= hi; here += width) {
res$.push(['triangle', here - width, here, here + width]);
}
chunks = res$;
chunks[0] = ['reverseGrade', low, low + width];
chunks[chunks.length - 1] = ['grade', hi - width, hi];
dom = Object.create(temps) || {};
i = 0;
for (i$ = 0, len$ = desc.length; i$ < len$; ++i$) {
d = desc[i$];
dom[d] = chunks[i++];
}
return 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' ]
*/
if (typeof module != 'undefined' && module !== null) {
module.exports = answer;
}
answer.is = temps.is.bind(temps);
answer.find = temps.find.bind(temps);
answer.temperatures = temps;
answer.domain = domain;
}).call(this);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment