human-logic
Version:
326 lines • 14.7 kB
JavaScript
"use strict";
/**
* Fuzzy Common Sense Logic
*
* Human Logic (also known as “common sense”) is based on five categories:
* - `true` = certainly positive
* - `false` = certainly negative
* - `maybe` = uncertain (could be either positive or negative)
* - `never` = impossible (neither positive nor negative)
* - `undefined` = totally unknown
*
* In Fuzzy Common Sense Logic the value is five-dimensional unit vector.
* Each vector component is a fuzzy value (between 0.0 and 1.0 inclusive)
* of respective `true`, `false`, `maybe`, `never` or `undefined` category.
* @module
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.normalize = exports.or = exports.and = exports.not = exports.Logic = void 0;
var tslib_1 = require("tslib");
/** @hidden */
var Fuzzy_1 = require("./Fuzzy");
/** @hidden */
var Category_1 = require("./Category");
/**
* Main Fuzzy Common Sense Logic Class
*/
var Logic = /** @class */ (function () {
/**
* Basic constructor. See {@link fromCategory}, {@link fromArray} and {@link fromValues}
* for more convenient instantiation methods.
*/
function Logic(_undef, _false, _never, _maybe, _true) {
var _a;
this.values = (_a = {},
_a[Category_1.UNDEF] = _undef || Fuzzy_1.FUZZY_FALSE,
_a[Category_1.FALSE] = _false || Fuzzy_1.FUZZY_FALSE,
_a[Category_1.NEVER] = _never || Fuzzy_1.FUZZY_FALSE,
_a[Category_1.MAYBE] = _maybe || Fuzzy_1.FUZZY_FALSE,
_a[Category_1.TRUE] = _true || Fuzzy_1.FUZZY_FALSE,
_a);
}
/**
* Creates new {@link Logic} instance with {@link Fuzzy.FUZZY_TRUE} value for the specified `category`
* (and {@link Fuzzy.FUZZY_FALSE} for all other categories).
*/
Logic.fromCategory = function (category) {
return new Logic(category === Category_1.UNDEF ? Fuzzy_1.FUZZY_TRUE : Fuzzy_1.FUZZY_FALSE, category === Category_1.FALSE ? Fuzzy_1.FUZZY_TRUE : Fuzzy_1.FUZZY_FALSE, category === Category_1.NEVER ? Fuzzy_1.FUZZY_TRUE : Fuzzy_1.FUZZY_FALSE, category === Category_1.MAYBE ? Fuzzy_1.FUZZY_TRUE : Fuzzy_1.FUZZY_FALSE, category === Category_1.TRUE ? Fuzzy_1.FUZZY_TRUE : Fuzzy_1.FUZZY_FALSE);
};
/**
* Creates new {@link Logic} instance from array of {@link Fuzzy} values.
* @param fuzzy The categories order in array is: {@link Category.UNDEF}, {@link Category.FALSE},
* {@link Category.NEVER}, {@link Category.MAYBE}, {@link Category.TRUE}.
*/
Logic.fromArray = function (fuzzy) {
return new Logic(fuzzy[0], fuzzy[1], fuzzy[2], fuzzy[3], fuzzy[4]);
};
/**
* Creates new {@link Logic} instance from {@link LogicValues}.
*/
Logic.fromValues = function (fuzzy) {
return new Logic(fuzzy.UNDEF, fuzzy.FALSE, fuzzy.NEVER, fuzzy.MAYBE, fuzzy.TRUE);
};
/**
* Retrieves an array of {@link Fuzzy} values.
* @return The categories order in array is: {@link Category.UNDEF}, {@link Category.FALSE},
* {@link Category.NEVER}, {@link Category.MAYBE}, {@link Category.TRUE}.
*/
Logic.prototype.asArray = function () {
return [
this.values[Category_1.UNDEF],
this.values[Category_1.FALSE],
this.values[Category_1.NEVER],
this.values[Category_1.MAYBE],
this.values[Category_1.TRUE]
];
};
/**
* Dominating {@link Category} or `undefined` if none of the categories
* has a value greater than {@link Fuzzy.FUZZY_FALSE}.
*/
Logic.prototype.asCategory = function () {
var result = Category_1.UNDEF;
if (this.values[result] < this.values[Category_1.FALSE])
result = Category_1.FALSE;
if (this.values[result] < this.values[Category_1.NEVER])
result = Category_1.NEVER;
if (this.values[result] < this.values[Category_1.MAYBE])
result = Category_1.MAYBE;
if (this.values[result] < this.values[Category_1.TRUE])
result = Category_1.TRUE;
return this.values[result] > Fuzzy_1.FUZZY_FALSE ? result : undefined;
};
/**
* Retrieves a copy of {@link LogicValues}.
* @return A clone, a new instance of {@link LogicValues} created from the values kept internally.
*/
Logic.prototype.asValues = function () {
return tslib_1.__assign({}, this.values);
};
Logic.prototype.getValues = function () {
return this.values;
};
/**
* Creates a deep copy (a clone) of a current instance.
*/
Logic.prototype.clone = function () {
return new Logic(this.values[Category_1.UNDEF], this.values[Category_1.FALSE], this.values[Category_1.NEVER], this.values[Category_1.MAYBE], this.values[Category_1.TRUE]);
};
/**
* String representation of five-dimensional vector of {@link Fuzzy} values.
* The categories order is: {@link Category.UNDEF}, {@link Category.FALSE}, {@link Category.NEVER},
* {@link Category.MAYBE}, {@link Category.TRUE}.
*/
Logic.prototype.toString = function () {
return "(".concat(this.asArray()
.map(function (val) { return val.toFixed(2); })
.join(','), ")");
};
/**
* Returns {@link Fuzzy} value of the specified category of this {@link Logic} object.
*/
Logic.prototype.get = function (category) {
return this.values[category];
};
Logic.prototype.scalar = function () {
return (this.values[Category_1.UNDEF] + this.values[Category_1.FALSE] + this.values[Category_1.NEVER] + this.values[Category_1.MAYBE] + this.values[Category_1.TRUE]);
};
Logic.prototype.normalizer = function () {
return this.scalar() || Fuzzy_1.FUZZY_TRUE;
};
/**
* Returns normalized {@link Fuzzy} value for the specified category. See {@link normalize} for details.
*/
Logic.prototype.getNormalized = function (category) {
return this.values[category] / this.normalizer();
};
/**
* If original values are not normalized, returns new Logic object with normalized {@link Logic} value,
* otherwise return the same object.
*
* The {@link Logic} value is normalized if and only if the sum of {@link Fuzzy} values of all categories
* equals to `1.0` (or `0.0` if there are no categories with {@link Fuzzy} value greater than
* {@link Fuzzy.FUZZY_FALSE}).
*/
Logic.prototype.normalize = function () {
var normalizer = this.normalizer();
return Math.abs(normalizer - Fuzzy_1.FUZZY_TRUE) < 1e-8 ? this : this.multiply(Fuzzy_1.FUZZY_TRUE / normalizer);
};
/**
* Checks that at least one of the categories has non-zero {@link Fuzzy} value.
*/
Logic.prototype.isValid = function () {
return this.scalar() > Fuzzy_1.FUZZY_FALSE;
};
/**
* Fuzzy Common Sense Logical NOT. See [README](../index.html#fuzzy-common-sense-logic) for details.
*/
Logic.prototype.not = function () {
return new Logic(
// UNDEF:
this.values[Category_1.UNDEF],
// FALSE:
this.values[Category_1.TRUE],
// NEVER:
this.values[Category_1.MAYBE],
// MAYBE:
this.values[Category_1.NEVER],
// TRUE:
this.values[Category_1.FALSE]);
};
/**
* Fuzzy Common Sense Logical AND. See [README](../index.html#fuzzy-common-sense-logic) for details.
*/
Logic.prototype.and = function (value) {
if (!value || !(value instanceof Logic))
throw new TypeError('Invalid argument type');
var values = value.getValues();
var undef = (0, Fuzzy_1.or)(this.values[Category_1.UNDEF], values[Category_1.UNDEF]);
var notUndef = (0, Fuzzy_1.not)(undef);
return new Logic(
// UNDEF:
undef,
// FALSE:
(0, Fuzzy_1.and)(notUndef, (0, Fuzzy_1.or)(this.values[Category_1.FALSE], values[Category_1.FALSE], (0, Fuzzy_1.and)(this.values[Category_1.MAYBE], values[Category_1.NEVER]), (0, Fuzzy_1.and)(this.values[Category_1.NEVER], values[Category_1.MAYBE]))),
// NEVER:
(0, Fuzzy_1.and)(notUndef, (0, Fuzzy_1.or)((0, Fuzzy_1.and)(this.values[Category_1.NEVER], values[Category_1.NEVER]), (0, Fuzzy_1.and)(this.values[Category_1.NEVER], values[Category_1.TRUE]), (0, Fuzzy_1.and)(this.values[Category_1.TRUE], values[Category_1.NEVER]))),
// MAYBE:
(0, Fuzzy_1.and)(notUndef, (0, Fuzzy_1.or)((0, Fuzzy_1.and)(this.values[Category_1.MAYBE], values[Category_1.MAYBE]), (0, Fuzzy_1.and)(this.values[Category_1.MAYBE], values[Category_1.TRUE]), (0, Fuzzy_1.and)(this.values[Category_1.TRUE], values[Category_1.MAYBE]))),
// TRUE:
(0, Fuzzy_1.and)(notUndef, this.values[Category_1.TRUE], values[Category_1.TRUE])).normalize();
};
/**
* Fuzzy Common Sense Logical OR. See [README](../index.html#fuzzy-common-sense-logic) for details.
*/
Logic.prototype.or = function (value) {
if (!value || !(value instanceof Logic))
throw new TypeError('Invalid argument type');
var values = value.getValues();
var undef = (0, Fuzzy_1.or)(this.values[Category_1.UNDEF], values[Category_1.UNDEF]);
var notUndef = (0, Fuzzy_1.not)(undef);
return new Logic(
// UNDEF:
undef,
// FALSE:
(0, Fuzzy_1.and)(notUndef, this.values[Category_1.FALSE], values[Category_1.FALSE]),
// NEVER:
(0, Fuzzy_1.and)(notUndef, (0, Fuzzy_1.or)((0, Fuzzy_1.and)(this.values[Category_1.NEVER], values[Category_1.NEVER]), (0, Fuzzy_1.and)(this.values[Category_1.NEVER], values[Category_1.FALSE]), (0, Fuzzy_1.and)(this.values[Category_1.FALSE], values[Category_1.NEVER]))),
// MAYBE:
(0, Fuzzy_1.and)(notUndef, (0, Fuzzy_1.or)((0, Fuzzy_1.and)(this.values[Category_1.MAYBE], values[Category_1.MAYBE]), (0, Fuzzy_1.and)(this.values[Category_1.MAYBE], values[Category_1.FALSE]), (0, Fuzzy_1.and)(this.values[Category_1.FALSE], values[Category_1.MAYBE]))),
// TRUE:
(0, Fuzzy_1.and)(notUndef, (0, Fuzzy_1.or)(this.values[Category_1.TRUE], values[Category_1.TRUE], (0, Fuzzy_1.and)(this.values[Category_1.MAYBE], values[Category_1.NEVER]), (0, Fuzzy_1.and)(this.values[Category_1.NEVER], values[Category_1.MAYBE])))).normalize();
};
/**
* Adds `value` to current value (category by category).
* Useful for accumulation of fuzzy sums (usually with normalization in the end).
* Mutates the current object.
* @return Mutated `this` object.
*/
Logic.prototype.add = function (value) {
if (!value || !(value instanceof Logic))
throw new TypeError('Invalid argument type');
var values = value.getValues();
this.values[Category_1.UNDEF] += values[Category_1.UNDEF];
this.values[Category_1.FALSE] += values[Category_1.FALSE];
this.values[Category_1.NEVER] += values[Category_1.NEVER];
this.values[Category_1.MAYBE] += values[Category_1.MAYBE];
this.values[Category_1.TRUE] += values[Category_1.TRUE];
return this;
};
Logic.prototype.multiply = function (value) {
return new Logic(
// UNDEF:
this.values[Category_1.UNDEF] * value,
// FALSE:
this.values[Category_1.FALSE] * value,
// NEVER:
this.values[Category_1.NEVER] * value,
// MAYBE:
this.values[Category_1.MAYBE] * value,
// TRUE:
this.values[Category_1.TRUE] * value);
};
/**
* Returns `true` if `category` is the dominating category of this object.
*/
Logic.prototype.eq = function (category) {
return ((category === Category_1.UNDEF || this.values[category] > this.values[Category_1.UNDEF]) &&
(category === Category_1.FALSE || this.values[category] > this.values[Category_1.FALSE]) &&
(category === Category_1.NEVER || this.values[category] > this.values[Category_1.NEVER]) &&
(category === Category_1.MAYBE || this.values[category] > this.values[Category_1.MAYBE]) &&
(category === Category_1.TRUE || this.values[category] > this.values[Category_1.TRUE]));
};
/**
* Returns `true` if `category` is **not** the dominating category of this object.
*/
Logic.prototype.ne = function (category) {
return ((category !== Category_1.UNDEF && this.values[category] <= this.values[Category_1.UNDEF]) ||
(category !== Category_1.FALSE && this.values[category] <= this.values[Category_1.FALSE]) ||
(category !== Category_1.NEVER && this.values[category] <= this.values[Category_1.NEVER]) ||
(category !== Category_1.MAYBE && this.values[category] <= this.values[Category_1.MAYBE]) ||
(category !== Category_1.TRUE && this.values[category] <= this.values[Category_1.TRUE]));
};
return Logic;
}());
exports.Logic = Logic;
/**
* Fuzzy Common Sense NOT (global function).
* Allows to use different code styles, e.g.:
* ```JavaScript
* const valueA = value.not();
* const valueB = not(value);
* ```
* See [README](../index.html#fuzzy-common-sense-logic) for details.
*/
function not(value) {
if (value && value instanceof Logic)
return value.not();
throw new TypeError('Invalid argument type');
}
exports.not = not;
/**
* Fuzzy Common Sense AND (global function).
* Allows to use different code styles, e.g.:
* ```JavaScript
* const valueA = value1.and(value2);
* const valueB = and(value1, value2);
* ```
* See [README](../index.html#fuzzy-common-sense-logic) for details.
*/
function and(a, b) {
if (a && a instanceof Logic)
return a.and(b);
throw new TypeError('Invalid argument type');
}
exports.and = and;
/**
* Fuzzy Common Sense OR (global function).
* Allows to use different code styles, e.g.:
* ```JavaScript
* const valueA = value1.or(value2);
* const valueB = or(value1, value2);
* ```
* See [README](../index.html#fuzzy-common-sense-logic) for details.
*/
function or(a, b) {
if (a && a instanceof Logic)
return a.or(b);
throw new TypeError('Invalid argument type');
}
exports.or = or;
/**
* Fuzzy Common Sense logical value normalization (global function).
* Allows to use different code styles, e.g.:
* ```JavaScript
* const valueA = value.normalize();
* const valueB = normalize(value);
* ```
* See {@link Logic.normalize} for details.
*/
function normalize(value) {
if (value && value instanceof Logic)
return value.normalize();
throw new TypeError('Invalid argument type');
}
exports.normalize = normalize;
//# sourceMappingURL=Logic.js.map