From d716e4256d9fda895ca8513ab6109de2e995651f Mon Sep 17 00:00:00 2001 From: Max Kasperowski Date: Mon, 25 Jul 2022 13:49:59 +0200 Subject: [PATCH 01/13] semantic filtering specifics --- .../src/filtering/semantic-filtering-util.ts | 318 ++++++++++++++++++ 1 file changed, 318 insertions(+) create mode 100644 packages/klighd-core/src/filtering/semantic-filtering-util.ts diff --git a/packages/klighd-core/src/filtering/semantic-filtering-util.ts b/packages/klighd-core/src/filtering/semantic-filtering-util.ts new file mode 100644 index 00000000..c36fc219 --- /dev/null +++ b/packages/klighd-core/src/filtering/semantic-filtering-util.ts @@ -0,0 +1,318 @@ +/* + * KIELER - Kiel Integrated Environment for Layout Eclipse RichClient + * + * http://rtsys.informatik.uni-kiel.de/kieler + * + * Copyright 2022 by + * + Kiel University + * + Department of Computer Science + * + Real-Time and Embedded Systems Group + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * SPDX-License-Identifier: EPL-2.0 + */ + +import { SKGraphElement } from "../skgraph-models" + +//// Base constructs //// + +/** + * Base interface for semantic filter rules. + */ +export interface SemanticFilterRule { + /** The rule name is used to identify rules and distinguish them from one another. */ + ruleName?: string + /** The default value is used to indicate whether the semantic filter should be on or off by default. */ + defaultValue?: boolean +} + +/** + * A semantic filter tag is used as a filter rule that evaluates to true iff the tag is present + * on a graph element. + */ +export class SemanticFilterTag implements SemanticFilterRule { + ruleName?: string + tag: string + /** Not defining num defaults it to 0. */ + num?: number +} + +/** + * Base interface for connectives. Connectives take one or more filter rules as operands and + * construct a new rule. + */ +export interface Connective extends SemanticFilterRule { + name: string +} + +//// Connectives //// + +/** + * Base interface for unary connectives. Unary Connectives take exactly one operand. + */ +export interface UnaryConnective extends Connective { + operand: SemanticFilterRule +} + +/** + * Base interface for binary connectives. Binary Connectives take exactly two operands. + */ +export interface BinaryConnective extends Connective { + leftOperand: SemanticFilterRule + rightOperand: SemanticFilterRule +} + +/** + * Base interface for ternary connectives. Ternary Connectives take exactly three operands. + */ +export interface TernaryConnective extends Connective { + firstOperand: SemanticFilterRule + secondOperand: SemanticFilterRule + thirdOperand: SemanticFilterRule +} + +//// Logic Connectives //// + +/** + * A Not Connective takes a rule R and evaluates to true + * iff + * R evaluates to false. + * @example !R + */ +export class NegationConnective implements UnaryConnective { + static NAME = "NOT" + name = NegationConnective.NAME + operand: SemanticFilterRule + ruleName?: string +} + +/** + * An And Connective takes two rules R1 and R2 and evaluates to true + * iff + * R1 and R2 evaluate to true. + * @example R1 && R2 + */ +export class AndConnective implements BinaryConnective { + static NAME = "AND" + name = AndConnective.NAME + leftOperand: SemanticFilterRule + rightOperand: SemanticFilterRule + ruleName?: string +} + +/** + * An Or Connective takes two rules R1 and R2 and evaluates to true + * iff + * R1 or R2 evaluate to true. + * @example R1 || R2 + */ +export class OrConnective implements BinaryConnective { + static NAME = "OR" + name = OrConnective.NAME + leftOperand: SemanticFilterRule + rightOperand: SemanticFilterRule + ruleName?: string +} + +/** + * An IfThen Connective takes two rules R1 and R2 and evaluates to true + * iff + * R1 evaluates to false or R2 evaluates to true. + * @example R1 ? R2 : true + * @example !R1 || R2 + */ +export class IfThenConnective implements BinaryConnective { + static NAME = "IFTHEN" + name = IfThenConnective.NAME + leftOperand: SemanticFilterRule + rightOperand: SemanticFilterRule + ruleName?: string +} + +/** + * A LogicEqual Connective takes two rules R1 and R2 and evaluates to true + * iff + * R1 and R2 evaluate to true or R1 and R2 evaluate to false. + * @example R1 === R2 + * @example R1 && R2 || !R1 && !R2 + */ +export class LogicEqualConnective implements BinaryConnective { + static NAME = "LOGICEQUAL" + name = LogicEqualConnective.NAME + leftOperand: SemanticFilterRule + rightOperand: SemanticFilterRule + ruleName?: string +} + +/** + * An IfThenElse Connective takes three rules R1, R2 and R3 and evaluates to true + * iff + * R1 and R2 evaluate to true or R1 evaluates to false and R3 evaluates to true. + * @example R1 ? R2 : R3 + * @example R1 && R2 || !R1 && R3 + */ +export class IfThenElseConnective implements TernaryConnective { + static NAME = "IFTHENELSE" + name = IfThenElseConnective.NAME + firstOperand: SemanticFilterRule + secondOperand: SemanticFilterRule + thirdOperand: SemanticFilterRule + ruleName?: string +} + +//// Numeric Connectives //// + +/** + * A LessThan Connective takes one rule R and evaluates to true + * iff + * R.num < correspondingTag.num. + * @example R.num < correspondingTag.num + */ +export class LessThanConnective implements UnaryConnective { + static NAME = "LESSTHAN" + name = LessThanConnective.NAME + operand: SemanticFilterTag + ruleName?: string +} + +/** + * A GreaterThan Connective takes one rule R and evaluates to true + * iff + * R.num > correspondingTag.num. + * @example R.num > correspondingTag.num + */ +export class GreaterThanConnective implements UnaryConnective { + static NAME = "GREATERTHAN" + name = GreaterThanConnective.NAME + operand: SemanticFilterTag + ruleName?: string +} + +/** + * A NumericEqual Connective takes one rule R and evaluates to true + * iff + * R.num === correspondingTag.num. + * @example R.num === correspondingTag.num + */ +export class NumericEqualConnective implements UnaryConnective { + static NAME = "NUMERICEQUAL" + name = NumericEqualConnective.NAME + operand: SemanticFilterTag + ruleName?: string +} + +//// Functions //// + +/** + * A filter is used to apply a filter rule as a boolean function on a graph element. The function + * returns true if the element fulfils the filter rule and false otherwise. + */ +export interface Filter { + name?: string + defaultValue?: boolean + filterFun(el: SKGraphElement): boolean +} + +/** + * Creates a new filter with a function that can be applied to graph elements when given + * a filter rule. + * @param rule the rule to construct the filter from + * @returns a new filter + */ +export function createFilter(rule: SemanticFilterRule): Filter { + + let ruleName; + if (rule instanceof SemanticFilterTag) { + ruleName = rule.tag; + } else { + ruleName = rule.ruleName; + } + return { + name: ruleName, + defaultValue: rule.defaultValue, + filterFun: (el) => { + let tags = Array(); + if (el.properties['de.cau.cs.kieler.klighd.semanticFilter.tags'] !== undefined) { + tags = el.properties['de.cau.cs.kieler.klighd.semanticFilter.tags'] as Array; + } + + return evaluateRule(rule, tags); + } + } + +} + +/** Evaluates `rule` using `tags`. See Connectives for further explanation on evaluation. */ +function evaluateRule(rule: SemanticFilterRule, tags: Array): boolean { + if ((rule as SemanticFilterTag).tag !== undefined) { + return tags.some((tag: SemanticFilterTag) => tag.tag === (rule as SemanticFilterTag).tag); + } + + // Rule is a Connective + const unary = rule as UnaryConnective; + const binary = rule as BinaryConnective; + const ternary = rule as TernaryConnective; + let correspondingTag; + switch ((rule as Connective).name) { + // Logic Connectives + case NegationConnective.NAME: + return !(evaluateRule(unary.operand, tags)); + case AndConnective.NAME: + return evaluateRule(binary.leftOperand, tags) + && evaluateRule(binary.rightOperand, tags); + case OrConnective.NAME: + return evaluateRule(binary.leftOperand, tags) + || evaluateRule(binary.rightOperand, tags); + case IfThenConnective.NAME: + return !evaluateRule(binary.leftOperand, tags) + || evaluateRule(binary.rightOperand, tags); + case LogicEqualConnective.NAME: + return evaluateRule(binary.leftOperand, tags) + === evaluateRule(binary.rightOperand, tags); + case IfThenElseConnective.NAME: + return evaluateRule(ternary.firstOperand, tags) + ? evaluateRule(ternary.secondOperand, tags) + : evaluateRule(ternary.thirdOperand, tags); + // Numeric Connectives + /* + For now, these are defined by an unset corresponding tag being treated as if its num was 0. TODO: + There is potential to redefine this so that an unset tag corresponding tag would automatically + be evaluated to false. However, this may result in three-valued logic which can be very dangerous + as some two-values logic laws may not hold. + Should this redefined, make sure to check all cases, e.g. !(x < y) === x >= y, de morgan, etc. + */ + case LessThanConnective.NAME: + correspondingTag = tags.find(tag => tag.tag === (unary as LessThanConnective).operand.tag); + return ((unary as LessThanConnective).operand.num ?? 0) + < (correspondingTag?.num ?? 0); + case GreaterThanConnective.NAME: + correspondingTag = tags.find(tag => tag.tag === (unary as GreaterThanConnective).operand.tag); + return ((unary as GreaterThanConnective).operand.num ?? 0) + > (correspondingTag?.num ?? 0); + case NumericEqualConnective.NAME: + correspondingTag = tags.find(tag => tag.tag === (unary as NumericEqualConnective).operand.tag); + return ((unary as NumericEqualConnective).operand.num ?? 0) + === (correspondingTag?.num ?? 0); + default: + return true; + } +} + +/** + * Gets all filters defined as filter rules on a given graph element. + * @param graph the graph element to check + * @returns array of filters + */ +export function getFilters(graph: SKGraphElement): Array { + const filters: Array = []; + if (graph.properties['de.cau.cs.kieler.klighd.semanticFilter.rules'] !== undefined) { + (graph.properties['de.cau.cs.kieler.klighd.semanticFilter.rules'] as Array) + .forEach((rule) => { + filters.push(createFilter(rule)); + }); + } + return filters; +} \ No newline at end of file From b38d1afb6d799857d4327ccdc8658783c0dd3608 Mon Sep 17 00:00:00 2001 From: Max Kasperowski Date: Tue, 26 Jul 2022 11:11:31 +0200 Subject: [PATCH 02/13] add true, false and id connectives --- .../src/filtering/semantic-filtering-util.ts | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/packages/klighd-core/src/filtering/semantic-filtering-util.ts b/packages/klighd-core/src/filtering/semantic-filtering-util.ts index c36fc219..de6af80b 100644 --- a/packages/klighd-core/src/filtering/semantic-filtering-util.ts +++ b/packages/klighd-core/src/filtering/semantic-filtering-util.ts @@ -50,6 +50,11 @@ export interface Connective extends SemanticFilterRule { //// Connectives //// +/** + * Base interface for nullary connectives. Nullary Connectives take no operands and are constants. + */ +export interface NullaryConnective extends Connective {} + /** * Base interface for unary connectives. Unary Connectives take exactly one operand. */ @@ -76,6 +81,33 @@ export interface TernaryConnective extends Connective { //// Logic Connectives //// +/** + * A True Connective always evaluates to true. + */ +export class TrueConnective implements NullaryConnective { + static NAME = "TRUE" + name = TrueConnective.NAME + ruleName?: string +} + +/** + * A False Connective always evaluates to false. + */ +export class FalseConnective implements NullaryConnective { + static NAME = "FALSE" + name = TrueConnective.NAME + ruleName?: string +} + +/** + * An Identity Connective evaluates to its operand i.e. ID (R) is equivalent to R. + */ +export class IdentityConnective implements UnaryConnective { + static NAME = "ID" + name = IdentityConnective.NAME + operand: SemanticFilterRule + ruleName?: string +} /** * A Not Connective takes a rule R and evaluates to true * iff @@ -258,6 +290,12 @@ function evaluateRule(rule: SemanticFilterRule, tags: Array): let correspondingTag; switch ((rule as Connective).name) { // Logic Connectives + case TrueConnective.NAME: + return true; + case FalseConnective.NAME: + return false; + case IdentityConnective.NAME: + return evaluateRule(unary.operand, tags) case NegationConnective.NAME: return !(evaluateRule(unary.operand, tags)); case AndConnective.NAME: From e43cccf660e04b8647a16270041dd313c4e9bb5e Mon Sep 17 00:00:00 2001 From: Max Kasperowski Date: Tue, 26 Jul 2022 12:02:34 +0200 Subject: [PATCH 03/13] remove empty interface --- .../klighd-core/src/filtering/semantic-filtering-util.ts | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/packages/klighd-core/src/filtering/semantic-filtering-util.ts b/packages/klighd-core/src/filtering/semantic-filtering-util.ts index de6af80b..54ae8175 100644 --- a/packages/klighd-core/src/filtering/semantic-filtering-util.ts +++ b/packages/klighd-core/src/filtering/semantic-filtering-util.ts @@ -50,11 +50,6 @@ export interface Connective extends SemanticFilterRule { //// Connectives //// -/** - * Base interface for nullary connectives. Nullary Connectives take no operands and are constants. - */ -export interface NullaryConnective extends Connective {} - /** * Base interface for unary connectives. Unary Connectives take exactly one operand. */ @@ -84,7 +79,7 @@ export interface TernaryConnective extends Connective { /** * A True Connective always evaluates to true. */ -export class TrueConnective implements NullaryConnective { +export class TrueConnective implements Connective { static NAME = "TRUE" name = TrueConnective.NAME ruleName?: string @@ -93,7 +88,7 @@ export class TrueConnective implements NullaryConnective { /** * A False Connective always evaluates to false. */ -export class FalseConnective implements NullaryConnective { +export class FalseConnective implements Connective { static NAME = "FALSE" name = TrueConnective.NAME ruleName?: string From 707849bccdd05757978827eb25fc92170a48c29d Mon Sep 17 00:00:00 2001 From: Max Kasperowski Date: Tue, 26 Jul 2022 13:47:30 +0200 Subject: [PATCH 04/13] make num not optional --- packages/klighd-core/src/filtering/semantic-filtering-util.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/klighd-core/src/filtering/semantic-filtering-util.ts b/packages/klighd-core/src/filtering/semantic-filtering-util.ts index 54ae8175..708920e1 100644 --- a/packages/klighd-core/src/filtering/semantic-filtering-util.ts +++ b/packages/klighd-core/src/filtering/semantic-filtering-util.ts @@ -36,8 +36,8 @@ export interface SemanticFilterRule { export class SemanticFilterTag implements SemanticFilterRule { ruleName?: string tag: string - /** Not defining num defaults it to 0. */ - num?: number + /** If num is not defined, the server will set the value 0 by default. */ + num: number } /** From 8dc9c36519454076305863b4f22941c5660e61e2 Mon Sep 17 00:00:00 2001 From: Max Kasperowski Date: Tue, 26 Jul 2022 14:49:10 +0200 Subject: [PATCH 05/13] put evaluation logic into separate namespaces --- .../src/filtering/semantic-filtering-util.ts | 118 ++++++++++++++---- 1 file changed, 91 insertions(+), 27 deletions(-) diff --git a/packages/klighd-core/src/filtering/semantic-filtering-util.ts b/packages/klighd-core/src/filtering/semantic-filtering-util.ts index 708920e1..4b28900a 100644 --- a/packages/klighd-core/src/filtering/semantic-filtering-util.ts +++ b/packages/klighd-core/src/filtering/semantic-filtering-util.ts @@ -85,6 +85,12 @@ export class TrueConnective implements Connective { ruleName?: string } +export namespace TrueConnective { + export function evaluate(conn: TrueConnective, tags: Array): boolean { + return true; + } +} + /** * A False Connective always evaluates to false. */ @@ -94,6 +100,12 @@ export class FalseConnective implements Connective { ruleName?: string } +export namespace FalseConnective { + export function evaluate(conn: FalseConnective, tags: Array): boolean { + return false; + } +} + /** * An Identity Connective evaluates to its operand i.e. ID (R) is equivalent to R. */ @@ -103,6 +115,13 @@ export class IdentityConnective implements UnaryConnective { operand: SemanticFilterRule ruleName?: string } + +export namespace IdentityConnective { + export function evaluate(conn: IdentityConnective, tags: Array): boolean { + return evaluateRule(conn.operand, tags); + } +} + /** * A Not Connective takes a rule R and evaluates to true * iff @@ -116,6 +135,12 @@ export class NegationConnective implements UnaryConnective { ruleName?: string } +export namespace NegationConnective { + export function evaluate(conn: NegationConnective, tags: Array): boolean { + return !evaluateRule(conn.operand, tags); + } +} + /** * An And Connective takes two rules R1 and R2 and evaluates to true * iff @@ -130,6 +155,12 @@ export class AndConnective implements BinaryConnective { ruleName?: string } +export namespace AndConnective { + export function evaluate(conn: AndConnective, tags: Array): boolean { + return evaluateRule(conn.leftOperand, tags) && evaluateRule(conn.rightOperand, tags); + } +} + /** * An Or Connective takes two rules R1 and R2 and evaluates to true * iff @@ -144,6 +175,12 @@ export class OrConnective implements BinaryConnective { ruleName?: string } +export namespace OrConnective { + export function evaluate(conn: OrConnective, tags: Array): boolean { + return evaluateRule(conn.leftOperand, tags) || evaluateRule(conn.rightOperand, tags); + } +} + /** * An IfThen Connective takes two rules R1 and R2 and evaluates to true * iff @@ -159,6 +196,12 @@ export class IfThenConnective implements BinaryConnective { ruleName?: string } +export namespace IfThenConnective { + export function evaluate(conn: IfThenConnective, tags: Array): boolean { + return !evaluateRule(conn.leftOperand, tags) || evaluateRule(conn.rightOperand, tags); + } +} + /** * A LogicEqual Connective takes two rules R1 and R2 and evaluates to true * iff @@ -174,6 +217,12 @@ export class LogicEqualConnective implements BinaryConnective { ruleName?: string } +export namespace LogicEqualConnective { + export function evaluate(conn: LogicEqualConnective, tags: Array): boolean { + return evaluateRule(conn.leftOperand, tags) === evaluateRule(conn.rightOperand, tags); + } +} + /** * An IfThenElse Connective takes three rules R1, R2 and R3 and evaluates to true * iff @@ -190,6 +239,14 @@ export class IfThenElseConnective implements TernaryConnective { ruleName?: string } +export namespace IfThenElseConnective { + export function evaluate(conn: IfThenElseConnective, tags: Array): boolean { + return evaluateRule(conn.firstOperand, tags) + ? evaluateRule(conn.secondOperand, tags) + : evaluateRule(conn.thirdOperand, tags); + } +} + //// Numeric Connectives //// /** @@ -205,6 +262,13 @@ export class LessThanConnective implements UnaryConnective { ruleName?: string } +export namespace LessThanConnective { + export function evaluate(conn: LessThanConnective, tags: Array): boolean { + let correspondingTag = tags.find(tag => tag.tag === conn.operand.tag); + return (conn.operand.num ?? 0) < (correspondingTag?.num ?? 0); + } +} + /** * A GreaterThan Connective takes one rule R and evaluates to true * iff @@ -218,6 +282,13 @@ export class GreaterThanConnective implements UnaryConnective { ruleName?: string } +export namespace GreaterThanConnective { + export function evaluate(conn: GreaterThanConnective, tags: Array): boolean { + let correspondingTag = tags.find(tag => tag.tag === conn.operand.tag); + return (conn.operand.num ?? 0) > (correspondingTag?.num ?? 0); + } +} + /** * A NumericEqual Connective takes one rule R and evaluates to true * iff @@ -231,6 +302,13 @@ export class NumericEqualConnective implements UnaryConnective { ruleName?: string } +export namespace NumericEqualConnective { + export function evaluate(conn: NumericEqualConnective, tags: Array): boolean { + let correspondingTag = tags.find(tag => tag.tag === conn.operand.tag); + return (conn.operand.num ?? 0) === (correspondingTag?.num ?? 0); + } +} + //// Functions //// /** @@ -274,41 +352,33 @@ export function createFilter(rule: SemanticFilterRule): Filter { /** Evaluates `rule` using `tags`. See Connectives for further explanation on evaluation. */ function evaluateRule(rule: SemanticFilterRule, tags: Array): boolean { + + // Rule is a Tag if ((rule as SemanticFilterTag).tag !== undefined) { return tags.some((tag: SemanticFilterTag) => tag.tag === (rule as SemanticFilterTag).tag); } // Rule is a Connective - const unary = rule as UnaryConnective; - const binary = rule as BinaryConnective; - const ternary = rule as TernaryConnective; - let correspondingTag; switch ((rule as Connective).name) { // Logic Connectives case TrueConnective.NAME: - return true; + return TrueConnective.evaluate(rule as TrueConnective, tags); case FalseConnective.NAME: return false; case IdentityConnective.NAME: - return evaluateRule(unary.operand, tags) + return IdentityConnective.evaluate(rule as IdentityConnective, tags); case NegationConnective.NAME: - return !(evaluateRule(unary.operand, tags)); + return NegationConnective.evaluate(rule as NegationConnective, tags); case AndConnective.NAME: - return evaluateRule(binary.leftOperand, tags) - && evaluateRule(binary.rightOperand, tags); + return AndConnective.evaluate(rule as AndConnective, tags); case OrConnective.NAME: - return evaluateRule(binary.leftOperand, tags) - || evaluateRule(binary.rightOperand, tags); + return OrConnective.evaluate(rule as OrConnective, tags); case IfThenConnective.NAME: - return !evaluateRule(binary.leftOperand, tags) - || evaluateRule(binary.rightOperand, tags); + return IfThenConnective.evaluate(rule as IfThenConnective, tags); case LogicEqualConnective.NAME: - return evaluateRule(binary.leftOperand, tags) - === evaluateRule(binary.rightOperand, tags); + return LogicEqualConnective.evaluate(rule as LogicEqualConnective, tags); case IfThenElseConnective.NAME: - return evaluateRule(ternary.firstOperand, tags) - ? evaluateRule(ternary.secondOperand, tags) - : evaluateRule(ternary.thirdOperand, tags); + return IfThenElseConnective.evaluate(rule as IfThenElseConnective, tags); // Numeric Connectives /* For now, these are defined by an unset corresponding tag being treated as if its num was 0. TODO: @@ -318,17 +388,11 @@ function evaluateRule(rule: SemanticFilterRule, tags: Array): Should this redefined, make sure to check all cases, e.g. !(x < y) === x >= y, de morgan, etc. */ case LessThanConnective.NAME: - correspondingTag = tags.find(tag => tag.tag === (unary as LessThanConnective).operand.tag); - return ((unary as LessThanConnective).operand.num ?? 0) - < (correspondingTag?.num ?? 0); + LessThanConnective.evaluate(rule as LessThanConnective, tags); case GreaterThanConnective.NAME: - correspondingTag = tags.find(tag => tag.tag === (unary as GreaterThanConnective).operand.tag); - return ((unary as GreaterThanConnective).operand.num ?? 0) - > (correspondingTag?.num ?? 0); + GreaterThanConnective.evaluate(rule as GreaterThanConnective, tags); case NumericEqualConnective.NAME: - correspondingTag = tags.find(tag => tag.tag === (unary as NumericEqualConnective).operand.tag); - return ((unary as NumericEqualConnective).operand.num ?? 0) - === (correspondingTag?.num ?? 0); + NumericEqualConnective.evaluate(rule as NumericEqualConnective, tags); default: return true; } From 4d49089080890042ca952a81606192a167fb68d5 Mon Sep 17 00:00:00 2001 From: Max Kasperowski Date: Tue, 26 Jul 2022 14:55:12 +0200 Subject: [PATCH 06/13] fix missing returns --- .../src/filtering/semantic-filtering-util.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/klighd-core/src/filtering/semantic-filtering-util.ts b/packages/klighd-core/src/filtering/semantic-filtering-util.ts index 4b28900a..f1e72522 100644 --- a/packages/klighd-core/src/filtering/semantic-filtering-util.ts +++ b/packages/klighd-core/src/filtering/semantic-filtering-util.ts @@ -264,7 +264,7 @@ export class LessThanConnective implements UnaryConnective { export namespace LessThanConnective { export function evaluate(conn: LessThanConnective, tags: Array): boolean { - let correspondingTag = tags.find(tag => tag.tag === conn.operand.tag); + const correspondingTag = tags.find(tag => tag.tag === conn.operand.tag); return (conn.operand.num ?? 0) < (correspondingTag?.num ?? 0); } } @@ -284,7 +284,7 @@ export class GreaterThanConnective implements UnaryConnective { export namespace GreaterThanConnective { export function evaluate(conn: GreaterThanConnective, tags: Array): boolean { - let correspondingTag = tags.find(tag => tag.tag === conn.operand.tag); + const correspondingTag = tags.find(tag => tag.tag === conn.operand.tag); return (conn.operand.num ?? 0) > (correspondingTag?.num ?? 0); } } @@ -304,7 +304,7 @@ export class NumericEqualConnective implements UnaryConnective { export namespace NumericEqualConnective { export function evaluate(conn: NumericEqualConnective, tags: Array): boolean { - let correspondingTag = tags.find(tag => tag.tag === conn.operand.tag); + const correspondingTag = tags.find(tag => tag.tag === conn.operand.tag); return (conn.operand.num ?? 0) === (correspondingTag?.num ?? 0); } } @@ -388,11 +388,11 @@ function evaluateRule(rule: SemanticFilterRule, tags: Array): Should this redefined, make sure to check all cases, e.g. !(x < y) === x >= y, de morgan, etc. */ case LessThanConnective.NAME: - LessThanConnective.evaluate(rule as LessThanConnective, tags); + return LessThanConnective.evaluate(rule as LessThanConnective, tags); case GreaterThanConnective.NAME: - GreaterThanConnective.evaluate(rule as GreaterThanConnective, tags); + return GreaterThanConnective.evaluate(rule as GreaterThanConnective, tags); case NumericEqualConnective.NAME: - NumericEqualConnective.evaluate(rule as NumericEqualConnective, tags); + return NumericEqualConnective.evaluate(rule as NumericEqualConnective, tags); default: return true; } From 5d772fc1db64b0018a09258e3abbcd84474127bf Mon Sep 17 00:00:00 2001 From: Max Kasperowski Date: Tue, 26 Jul 2022 15:30:53 +0200 Subject: [PATCH 07/13] add >=, <=, != numeric connectives --- .../src/filtering/semantic-filtering-util.ts | 63 +++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/packages/klighd-core/src/filtering/semantic-filtering-util.ts b/packages/klighd-core/src/filtering/semantic-filtering-util.ts index f1e72522..19f86ae8 100644 --- a/packages/klighd-core/src/filtering/semantic-filtering-util.ts +++ b/packages/klighd-core/src/filtering/semantic-filtering-util.ts @@ -309,6 +309,63 @@ export namespace NumericEqualConnective { } } +/** + * A GreaterEquals Connective takes one rule R and evaluates to true + * iff + * @example R.num >= correspondingTag.num. + */ +export class GreaterEqualsConnective implements UnaryConnective { + static NAME = "GREATEREQUALS" + name = GreaterEqualsConnective.NAME + operand: SemanticFilterTag + ruleName?: string +} + +export namespace GreaterEqualsConnective { + export function evaluate(conn: GreaterEqualsConnective, tags: Array): boolean { + const correspondingTag = tags.find(tag => tag.tag === conn.operand.tag); + return (conn.operand.num ?? 0) >= (correspondingTag?.num ?? 0); + } +} + +/** + * A LessEquals Connective takes one rule R and evaluates to true + * iff + * @example R.num <= correspondingTag.num. + */ + export class LessEqualsConnective implements UnaryConnective { + static NAME = "LESSEQUALS" + name = GreaterEqualsConnective.NAME + operand: SemanticFilterTag + ruleName?: string +} + +export namespace LessEqualsConnective { + export function evaluate(conn: LessEqualsConnective, tags: Array): boolean { + const correspondingTag = tags.find(tag => tag.tag === conn.operand.tag); + return (conn.operand.num ?? 0) <= (correspondingTag?.num ?? 0); + } +} + +/** + * A NumericNotEqual Connective takes one rule R and evaluates to true + * iff + * @example R.num != correspondingTag.num. + */ + export class NumericNotEqualConnective implements UnaryConnective { + static NAME = "NUMERICNOTEQUAL" + name = GreaterEqualsConnective.NAME + operand: SemanticFilterTag + ruleName?: string +} + +export namespace NumericNotEqualConnective { + export function evaluate(conn: NumericNotEqualConnective, tags: Array): boolean { + const correspondingTag = tags.find(tag => tag.tag === conn.operand.tag); + return (conn.operand.num ?? 0) !== (correspondingTag?.num ?? 0); + } +} + //// Functions //// /** @@ -393,6 +450,12 @@ function evaluateRule(rule: SemanticFilterRule, tags: Array): return GreaterThanConnective.evaluate(rule as GreaterThanConnective, tags); case NumericEqualConnective.NAME: return NumericEqualConnective.evaluate(rule as NumericEqualConnective, tags); + case GreaterEqualsConnective.NAME: + return GreaterEqualsConnective.evaluate(rule as GreaterEqualsConnective, tags); + case LessEqualsConnective.NAME: + return LessEqualsConnective.evaluate(rule as LessEqualsConnective, tags); + case NumericNotEqualConnective.NAME: + return NumericNotEqualConnective.evaluate(rule as NumericNotEqualConnective, tags); default: return true; } From 47ab7f9cff0cfa7b76ca3774513dba8da6d979e9 Mon Sep 17 00:00:00 2001 From: Max Kasperowski Date: Fri, 29 Jul 2022 13:04:36 +0200 Subject: [PATCH 08/13] add numeric connectives --- .../src/filtering/semantic-filtering-util.ts | 97 ++++++++++++++++++- 1 file changed, 96 insertions(+), 1 deletion(-) diff --git a/packages/klighd-core/src/filtering/semantic-filtering-util.ts b/packages/klighd-core/src/filtering/semantic-filtering-util.ts index 19f86ae8..d608c994 100644 --- a/packages/klighd-core/src/filtering/semantic-filtering-util.ts +++ b/packages/klighd-core/src/filtering/semantic-filtering-util.ts @@ -19,6 +19,13 @@ import { SKGraphElement } from "../skgraph-models" //// Base constructs //// +/** + * + */ +export interface NumericResult { + num: number +} + /** * Base interface for semantic filter rules. */ @@ -33,7 +40,7 @@ export interface SemanticFilterRule { * A semantic filter tag is used as a filter rule that evaluates to true iff the tag is present * on a graph element. */ -export class SemanticFilterTag implements SemanticFilterRule { +export class SemanticFilterTag implements SemanticFilterRule, NumericResult { ruleName?: string tag: string /** If num is not defined, the server will set the value 0 by default. */ @@ -366,6 +373,74 @@ export namespace NumericNotEqualConnective { } } +/** + * A Numeric Plus Connective takes two numeric operands and evaluates + * to their sum. + */ +export class NumericPlusConnective implements BinaryConnective { + static NAME = "NUMERICPLUS" + name = NumericPlusConnective.NAME + leftOperand: SemanticFilterRule + rightOperand: SemanticFilterRule +} + +export namespace NumericPlusConnective { + export function evaluate(conn: NumericPlusConnective): number { + return evaluateNumeric(conn.leftOperand) + evaluateNumeric(conn.rightOperand); + } +} + +/** + * A Numeric Minus Connective takes two numeric operands and evaluates + * to their difference. + */ +export class NumericMinusConnective implements BinaryConnective { + static NAME = "NUMERICMINUS" + name = NumericMinusConnective.NAME + leftOperand: SemanticFilterRule + rightOperand: SemanticFilterRule +} + +export namespace NumericMinusConnective { + export function evaluate(conn: NumericMinusConnective): number { + return evaluateNumeric(conn.leftOperand) - evaluateNumeric(conn.rightOperand); + } +} + +/** + * A Numeric Times Connective takes two numeric operands and evaluates + * to their product. + */ + export class NumericTimesConnective implements BinaryConnective { + static NAME = "NUMERICTIMES" + name = NumericTimesConnective.NAME + leftOperand: SemanticFilterRule + rightOperand: SemanticFilterRule +} + +export namespace NumericTimesConnective { + export function evaluate(conn: NumericTimesConnective): number { + return evaluateNumeric(conn.leftOperand) * evaluateNumeric(conn.rightOperand); + } +} + +/** + * A Numeric Divides Connective takes two numeric operands and evaluates + * to their product. + */ + export class NumericDividesConnective implements BinaryConnective { + static NAME = "NUMERICDIVIDES" + name = NumericDividesConnective.NAME + leftOperand: SemanticFilterRule + rightOperand: SemanticFilterRule +} + +export namespace NumericDividesConnective { + export function evaluate(conn: NumericDividesConnective): number { + return evaluateNumeric(conn.leftOperand) / evaluateNumeric(conn.rightOperand); + } +} + //// Functions //// /** @@ -407,6 +482,26 @@ export function createFilter(rule: SemanticFilterRule): Filter { } +function evaluateNumeric(rule: SemanticFilterRule): number { + // Rule is a Tag + if ((rule as SemanticFilterTag).tag !== undefined) { + return (rule as SemanticFilterTag).num; + } else { + switch ((rule as Connective).name) { + case NumericPlusConnective.NAME: + return NumericPlusConnective.evaluate(rule as NumericPlusConnective); + case NumericMinusConnective.NAME: + return NumericMinusConnective.evaluate(rule as NumericMinusConnective); + case NumericTimesConnective.NAME: + return NumericTimesConnective.evaluate(rule as NumericTimesConnective); + case NumericDividesConnective.NAME: + return NumericDividesConnective.evaluate(rule as NumericDividesConnective); + default: + return 0 + } + } +} + /** Evaluates `rule` using `tags`. See Connectives for further explanation on evaluation. */ function evaluateRule(rule: SemanticFilterRule, tags: Array): boolean { From 784504a51d9a8ac0a7b86e5d436e37a8434a4de8 Mon Sep 17 00:00:00 2001 From: Max Kasperowski Date: Fri, 29 Jul 2022 15:34:50 +0200 Subject: [PATCH 09/13] rename numeric connectives --- .../src/filtering/semantic-filtering-util.ts | 64 +++++++++---------- 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/packages/klighd-core/src/filtering/semantic-filtering-util.ts b/packages/klighd-core/src/filtering/semantic-filtering-util.ts index d608c994..08913a97 100644 --- a/packages/klighd-core/src/filtering/semantic-filtering-util.ts +++ b/packages/klighd-core/src/filtering/semantic-filtering-util.ts @@ -374,69 +374,69 @@ export namespace NumericNotEqualConnective { } /** - * A Numeric Plus Connective takes two numeric operands and evaluates + * A Numeric Addition Connective takes two numeric operands and evaluates * to their sum. */ -export class NumericPlusConnective implements BinaryConnective { - static NAME = "NUMERICPLUS" - name = NumericPlusConnective.NAME +export class NumericAdditionConnective implements BinaryConnective { + static NAME = "NUMERICAddition" + name = NumericAdditionConnective.NAME leftOperand: SemanticFilterRule rightOperand: SemanticFilterRule } -export namespace NumericPlusConnective { - export function evaluate(conn: NumericPlusConnective): number { +export namespace NumericAdditionConnective { + export function evaluate(conn: NumericAdditionConnective): number { return evaluateNumeric(conn.leftOperand) + evaluateNumeric(conn.rightOperand); } } /** - * A Numeric Minus Connective takes two numeric operands and evaluates + * A Numeric Subtraction Connective takes two numeric operands and evaluates * to their difference. */ -export class NumericMinusConnective implements BinaryConnective { - static NAME = "NUMERICMINUS" - name = NumericMinusConnective.NAME +export class NumericSubtractionConnective implements BinaryConnective { + static NAME = "NUMERICSubtraction" + name = NumericSubtractionConnective.NAME leftOperand: SemanticFilterRule rightOperand: SemanticFilterRule } -export namespace NumericMinusConnective { - export function evaluate(conn: NumericMinusConnective): number { +export namespace NumericSubtractionConnective { + export function evaluate(conn: NumericSubtractionConnective): number { return evaluateNumeric(conn.leftOperand) - evaluateNumeric(conn.rightOperand); } } /** - * A Numeric Times Connective takes two numeric operands and evaluates + * A Numeric Multiplication Connective takes two numeric operands and evaluates * to their product. */ - export class NumericTimesConnective implements BinaryConnective { - static NAME = "NUMERICTIMES" - name = NumericTimesConnective.NAME + export class NumericMultiplicationConnective implements BinaryConnective { + static NAME = "NUMERICMultiplication" + name = NumericMultiplicationConnective.NAME leftOperand: SemanticFilterRule rightOperand: SemanticFilterRule } -export namespace NumericTimesConnective { - export function evaluate(conn: NumericTimesConnective): number { +export namespace NumericMultiplicationConnective { + export function evaluate(conn: NumericMultiplicationConnective): number { return evaluateNumeric(conn.leftOperand) * evaluateNumeric(conn.rightOperand); } } /** - * A Numeric Divides Connective takes two numeric operands and evaluates + * A Numeric Division Connective takes two numeric operands and evaluates * to their product. */ - export class NumericDividesConnective implements BinaryConnective { - static NAME = "NUMERICDIVIDES" - name = NumericDividesConnective.NAME + export class NumericDivisionConnective implements BinaryConnective { + static NAME = "NUMERICDivision" + name = NumericDivisionConnective.NAME leftOperand: SemanticFilterRule rightOperand: SemanticFilterRule } -export namespace NumericDividesConnective { - export function evaluate(conn: NumericDividesConnective): number { +export namespace NumericDivisionConnective { + export function evaluate(conn: NumericDivisionConnective): number { return evaluateNumeric(conn.leftOperand) / evaluateNumeric(conn.rightOperand); } } @@ -488,14 +488,14 @@ function evaluateNumeric(rule: SemanticFilterRule): number { return (rule as SemanticFilterTag).num; } else { switch ((rule as Connective).name) { - case NumericPlusConnective.NAME: - return NumericPlusConnective.evaluate(rule as NumericPlusConnective); - case NumericMinusConnective.NAME: - return NumericMinusConnective.evaluate(rule as NumericMinusConnective); - case NumericTimesConnective.NAME: - return NumericTimesConnective.evaluate(rule as NumericTimesConnective); - case NumericDividesConnective.NAME: - return NumericDividesConnective.evaluate(rule as NumericDividesConnective); + case NumericAdditionConnective.NAME: + return NumericAdditionConnective.evaluate(rule as NumericAdditionConnective); + case NumericSubtractionConnective.NAME: + return NumericSubtractionConnective.evaluate(rule as NumericSubtractionConnective); + case NumericMultiplicationConnective.NAME: + return NumericMultiplicationConnective.evaluate(rule as NumericMultiplicationConnective); + case NumericDivisionConnective.NAME: + return NumericDivisionConnective.evaluate(rule as NumericDivisionConnective); default: return 0 } From 330a8110f3c9a7741f55813252e5968045a036d7 Mon Sep 17 00:00:00 2001 From: Max Kasperowski Date: Tue, 2 Aug 2022 15:54:24 +0200 Subject: [PATCH 10/13] fix evaluate numeric for tags --- .../src/filtering/semantic-filtering-util.ts | 41 +++++++++++-------- 1 file changed, 23 insertions(+), 18 deletions(-) diff --git a/packages/klighd-core/src/filtering/semantic-filtering-util.ts b/packages/klighd-core/src/filtering/semantic-filtering-util.ts index 08913a97..56377f63 100644 --- a/packages/klighd-core/src/filtering/semantic-filtering-util.ts +++ b/packages/klighd-core/src/filtering/semantic-filtering-util.ts @@ -378,15 +378,15 @@ export namespace NumericNotEqualConnective { * to their sum. */ export class NumericAdditionConnective implements BinaryConnective { - static NAME = "NUMERICAddition" + static NAME = "NUMERICADDITION" name = NumericAdditionConnective.NAME leftOperand: SemanticFilterRule rightOperand: SemanticFilterRule } export namespace NumericAdditionConnective { - export function evaluate(conn: NumericAdditionConnective): number { - return evaluateNumeric(conn.leftOperand) + evaluateNumeric(conn.rightOperand); + export function evaluate(conn: NumericAdditionConnective, tags: Array): number { + return evaluateNumeric(conn.leftOperand, tags) + evaluateNumeric(conn.rightOperand, tags); } } @@ -395,15 +395,15 @@ export namespace NumericAdditionConnective { * to their difference. */ export class NumericSubtractionConnective implements BinaryConnective { - static NAME = "NUMERICSubtraction" + static NAME = "NUMERICSUBBTRACTION" name = NumericSubtractionConnective.NAME leftOperand: SemanticFilterRule rightOperand: SemanticFilterRule } export namespace NumericSubtractionConnective { - export function evaluate(conn: NumericSubtractionConnective): number { - return evaluateNumeric(conn.leftOperand) - evaluateNumeric(conn.rightOperand); + export function evaluate(conn: NumericSubtractionConnective, tags: Array): number { + return evaluateNumeric(conn.leftOperand, tags) - evaluateNumeric(conn.rightOperand, tags); } } @@ -412,15 +412,15 @@ export namespace NumericSubtractionConnective { * to their product. */ export class NumericMultiplicationConnective implements BinaryConnective { - static NAME = "NUMERICMultiplication" + static NAME = "NUMERICMULTIPLICATION" name = NumericMultiplicationConnective.NAME leftOperand: SemanticFilterRule rightOperand: SemanticFilterRule } export namespace NumericMultiplicationConnective { - export function evaluate(conn: NumericMultiplicationConnective): number { - return evaluateNumeric(conn.leftOperand) * evaluateNumeric(conn.rightOperand); + export function evaluate(conn: NumericMultiplicationConnective, tags: Array): number { + return evaluateNumeric(conn.leftOperand, tags) * evaluateNumeric(conn.rightOperand, tags); } } @@ -429,15 +429,15 @@ export namespace NumericMultiplicationConnective { * to their product. */ export class NumericDivisionConnective implements BinaryConnective { - static NAME = "NUMERICDivision" + static NAME = "NUMERICDIVISION" name = NumericDivisionConnective.NAME leftOperand: SemanticFilterRule rightOperand: SemanticFilterRule } export namespace NumericDivisionConnective { - export function evaluate(conn: NumericDivisionConnective): number { - return evaluateNumeric(conn.leftOperand) / evaluateNumeric(conn.rightOperand); + export function evaluate(conn: NumericDivisionConnective, tags: Array): number { + return evaluateNumeric(conn.leftOperand, tags) / evaluateNumeric(conn.rightOperand, tags); } } @@ -482,20 +482,25 @@ export function createFilter(rule: SemanticFilterRule): Filter { } -function evaluateNumeric(rule: SemanticFilterRule): number { +function evaluateNumeric(rule: SemanticFilterRule, tags: Array): number { // Rule is a Tag if ((rule as SemanticFilterTag).tag !== undefined) { - return (rule as SemanticFilterTag).num; + let nodeTag = tags.find((tag: SemanticFilterTag) => tag.tag === (rule as SemanticFilterTag).tag) + if (nodeTag != undefined) { + return nodeTag.num; + } else { + return 0; + } } else { switch ((rule as Connective).name) { case NumericAdditionConnective.NAME: - return NumericAdditionConnective.evaluate(rule as NumericAdditionConnective); + return NumericAdditionConnective.evaluate(rule as NumericAdditionConnective, tags); case NumericSubtractionConnective.NAME: - return NumericSubtractionConnective.evaluate(rule as NumericSubtractionConnective); + return NumericSubtractionConnective.evaluate(rule as NumericSubtractionConnective, tags); case NumericMultiplicationConnective.NAME: - return NumericMultiplicationConnective.evaluate(rule as NumericMultiplicationConnective); + return NumericMultiplicationConnective.evaluate(rule as NumericMultiplicationConnective, tags); case NumericDivisionConnective.NAME: - return NumericDivisionConnective.evaluate(rule as NumericDivisionConnective); + return NumericDivisionConnective.evaluate(rule as NumericDivisionConnective, tags); default: return 0 } From ee162ffdec7cbe98218e531cd20863a82c23e183 Mon Sep 17 00:00:00 2001 From: Max Kasperowski Date: Tue, 2 Aug 2022 16:15:15 +0200 Subject: [PATCH 11/13] make numeric to bool connectives binary --- .../src/filtering/semantic-filtering-util.ts | 74 +++++++++---------- 1 file changed, 35 insertions(+), 39 deletions(-) diff --git a/packages/klighd-core/src/filtering/semantic-filtering-util.ts b/packages/klighd-core/src/filtering/semantic-filtering-util.ts index 56377f63..c0cbe758 100644 --- a/packages/klighd-core/src/filtering/semantic-filtering-util.ts +++ b/packages/klighd-core/src/filtering/semantic-filtering-util.ts @@ -257,119 +257,115 @@ export namespace IfThenElseConnective { //// Numeric Connectives //// /** - * A LessThan Connective takes one rule R and evaluates to true + * A LessThan Connective takes two numeric rules R1 and R2 and evaluates to true * iff - * R.num < correspondingTag.num. - * @example R.num < correspondingTag.num + * R1 < R2 */ -export class LessThanConnective implements UnaryConnective { +export class LessThanConnective implements BinaryConnective { static NAME = "LESSTHAN" name = LessThanConnective.NAME - operand: SemanticFilterTag + leftOperand: SemanticFilterRule + rightOperand: SemanticFilterRule ruleName?: string } export namespace LessThanConnective { export function evaluate(conn: LessThanConnective, tags: Array): boolean { - const correspondingTag = tags.find(tag => tag.tag === conn.operand.tag); - return (conn.operand.num ?? 0) < (correspondingTag?.num ?? 0); + return evaluateNumeric(conn.leftOperand, tags) < evaluateNumeric(conn.rightOperand, tags); } } /** - * A GreaterThan Connective takes one rule R and evaluates to true + * A GreaterThan Connective takes two numeric rules R1 and R2 and evaluates to true * iff - * R.num > correspondingTag.num. - * @example R.num > correspondingTag.num + * R1 > R2 */ -export class GreaterThanConnective implements UnaryConnective { +export class GreaterThanConnective implements BinaryConnective { static NAME = "GREATERTHAN" name = GreaterThanConnective.NAME - operand: SemanticFilterTag + leftOperand: SemanticFilterRule + rightOperand: SemanticFilterRule ruleName?: string } export namespace GreaterThanConnective { export function evaluate(conn: GreaterThanConnective, tags: Array): boolean { - const correspondingTag = tags.find(tag => tag.tag === conn.operand.tag); - return (conn.operand.num ?? 0) > (correspondingTag?.num ?? 0); + return evaluateNumeric(conn.leftOperand, tags) > evaluateNumeric(conn.rightOperand, tags); } } /** - * A NumericEqual Connective takes one rule R and evaluates to true + * A NumericEqual Connective takes two rules R1 and R2 and evaluates to true * iff - * R.num === correspondingTag.num. - * @example R.num === correspondingTag.num + * R1 === R2 */ -export class NumericEqualConnective implements UnaryConnective { +export class NumericEqualConnective implements BinaryConnective { static NAME = "NUMERICEQUAL" name = NumericEqualConnective.NAME - operand: SemanticFilterTag + leftOperand: SemanticFilterTag + rightOperand: SemanticFilterRule ruleName?: string } export namespace NumericEqualConnective { export function evaluate(conn: NumericEqualConnective, tags: Array): boolean { - const correspondingTag = tags.find(tag => tag.tag === conn.operand.tag); - return (conn.operand.num ?? 0) === (correspondingTag?.num ?? 0); + return evaluateNumeric(conn.leftOperand, tags) === evaluateNumeric(conn.rightOperand, tags); } } /** - * A GreaterEquals Connective takes one rule R and evaluates to true + * A GreaterEquals Connective takes two numeric rules R1 and R2 and evaluates to true * iff - * @example R.num >= correspondingTag.num. */ -export class GreaterEqualsConnective implements UnaryConnective { +export class GreaterEqualsConnective implements BinaryConnective { static NAME = "GREATEREQUALS" name = GreaterEqualsConnective.NAME - operand: SemanticFilterTag + leftOperand: SemanticFilterTag + rightOperand: SemanticFilterRule ruleName?: string } export namespace GreaterEqualsConnective { export function evaluate(conn: GreaterEqualsConnective, tags: Array): boolean { - const correspondingTag = tags.find(tag => tag.tag === conn.operand.tag); - return (conn.operand.num ?? 0) >= (correspondingTag?.num ?? 0); + return evaluateNumeric(conn.leftOperand, tags) >= evaluateNumeric(conn.rightOperand, tags); } } /** - * A LessEquals Connective takes one rule R and evaluates to true + * A LessEquals Connective takes two numeric rules R1 and R2 and evaluates to true * iff - * @example R.num <= correspondingTag.num. + * R1 <= R2 */ - export class LessEqualsConnective implements UnaryConnective { + export class LessEqualsConnective implements BinaryConnective { static NAME = "LESSEQUALS" name = GreaterEqualsConnective.NAME - operand: SemanticFilterTag + leftOperand: SemanticFilterTag + rightOperand: SemanticFilterRule ruleName?: string } export namespace LessEqualsConnective { export function evaluate(conn: LessEqualsConnective, tags: Array): boolean { - const correspondingTag = tags.find(tag => tag.tag === conn.operand.tag); - return (conn.operand.num ?? 0) <= (correspondingTag?.num ?? 0); + return evaluateNumeric(conn.leftOperand, tags) <= evaluateNumeric(conn.rightOperand, tags); } } /** - * A NumericNotEqual Connective takes one rule R and evaluates to true + * A NumericNotEqual Connective takes two rules R1 and R2 and evaluates to true * iff - * @example R.num != correspondingTag.num. + * R1 != R2 */ - export class NumericNotEqualConnective implements UnaryConnective { + export class NumericNotEqualConnective implements BinaryConnective { static NAME = "NUMERICNOTEQUAL" name = GreaterEqualsConnective.NAME - operand: SemanticFilterTag + leftOperand: SemanticFilterTag + rightOperand: SemanticFilterRule ruleName?: string } export namespace NumericNotEqualConnective { export function evaluate(conn: NumericNotEqualConnective, tags: Array): boolean { - const correspondingTag = tags.find(tag => tag.tag === conn.operand.tag); - return (conn.operand.num ?? 0) !== (correspondingTag?.num ?? 0); + return evaluateNumeric(conn.leftOperand, tags) !== evaluateNumeric(conn.rightOperand, tags); } } From 39aded8d678f28ccd91c1b1efc9e2a9af32916df Mon Sep 17 00:00:00 2001 From: Max Kasperowski Date: Tue, 2 Aug 2022 16:25:27 +0200 Subject: [PATCH 12/13] add numeric constant --- .../src/filtering/semantic-filtering-util.ts | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/packages/klighd-core/src/filtering/semantic-filtering-util.ts b/packages/klighd-core/src/filtering/semantic-filtering-util.ts index c0cbe758..10264c9e 100644 --- a/packages/klighd-core/src/filtering/semantic-filtering-util.ts +++ b/packages/klighd-core/src/filtering/semantic-filtering-util.ts @@ -437,6 +437,21 @@ export namespace NumericDivisionConnective { } } +/** + * A Numeric Constant Connective returns a constant value. + */ +export class NumericConstantConnective implements Connective { + static NAME = "CONST" + name = NumericConstantConnective.NAME + num: number +} + +export namespace NumericConstantConnective { + export function evaluate(conn: NumericConstantConnective): number { + return conn.num; + } +} + //// Functions //// /** @@ -489,6 +504,8 @@ function evaluateNumeric(rule: SemanticFilterRule, tags: Array Date: Wed, 3 Aug 2022 08:52:23 +0200 Subject: [PATCH 13/13] change let to const --- packages/klighd-core/src/filtering/semantic-filtering-util.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/klighd-core/src/filtering/semantic-filtering-util.ts b/packages/klighd-core/src/filtering/semantic-filtering-util.ts index 10264c9e..ff4f8b19 100644 --- a/packages/klighd-core/src/filtering/semantic-filtering-util.ts +++ b/packages/klighd-core/src/filtering/semantic-filtering-util.ts @@ -496,7 +496,7 @@ export function createFilter(rule: SemanticFilterRule): Filter { function evaluateNumeric(rule: SemanticFilterRule, tags: Array): number { // Rule is a Tag if ((rule as SemanticFilterTag).tag !== undefined) { - let nodeTag = tags.find((tag: SemanticFilterTag) => tag.tag === (rule as SemanticFilterTag).tag) + const nodeTag = tags.find((tag: SemanticFilterTag) => tag.tag === (rule as SemanticFilterTag).tag) if (nodeTag != undefined) { return nodeTag.num; } else {