UNPKG

@eagleoutice/flowr-dev

Version:

Static Dataflow Analyzer and Program Slicer for the R Programming Language

232 lines 8.79 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.IntervalDomain = exports.IntervalTop = void 0; const assert_1 = require("../../util/assert"); const logic_1 = require("../../util/logic"); const abstract_domain_1 = require("./abstract-domain"); const lattice_1 = require("./lattice"); const value_abstract_domain_1 = require("./value-abstract-domain"); /** The Top element of the interval domain as interval [-∞, +∞] */ exports.IntervalTop = [-Infinity, +Infinity]; /** * The interval abstract domain as intervals with possibly infinite bounds representing possible numeric values. * The Bottom element is defined as {@link Bottom} symbol and the Top element is defined as the interval [-∞, +∞]. * @template Value - Type of the constraint in the abstract domain (Top, Bottom, or an actual value) */ class IntervalDomain extends abstract_domain_1.AbstractDomain { constructor(value) { if (Array.isArray(value)) { if (value.some(Number.isNaN) || value[0] > value[1] || value[0] === +Infinity || value[1] === -Infinity) { super(lattice_1.Bottom); } else { super([value[0], value[1]]); } } else { super(value); } } create(value) { return new IntervalDomain(value); } get lower() { return (this.isValue() ? this.value[0] : lattice_1.Bottom); } get upper() { return (this.isValue() ? this.value[1] : lattice_1.Bottom); } from(...values) { if (values.length === 0) { return this.bottom(); } return this.create([Math.min(...values), Math.max(...values)]); } static top() { return new this(exports.IntervalTop); } static bottom() { return new this(lattice_1.Bottom); } static from(...values) { if (values.length === 0) { return this.bottom(); } return new this([Math.min(...values), Math.max(...values)]); } top() { return this.create(exports.IntervalTop); } bottom() { return this.create(lattice_1.Bottom); } equalsValue(other) { return this.lower === other.lower && this.upper === other.upper; } leqValue(other) { return other.lower <= this.lower && this.upper <= other.upper; } joinValue(other) { return this.create([Math.min(this.lower, other.lower), Math.max(this.upper, other.upper)]); } meetValue(other) { return this.create([Math.max(this.lower, other.lower), Math.min(this.upper, other.upper)]); } widenValue(other) { return this.create([ this.lower <= other.lower ? this.lower : -Infinity, this.upper >= other.upper ? this.upper : +Infinity ]); } narrowValue(other) { if (Math.max(this.lower, other.lower) > Math.min(this.upper, other.upper)) { return this.bottom(); } return this.create([ this.lower === -Infinity ? other.lower : this.lower, this.upper === +Infinity ? other.upper : this.upper ]); } satisfies(value, comparator = value_abstract_domain_1.NumericalComparator.Equal) { switch (comparator) { case value_abstract_domain_1.NumericalComparator.Equal: { if (this.isValue() && this.lower <= value && value <= this.upper) { return this.lower === this.upper ? logic_1.Ternary.Always : logic_1.Ternary.Maybe; } else { return logic_1.Ternary.Never; } } case value_abstract_domain_1.NumericalComparator.Less: { if (this.isValue() && value < this.upper) { return value < this.lower ? logic_1.Ternary.Always : logic_1.Ternary.Maybe; } else { return logic_1.Ternary.Never; } } case value_abstract_domain_1.NumericalComparator.LessOrEqual: { if (this.isValue() && value <= this.upper) { return value <= this.lower ? logic_1.Ternary.Always : logic_1.Ternary.Maybe; } else { return logic_1.Ternary.Never; } } case value_abstract_domain_1.NumericalComparator.Greater: { if (this.isValue() && this.lower <= value) { return this.upper <= value ? logic_1.Ternary.Always : logic_1.Ternary.Maybe; } else { return logic_1.Ternary.Never; } } case value_abstract_domain_1.NumericalComparator.GreaterOrEqual: { if (this.isValue() && this.lower < value) { return this.upper < value ? logic_1.Ternary.Always : logic_1.Ternary.Maybe; } else { return logic_1.Ternary.Never; } } default: { (0, assert_1.assertUnreachable)(comparator); } } } negate() { if (this.isValue()) { return this.create([-this.value[1], -this.value[0]]); } return this.bottom(); } add(other) { const otherValue = other instanceof abstract_domain_1.AbstractDomain ? other.value : other; if (this.isValue() && otherValue !== lattice_1.Bottom) { return this.create([this.lower + otherValue[0], this.upper + otherValue[1]]); } return this.bottom(); } subtract(other) { const otherValue = other instanceof abstract_domain_1.AbstractDomain ? other.value : other; if (this.isValue() && otherValue !== lattice_1.Bottom) { return this.create([this.lower - otherValue[0], this.upper - otherValue[1]]); } return this.bottom(); } multiply(other) { const otherValue = other instanceof abstract_domain_1.AbstractDomain ? other.value : other; if (this.isValue() && otherValue !== lattice_1.Bottom) { const products = [ this.value[0] * otherValue[0], this.value[0] * otherValue[1], this.value[1] * otherValue[0], this.value[1] * otherValue[1] ]; return this.create([Math.min(...products), Math.max(...products)]); } return this.bottom(); } divide(other) { const otherValue = other instanceof abstract_domain_1.AbstractDomain ? other.value : other; if (this.isValue() && otherValue !== lattice_1.Bottom) { if (otherValue[0] <= 0 && 0 <= otherValue[1]) { return this.top(); } return this.multiply(this.create([1 / otherValue[1], 1 / otherValue[0]])); } return this.bottom(); } min(other) { const otherValue = other instanceof abstract_domain_1.AbstractDomain ? other.value : other; if (this.isValue() && otherValue !== lattice_1.Bottom) { return this.create([Math.min(this.lower, otherValue[0]), Math.min(this.upper, otherValue[1])]); } return this.bottom(); } max(other) { const otherValue = other instanceof abstract_domain_1.AbstractDomain ? other.value : other; if (this.isValue() && otherValue !== lattice_1.Bottom) { return this.create([Math.max(this.lower, otherValue[0]), Math.max(this.upper, otherValue[1])]); } return this.bottom(); } /** * Extends the lower bound of the current abstract value down to -∞. */ widenDown() { if (this.isValue()) { return this.create([-Infinity, this.upper]); } return this.bottom(); } /** * Extends the upper bound of the current abstract value up to +∞. */ widenUp() { if (this.isValue()) { return this.create([this.lower, +Infinity]); } return this.bottom(); } jsonify() { return this.value; } stringify() { return `[${Number.isFinite(this.lower) ? this.lower : '-∞'}, ${Number.isFinite(this.upper) ? this.upper : '+∞'}]`; } isTop() { return this.value !== lattice_1.Bottom && this.lower === -Infinity && this.upper === +Infinity; } isBottom() { return this.value === lattice_1.Bottom; } isValue() { return this.value !== lattice_1.Bottom; } isFinite() { return this.isValue() && Number.isFinite(this.lower) && Number.isFinite(this.upper); } } exports.IntervalDomain = IntervalDomain; //# sourceMappingURL=interval-domain.js.map