Skip to content

Latest commit

 

History

History
377 lines (303 loc) · 15.5 KB

README.md

File metadata and controls

377 lines (303 loc) · 15.5 KB

@thi.ng/fuzzy

npm version npm downloads Mastodon Follow

Note

This is one of 199 standalone projects, maintained as part of the @thi.ng/umbrella monorepo and anti-framework.

🚀 Please help me to work full-time on these projects by sponsoring me on GitHub. Thank you! ❤️

About

Fuzzy logic operators & configurable rule inferencing engine.

Features

  • Entirely declarative & functional approach
  • Fully type checked
  • Fuzzy set domain shaping & composition functions (incl. negated / inverse)
  • Various T-norms & S-norms, incl. parametric versions
  • Rules with multiple inputs/outputs and arbitrary term combinators (i.e. T-norms). Syntax sugar for common and/or rules.
  • Defuzzification via customizable strategies and options to balance precision vs. performance
    • Maxima: First, Last, Mean
    • Center-of-Gravity (COG)
  • Linguistic variable creation and term/set classification for given domain values
  • Fuzzy set visualization (via @thi.ng/fuzzy-viz)

References / Further reading

Status

STABLE - used in production

Search or submit any issues for this package

Support packages

Installation

yarn add @thi.ng/fuzzy

ESM import:

import * as fuzzy from "@thi.ng/fuzzy";

Browser ESM import:

<script type="module" src="https://esm.run/@thi.ng/fuzzy"></script>

JSDelivr documentation

For Node.js REPL:

const fuzzy = await import("@thi.ng/fuzzy");

Package sizes (brotli'd, pre-treeshake): ESM: 1.62 KB

Dependencies

Note: @thi.ng/api is in most cases a type-only import (not used at runtime)

API

Generated API docs

(See tests for more usage examples).

Fuzzy set generators & combinators

Generators:

  • constant()
  • point()
  • ramp() / invRamp()
  • triangle()
  • trapezoid()
  • sigmoid() / invSigmoid()
  • gaussian()

Combinators:

  • negate()
  • weighted()
  • alphaCut() / invAlphaCut()
  • compose() / intersect() / union()

Linguistic variables

Linguistic variables (short: L-vars) are groupings of named (and possibly overlapping) fuzzy sets within a given value domain. The can be used standalone or as inputs/outputs in rules (further below).

The @thi.ng/fuzzy-viz package provides utilities to visualize the fuzzy sets of an L-var.

fuzzy set visualization of the example l-var

import {
    variable, invSigmoid, sigmoid, trapezoid,
    evaluate, classify
} from "@thi.ng/fuzzy";

// temperature sets (in celsius)
const temp = variable(
  // value domain
  [-20, 40],
  {
    freezing: invSigmoid(0, 2),
    cold: trapezoid(-1, 2, 16, 20),
    warm: trapezoid(15, 20, 30, 34),
    hot: sigmoid(32, 2)
  }
);

// evaluate all fuzzy sets for given domain value
evaluate(temp, 18)
// {
//   freezing: 2.220446049250313e-16,
//   cold: 0.5,
//   warm: 0.6,
//   hot: 6.914400106935423e-13
// }

evaluate(temp, 28)
// {
//   freezing: 0,
//   cold: 0,
//   warm: 1,
//   hot: 0.0003353501304664781
// }

// classify temperature (min confidence 33%, default: 50%)
classify(temp, 28, 0.33)
// "warm"

Rule creation & inferencing

Example taken from Franck Dernoncourt's Introduction to Fuzzy Logic:

fuzzy set illustration from F.Dernoncourt's tutorial

import {
    variable, ramp, invRamp, gaussian, triangle,
    or, defuzz, meanOfMaximaStrategy
} from "@thi.ng/fuzzy";

// define fuzzy input variables
const inputs = {
  food: variable([0, 10], {
    awful: invRamp(1, 3),
    delicious: ramp(7, 9),
  }),
  service: variable([0, 10], {
    poor: gaussian(0, 1.5),
    good: gaussian(5, 1.5),
    excellent: gaussian(10, 1.5),
  }),
};

const outputs = {
  tip: variable([0, 30], {
    low: triangle(0, 5, 10),
    medium: triangle(10, 15, 20),
    high: triangle(20, 25, 30),
  }),
};

// l-vars, rules and defuzzification are using generics for type safety
// we define these 2 type aliases for brevity
type I = typeof inputs;
type O = typeof outputs;

// rule definitions:
// if service is poor OR food is awful -> tip is low
// if service is normal -> tip is medium
// if service is excellent OR food is delicious -> tip is high
const rules = [
  or<I, O>({ food: "awful", service: "poor" }, { tip: "low" }),
  or<I, O>({ service: "good" }, { tip: "medium" }),
  or<I, O>({ food: "delicious", service: "excellent" }, { tip: "high" }),
];

// defuzzification using default center-of-gravity strategy
defuzz(
  inputs,
  outputs,
  rules,
  // input values
  { food: 7.32, service: 7.83 },
);
// { tip: 22.650000000000034 }

// defuzz with custom strategy (note: each has further config options)
defuzz(
  inputs,
  outputs,
  rules,
  // input values
  { food: 7.32, service: 7.83 },
  // custom defuzz strategy
  meanOfMaximaStrategy()
);
// { tip: 25.050000000000043 }

Note: The results are slightly different than those in the textbook example, due to different gaussian fuzzy sets used for the service L-var.

Using instrumentStrategy() from the upcoming @thi.ng/fuzzy-viz package, we can also visualize the final, transformed fuzzy sets used to compute crisp results and highlight the position of the crisp result value.

Here is the ASCII art output for the centroidStrategy and using tnormMin (the default) to transform each rule's output set(s):

import { defuzz, centroidStrategy } from "@thi.ng/fuzzy";
import { instrumentStrategy, fuzzySetToAscii } from "@thi.ng/fuzzy-viz";

// wrap existing strategy
const strat = instrumentStrategy(centroidStrategy(), fuzzySetToAscii());

// call defuzz as normal
defuzz(inputs, outputs, rules, strat);

// obtain secondary results via deref()
console.log(strat.deref()[0]);
........................................................................|...........................
........................................................................|...........................
........................................................................|...........................
........................................................................|...........................
........................................................................|...........................
........................................................................|...........................
........................................................................|...........................
........................................................................|...........................
........................................................................|...........................
........................................................................|...........................
........................................................................|▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅▅.....
.......................................................................▁|██████████████████████▇....
......................................................................▁█|███████████████████████▇...
....................................▅▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▅....▂██|████████████████████████▇..
...................................▅█████████████████████████████▅..▂███|██████████████████████████.
..................................▅███████████████████████████████▅▂████|███████████████████████████
                                                                        ^ 21.52

Different results can be obtained by adjusting the T-norm used to transform each rule's output sets, here using tnormHamacher(2).

.........................................................................|..........................
.........................................................................|..........................
.........................................................................|..........................
.........................................................................|..........................
.........................................................................|..........................
.........................................................................|..........................
.........................................................................|..........................
.........................................................................|..........................
.........................................................................|..........................
.........................................................................|..........................
.........................................................................|.........▃▂...............
.........................................................................|.......▃███▆▂.............
.........................................................................|....▁▅███████▇▃...........
................................................▁▃▆▃▁....................|.▁▄▇████████████▆▃........
...........................................▁▂▄▆███████▆▄▂▁..............▂|▇██████████████████▆▃▁....
...................................▁▂▃▄▅▆▇█████████████████▇▆▅▄▃▂▁..▂▄▆██|███████████████████████▅▃▁
                                                                         ^ 21.84

...or using tnormAczelAlsina(2) (there're many more available):

........................................................................|...........................
........................................................................|...........................
........................................................................|...........................
........................................................................|...........................
........................................................................|...........................
........................................................................|...........................
........................................................................|...........................
........................................................................|...........................
........................................................................|...........................
........................................................................|...........................
........................................................................|.....▂▃▄▅▅▅▅▅▄▄▃▁..........
........................................................................|.▂▅▇██████████████▆▄.......
........................................................................|▇████████████████████▆▂....
........................................▁▂▃▄▄▅▅▆▆▆▆▆▆▆▅▅▄▄▃▂▁.........▃█|███████████████████████▆▁..
....................................▂▄▇███████████████████████▇▄▂....▆██|█████████████████████████▄.
..................................▃▇█████████████████████████████▇▃▂████|██████████████████████████▇
                                                                        ^ 21.58

Just for illustration purposes (and using a different example), SVG output can be obtained by merely switching to another instrumentation function (here fuzzySetToSvg()):

fuzzySetToSvg() visualization example

Authors

If this project contributes to an academic publication, please cite it as:

@misc{thing-fuzzy,
  title = "@thi.ng/fuzzy",
  author = "Karsten Schmidt",
  note = "https://thi.ng/fuzzy",
  year = 2020
}

License

© 2020 - 2024 Karsten Schmidt // Apache License 2.0