UNPKG

@eagleoutice/flowr

Version:

Static Dataflow Analyzer and Program Slicer for the R Programming Language

208 lines 7.54 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.IntervalDomain = void 0; const abstract_domain_1 = require("./abstract-domain"); const lattice_1 = require("./lattice"); /** * 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 { _value; constructor(value) { if (Array.isArray(value)) { if (value.some(isNaN) || value[0] > value[1] || value[0] === +Infinity || value[1] === -Infinity) { this._value = lattice_1.Bottom; } else { this._value = [value[0], value[1]]; } } else { this._value = value; } } get value() { return this._value; } static top() { return new IntervalDomain([-Infinity, +Infinity]); } static bottom() { return new IntervalDomain(lattice_1.Bottom); } static abstract(concrete) { if (concrete === lattice_1.Top) { return IntervalDomain.top(); } else if (concrete.size === 0 || concrete.values().some(isNaN)) { return IntervalDomain.bottom(); } return new IntervalDomain([Math.min(...concrete), Math.max(...concrete)]); } top() { return IntervalDomain.top(); } bottom() { return IntervalDomain.bottom(); } equals(other) { return this.value === other.value || (this.isValue() && other.isValue() && this.value[0] === other.value[0] && this.value[1] === other.value[1]); } leq(other) { return this.value === lattice_1.Bottom || (other.isValue() && other.value[0] <= this.value[0] && this.value[1] <= other.value[1]); } join(...values) { const result = new IntervalDomain(this.value); for (const other of values) { if (result.value === lattice_1.Bottom) { result._value = other.value; } else if (other.value === lattice_1.Bottom) { result._value = result.value; } else { result._value = [Math.min(result.value[0], other.value[0]), Math.max(result.value[1], other.value[1])]; } } return result; } meet(...values) { const result = new IntervalDomain(this.value); for (const other of values) { if (this.value === lattice_1.Bottom || other.value === lattice_1.Bottom) { result._value = lattice_1.Bottom; } else if (Math.max(this.value[0], other.value[0]) > Math.min(this.value[1], other.value[1])) { result._value = lattice_1.Bottom; } else { result._value = [Math.max(this.value[0], other.value[0]), Math.min(this.value[1], other.value[1])]; } } return result; } widen(other) { if (this.value === lattice_1.Bottom) { return new IntervalDomain(other.value); } else if (other.value === lattice_1.Bottom) { return new IntervalDomain(this.value); } else { return new IntervalDomain([ this.value[0] <= other.value[0] ? this.value[0] : -Infinity, this.value[1] >= other.value[1] ? this.value[1] : +Infinity ]); } } narrow(other) { if (this.value === lattice_1.Bottom || other.value === lattice_1.Bottom) { return this.bottom(); } return new IntervalDomain([ this.value[0] === -Infinity ? other.value[0] : this.value[0], this.value[1] === +Infinity ? other.value[1] : this.value[1] ]); } concretize(limit = abstract_domain_1.DEFAULT_INFERENCE_LIMIT) { if (this.value === lattice_1.Bottom) { return new Set(); } else if (!isFinite(this.value[0]) || !isFinite(this.value[1]) || this.value[1] - this.value[0] + 1 > limit) { return lattice_1.Top; } const set = new Set(); for (let x = this.value[0]; x <= this.value[1]; x++) { set.add(x); } return set; } abstract(concrete) { return IntervalDomain.abstract(concrete); } /** * Adds another abstract value to the current abstract value by adding the two lower and upper bounds, respectively. */ add(other) { if (this.value === lattice_1.Bottom || other.value === lattice_1.Bottom) { return this.bottom(); } else { return new IntervalDomain([this.value[0] + other.value[0], this.value[1] + other.value[1]]); } } /** * Subtracts another abstract value from the current abstract value by subtracting the two lower and upper bounds from each other, respectively. */ subtract(other) { if (this.value === lattice_1.Bottom || other.value === lattice_1.Bottom) { return this.bottom(); } else { return new IntervalDomain([this.value[0] - other.value[0], this.value[1] - other.value[1]]); } } /** * Creates the minimum between the current abstract value and another abstract value by creating the minimum of the two lower and upper bounds, respectively. */ min(other) { if (this.value === lattice_1.Bottom || other.value === lattice_1.Bottom) { return this.bottom(); } else { return new IntervalDomain([Math.min(this.value[0], other.value[0]), Math.min(this.value[1], other.value[1])]); } } /** * Creates the maximum between the current abstract value and another abstract value by creating the maximum of the two lower and upper bounds, respectively. */ max(other) { if (this.value === lattice_1.Bottom || other.value === lattice_1.Bottom) { return this.bottom(); } else { return new IntervalDomain([Math.max(this.value[0], other.value[0]), Math.max(this.value[1], other.value[1])]); } } /** * Extends the lower bound of the current abstract value down to -∞. */ extendDown() { if (this.value === lattice_1.Bottom) { return this.bottom(); } else { return new IntervalDomain([-Infinity, this.value[1]]); } } /** * Extends the upper bound of the current abstract value up to +∞. */ extendUp() { if (this.value === lattice_1.Bottom) { return this.bottom(); } else { return new IntervalDomain([this.value[0], +Infinity]); } } toString() { if (this.value === lattice_1.Bottom) { return '⊥'; } return `[${isFinite(this.value[0]) ? this.value[0] : '-∞'}, ${isFinite(this.value[1]) ? this.value[1] : '+∞'}]`; } isTop() { return this.value !== lattice_1.Bottom && this.value[0] === -Infinity && this.value[1] === +Infinity; } isBottom() { return this.value === lattice_1.Bottom; } isValue() { return this.value !== lattice_1.Bottom; } } exports.IntervalDomain = IntervalDomain; //# sourceMappingURL=interval-domain.js.map