Skip to content

Commit

Permalink
feat(fuzzy): update types, update compose
Browse files Browse the repository at this point in the history
- add new LVar types
- remove combineTerms(), merge into compose()
- remove implication(), merge into compose()
- update compose() to return optimized fns
- add intersect()/union() syntax sugar
- update defuzz()
  • Loading branch information
postspectacular committed Dec 20, 2020
1 parent 8e21a7b commit 566469d
Show file tree
Hide file tree
Showing 5 changed files with 57 additions and 60 deletions.
10 changes: 7 additions & 3 deletions packages/fuzzy/src/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,11 @@ export type FuzzyFn = FnN;

export type RuleOp = (x: number, a: FuzzyFn, b: FuzzyFn) => number;

export type DefuzzStrategy = Fn2<FuzzyFn, [number, number], number>;
export type DefuzzStrategy = Fn2<FuzzyFn, LVarDomain, number>;

export type LVarDomain = [number, number];

export type LVarTerms<K extends string> = Record<K, FuzzyFn>;

export type LVarSet<I extends string> = Record<I, LVar<any>>;

Expand All @@ -30,11 +34,11 @@ export interface LVar<K extends string> {
* defined sets. However, for precision and performance reasons, it's
* recommended to keep this interval as compact as possible.
*/
domain: [number, number];
domain: LVarDomain;
/**
* Object of named fuzzy sets.
*/
terms: Record<K, FuzzyFn>;
terms: LVarTerms<K>;
}

export interface Rule<I extends LVarSet<string>, O extends LVarSet<string>> {
Expand Down
23 changes: 0 additions & 23 deletions packages/fuzzy/src/combine.ts

This file was deleted.

6 changes: 3 additions & 3 deletions packages/fuzzy/src/defuzz.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import type { IObjectOf } from "@thi.ng/api";
import type { FuzzyFn, LVarSet, Rule } from "./api";
import { cogStrategy } from "./cog";
import { compose, constant, implication, weighted } from "./shapes";
import { constant, intersect, union, weighted } from "./shapes";
import { snormMax, tnormMin } from "./tnorms";

/**
Expand Down Expand Up @@ -53,7 +53,7 @@ export const defuzz = <I extends LVarSet<string>, O extends LVarSet<string>>(
for (let id in r.then) {
if (outs[id]) {
const oterm = outs[id].terms[<string>r.then[id]];
terms[id] = implication(
terms[id] = intersect(
imply,
r.weight == 1 ? oterm : weighted(oterm, r.weight),
aterm
Expand All @@ -67,7 +67,7 @@ export const defuzz = <I extends LVarSet<string>, O extends LVarSet<string>>(
const res: Partial<Record<keyof O, number>> = {};
for (let id in outs) {
res[id] = strategy(
compose(combine, 0, ...ruleTerms.map((r) => r[id])),
union(combine, ...ruleTerms.map((r) => r[id]).filter((f) => !!f)),
outs[id].domain
);
}
Expand Down
1 change: 0 additions & 1 deletion packages/fuzzy/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
export * from "./api";
export * from "./cog";
export * from "./combine";
export * from "./defuzz";
export * from "./maxima";
export * from "./rules";
Expand Down
77 changes: 47 additions & 30 deletions packages/fuzzy/src/shapes.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { FnN2, FnU, FnU2, FnU3, FnU4, Nullable } from "@thi.ng/api";
import type { FnN2, FnU, FnU2, FnU3, FnU4 } from "@thi.ng/api";
import {
EPS,
eqDelta,
Expand All @@ -8,7 +8,6 @@ import {
sigmoid as $sigmoid,
} from "@thi.ng/math";
import type { FuzzyFn } from "./api";
import { combineTerms } from "./combine";

/**
* HOF {@link FuzzyFn} always yielding given `x` (should be in [0,1]
Expand Down Expand Up @@ -149,32 +148,10 @@ export const invAlphaCut = (fn: FuzzyFn, alpha = 0.5): FuzzyFn => (x) => {
};

/**
* Higher order function. Takes a T-norm and two {@link FuzzyFn}s. Returns new
* function which combines results of a(x) and b(x) using given T-norm
* implication.
*
* @example
* ```ts
* const f = implication(tnormMin, triangle(0,2,4), triangle(1,3,5));
* f(1); // 0
* f(2); // 0.5
* f(3); // 0.5
* f(4); // 0
* ```
*
* @param tnorm
* @param a
* @param b
*/
export const implication = (tnorm: FnN2, a: FuzzyFn, b: FuzzyFn): FuzzyFn => (
x
) => tnorm(a(x), b(x));

/**
* Complex shape generator and a more generalized version of
* {@link implication}. Takes a T-norm (or S-norm) as reduction function `op`
* and any number of {@link FuzzyFn}s. Returns new `FuzzyFn` which evaluates all
* given `fns` and combines/reduces their results with `op`.
* Higher order function, complex shape generator. Takes a T-norm (or S-norm) as
* reduction function `op` and any number of {@link FuzzyFn}s. Returns new
* `FuzzyFn` which evaluates all given `fns` and combines/reduces their results
* with `op`.
*
* @remarks
* Depending on the use case and choice of `op`, the `initial` value should
Expand All @@ -190,6 +167,15 @@ export const implication = (tnorm: FnN2, a: FuzzyFn, b: FuzzyFn): FuzzyFn => (
*
* @example
* ```ts
* const f = compose(tnormMin, 1, triangle(0,2,4), triangle(1,3,5));
* f(1); // 0
* f(2); // 0.5
* f(3); // 0.5
* f(4); // 0
* ```
*
* @example
* ```ts
* // M-like shape w/ peaks at 3 & 5
* const M = compose(
* Math.max,
Expand All @@ -210,5 +196,36 @@ export const implication = (tnorm: FnN2, a: FuzzyFn, b: FuzzyFn): FuzzyFn => (
export const compose = (
op: FnN2,
initial: number,
...fns: Nullable<FuzzyFn>[]
): FuzzyFn => (x) => combineTerms(op, fns, x, initial);
...fns: FuzzyFn[]
): FuzzyFn => {
const [a, b] = fns;
switch (fns.length) {
case 0:
throw new Error("no fuzzy sets given");
case 1:
return a;
case 2:
return (x) => op(a(x), b(x));
default:
return (x) => fns.reduce((acc, f) => op(acc, f(x)), initial);
}
};

/**
* Syntax sugar for {@link compose} with an initial value of 1.0. The `op` is
* supposed to be a T-norm.
*
* @param op
* @param fns
*/
export const intersect = (op: FnN2, ...fns: FuzzyFn[]) =>
compose(op, 1, ...fns);

/**
* Syntax sugar for {@link compose} with an initial value of 0.0. The `op` is
* supposed to be a S-norm.
*
* @param op
* @param fns
*/
export const union = (op: FnN2, ...fns: FuzzyFn[]) => compose(op, 0, ...fns);

0 comments on commit 566469d

Please sign in to comment.