From 7f2df1ba80aac7e1c5e99315bf5a8e32ad7456da Mon Sep 17 00:00:00 2001 From: Kristóf Marussy Date: Fri, 21 Jul 2023 02:18:06 +0200 Subject: feat: custom connected component RETE node --- .../refinery/store/query/literal/CallLiteral.java | 4 + .../refinery/store/query/literal/Connectivity.java | 18 ++++ .../literal/RepresentativeElectionLiteral.java | 102 +++++++++++++++++++++ 3 files changed, 124 insertions(+) create mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/literal/Connectivity.java create mode 100644 subprojects/store-query/src/main/java/tools/refinery/store/query/literal/RepresentativeElectionLiteral.java (limited to 'subprojects/store-query/src/main/java') diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/CallLiteral.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/CallLiteral.java index b1585c77..3a80cefd 100644 --- a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/CallLiteral.java +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/CallLiteral.java @@ -30,6 +30,10 @@ public final class CallLiteral extends AbstractCallLiteral implements CanNegate< if (parameters.get(0).isDataVariable() || parameters.get(1).isDataVariable()) { throw new IllegalArgumentException("Transitive closures can only be computed over nodes"); } + if (parameters.get(0).getDirection() != ParameterDirection.OUT || + parameters.get(1).getDirection() != ParameterDirection.OUT) { + throw new IllegalArgumentException("Transitive closures cannot take input parameters"); + } } this.polarity = polarity; } diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/Connectivity.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/Connectivity.java new file mode 100644 index 00000000..a058094d --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/Connectivity.java @@ -0,0 +1,18 @@ +/* + * SPDX-FileCopyrightText: 2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.store.query.literal; + +import java.util.Locale; + +public enum Connectivity { + WEAK, + STRONG; + + @Override + public String toString() { + return name().toLowerCase(Locale.ROOT); + } +} diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/RepresentativeElectionLiteral.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/RepresentativeElectionLiteral.java new file mode 100644 index 00000000..876ae253 --- /dev/null +++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/RepresentativeElectionLiteral.java @@ -0,0 +1,102 @@ +/* + * SPDX-FileCopyrightText: 2023 The Refinery Authors + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tools.refinery.store.query.literal; + +import tools.refinery.store.query.Constraint; +import tools.refinery.store.query.substitution.Substitution; +import tools.refinery.store.query.term.NodeVariable; +import tools.refinery.store.query.term.ParameterDirection; +import tools.refinery.store.query.term.Variable; + +import java.util.List; +import java.util.Set; + +// {@link Object#equals(Object)} is implemented by {@link AbstractLiteral}. +@SuppressWarnings("squid:S2160") +public class RepresentativeElectionLiteral extends AbstractCallLiteral { + private final Connectivity connectivity; + + public RepresentativeElectionLiteral(Connectivity connectivity, Constraint target, NodeVariable specific, + NodeVariable representative) { + this(connectivity, target, List.of(specific, representative)); + } + + private RepresentativeElectionLiteral(Connectivity connectivity, Constraint target, List arguments) { + super(target, arguments); + this.connectivity = connectivity; + var parameters = target.getParameters(); + int arity = target.arity(); + if (arity != 2) { + throw new IllegalArgumentException("SCCs can only take binary relations"); + } + if (parameters.get(0).isDataVariable() || parameters.get(1).isDataVariable()) { + throw new IllegalArgumentException("SCCs can only be computed over nodes"); + } + if (parameters.get(0).getDirection() != ParameterDirection.OUT || + parameters.get(1).getDirection() != ParameterDirection.OUT) { + throw new IllegalArgumentException("SCCs cannot take input parameters"); + } + } + + public Connectivity getConnectivity() { + return connectivity; + } + + @Override + protected Literal doSubstitute(Substitution substitution, List substitutedArguments) { + return new RepresentativeElectionLiteral(connectivity, getTarget(), substitutedArguments); + } + + @Override + public Set getOutputVariables() { + return getArgumentsOfDirection(ParameterDirection.OUT); + } + + @Override + public Set getInputVariables(Set positiveVariablesInClause) { + return Set.of(); + } + + @Override + public Set getPrivateVariables(Set positiveVariablesInClause) { + return Set.of(); + } + + @Override + public Literal reduce() { + var reduction = getTarget().getReduction(); + return switch (reduction) { + case ALWAYS_FALSE -> BooleanLiteral.FALSE; + case ALWAYS_TRUE -> throw new IllegalArgumentException( + "Trying to elect representatives over an infinite set"); + case NOT_REDUCIBLE -> this; + }; + } + + @Override + protected AbstractCallLiteral internalWithTarget(Constraint newTarget) { + return new RepresentativeElectionLiteral(connectivity, newTarget, getArguments()); + } + + @Override + public String toString() { + var builder = new StringBuilder(); + builder.append("@Representative(\""); + builder.append(connectivity); + builder.append("\") "); + builder.append(getTarget().toReferenceString()); + builder.append("("); + var argumentIterator = getArguments().iterator(); + if (argumentIterator.hasNext()) { + builder.append(argumentIterator.next()); + while (argumentIterator.hasNext()) { + builder.append(", ").append(argumentIterator.next()); + } + } + builder.append(")"); + return builder.toString(); + } +} -- cgit v1.2.3-54-g00ecf