aboutsummaryrefslogtreecommitdiffstats
path: root/subprojects/store-query/src
diff options
context:
space:
mode:
Diffstat (limited to 'subprojects/store-query/src')
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/Constraint.java72
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/InvalidQueryException.java23
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/ModelQueryAdapter.java4
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/ModelQueryBuilder.java4
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/ModelQueryStoreAdapter.java4
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/AbstractQueryBuilder.java175
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/AnyQuery.java16
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/ClausePostProcessor.java362
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/Dnf.java235
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/DnfBuilder.java225
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/DnfClause.java37
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/DnfPostProcessor.java112
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/DnfUtils.java24
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/FunctionalDependency.java22
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/FunctionalQuery.java110
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/FunctionalQueryBuilder.java29
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/InvalidClauseException.java35
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/Query.java202
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/QueryBuilder.java27
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/RelationalQuery.java77
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/SymbolicParameter.java53
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/ClauseCallback0.java15
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/ClauseCallback1Data0.java16
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/ClauseCallback1Data1.java16
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/ClauseCallback2Data0.java16
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/ClauseCallback2Data1.java17
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/ClauseCallback2Data2.java16
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/ClauseCallback3Data0.java16
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/ClauseCallback3Data1.java17
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/ClauseCallback3Data2.java17
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/ClauseCallback3Data3.java16
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/ClauseCallback4Data0.java16
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/ClauseCallback4Data1.java17
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/ClauseCallback4Data2.java17
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/ClauseCallback4Data3.java17
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/ClauseCallback4Data4.java16
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/FunctionalQueryCallback0.java14
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/FunctionalQueryCallback1.java15
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/FunctionalQueryCallback2.java15
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/FunctionalQueryCallback3.java16
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/FunctionalQueryCallback4.java16
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/QueryCallback0.java13
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/QueryCallback1.java14
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/QueryCallback2.java14
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/QueryCallback3.java14
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/QueryCallback4.java14
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/equality/DeepDnfEqualityChecker.java77
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/equality/DnfEqualityChecker.java17
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/equality/LiteralEqualityHelper.java27
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/equality/LiteralHashCodeHelper.java17
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/equality/SubstitutingLiteralEqualityHelper.java59
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/equality/SubstitutingLiteralHashCodeHelper.java42
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/literal/AbstractCallLiteral.java135
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/literal/AbstractCountLiteral.java107
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/literal/AbstractLiteral.java34
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/literal/AggregationLiteral.java138
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/literal/AssignLiteral.java88
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/literal/BooleanLiteral.java69
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/literal/CallLiteral.java134
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/literal/CallPolarity.java39
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/literal/CanNegate.java10
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/literal/CheckLiteral.java95
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/literal/Connectivity.java18
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/literal/ConstantLiteral.java73
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/literal/CountLiteral.java45
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/literal/EquivalenceLiteral.java100
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/literal/Literal.java32
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/literal/Literals.java22
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/literal/Reduction.java31
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/literal/RepresentativeElectionLiteral.java119
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/resultset/AbstractResultSet.java2
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/resultset/AnyResultSet.java2
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/resultset/EmptyResultSet.java2
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/resultset/OrderedResultSet.java2
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/resultset/ResultSet.java2
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/rewriter/AbstractRecursiveRewriter.java26
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/rewriter/ClauseInputParameterResolver.java160
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/rewriter/CompositeRewriter.java29
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/rewriter/DnfRewriter.java24
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/rewriter/DuplicateDnfRemover.java98
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/rewriter/InputParameterResolver.java51
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/substitution/MapBasedSubstitution.java18
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/substitution/RenewingSubstitution.java20
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/substitution/StatelessSubstitution.java23
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/substitution/Substitution.java29
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/substitution/SubstitutionBuilder.java79
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/term/AbstractTerm.java47
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/term/Aggregator.java18
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/term/AnyDataVariable.java55
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/term/AnyTerm.java24
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/term/AssignedValue.java13
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/term/BinaryTerm.java106
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/term/ConstantTerm.java67
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/term/DataVariable.java103
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/term/ExtremeValueAggregator.java108
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/term/NodeVariable.java71
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/term/Parameter.java68
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/term/ParameterDirection.java22
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/term/StatefulAggregate.java22
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/term/StatefulAggregator.java28
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/term/StatelessAggregator.java25
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/term/Term.java26
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/term/UnaryTerm.java74
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/term/Variable.java88
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/BoolAndTerm.java31
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/BoolBinaryTerm.java15
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/BoolNotTerm.java31
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/BoolOrTerm.java31
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/BoolTerms.java35
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/BoolXorTerm.java31
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/term/comparable/ComparisonTerm.java19
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/term/comparable/EqTerm.java30
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/term/comparable/GreaterEqTerm.java30
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/term/comparable/GreaterTerm.java30
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/term/comparable/LessEqTerm.java30
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/term/comparable/LessTerm.java30
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/term/comparable/NotEqTerm.java30
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntAddTerm.java31
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntBinaryTerm.java15
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntDivTerm.java31
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntMaxTerm.java31
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntMinTerm.java31
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntMinusTerm.java30
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntMulTerm.java31
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntPlusTerm.java30
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntPowTerm.java43
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntSubTerm.java31
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntSumAggregator.java40
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntTerms.java94
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntUnaryTerm.java15
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/RealToIntTerm.java31
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/IntToRealTerm.java31
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealAddTerm.java31
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealBinaryTerm.java15
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealDivTerm.java31
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealMaxTerm.java31
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealMinTerm.java31
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealMinusTerm.java30
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealMulTerm.java31
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealPlusTerm.java30
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealPowTerm.java31
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealSubTerm.java31
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealSumAggregator.java90
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealTerms.java94
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealUnaryTerm.java15
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/term/uppercardinality/UpperCardinalityAddTerm.java31
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/term/uppercardinality/UpperCardinalityBinaryTerm.java17
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/term/uppercardinality/UpperCardinalityMaxTerm.java31
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/term/uppercardinality/UpperCardinalityMinTerm.java31
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/term/uppercardinality/UpperCardinalityMulTerm.java31
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/term/uppercardinality/UpperCardinalitySumAggregator.java86
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/term/uppercardinality/UpperCardinalityTerms.java73
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/valuation/MapBasedValuation.java22
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/valuation/RestrictedValuation.java21
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/valuation/SubstitutedValuation.java16
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/valuation/Valuation.java37
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/valuation/ValuationBuilder.java40
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/view/AbstractFunctionView.java4
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/view/AnySymbolView.java4
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/view/FilteredView.java2
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/view/ForbiddenView.java2
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/view/FunctionView.java18
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/view/MayView.java2
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/view/MustView.java2
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/view/NodeFunctionView.java2
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/view/TuplePreservingView.java2
-rw-r--r--subprojects/store-query/src/test/java/tools/refinery/store/query/dnf/DnfBuilderLiteralEliminationTest.java259
-rw-r--r--subprojects/store-query/src/test/java/tools/refinery/store/query/dnf/DnfBuilderVariableUnificationTest.java325
-rw-r--r--subprojects/store-query/src/test/java/tools/refinery/store/query/dnf/DnfToDefinitionStringTest.java157
-rw-r--r--subprojects/store-query/src/test/java/tools/refinery/store/query/dnf/HashCodeTest.java67
-rw-r--r--subprojects/store-query/src/test/java/tools/refinery/store/query/dnf/TopologicalSortTest.java113
-rw-r--r--subprojects/store-query/src/test/java/tools/refinery/store/query/dnf/VariableDirectionTest.java251
-rw-r--r--subprojects/store-query/src/test/java/tools/refinery/store/query/literal/AggregationLiteralTest.java89
-rw-r--r--subprojects/store-query/src/test/java/tools/refinery/store/query/literal/CallLiteralTest.java94
-rw-r--r--subprojects/store-query/src/test/java/tools/refinery/store/query/rewriter/DuplicateDnfRemoverTest.java164
-rw-r--r--subprojects/store-query/src/test/java/tools/refinery/store/query/rewriter/InputParameterResolverTest.java228
-rw-r--r--subprojects/store-query/src/test/java/tools/refinery/store/query/term/TermSubstitutionTest.java97
-rw-r--r--subprojects/store-query/src/test/java/tools/refinery/store/query/term/bool/BoolTermsEvaluateTest.java75
-rw-r--r--subprojects/store-query/src/test/java/tools/refinery/store/query/term/int_/IntTermsEvaluateTest.java259
-rw-r--r--subprojects/store-query/src/test/java/tools/refinery/store/query/term/real/RealTermEvaluateTest.java238
-rw-r--r--subprojects/store-query/src/test/java/tools/refinery/store/query/term/uppercardinality/UpperCardinalitySumAggregatorStreamTest.java56
-rw-r--r--subprojects/store-query/src/test/java/tools/refinery/store/query/term/uppercardinality/UpperCardinalitySumAggregatorTest.java80
-rw-r--r--subprojects/store-query/src/test/java/tools/refinery/store/query/term/uppercardinality/UpperCardinalityTermsEvaluateTest.java104
-rw-r--r--subprojects/store-query/src/test/java/tools/refinery/store/query/tests/StructurallyEqualToRawTest.java159
-rw-r--r--subprojects/store-query/src/test/java/tools/refinery/store/query/tests/StructurallyEqualToTest.java127
-rw-r--r--subprojects/store-query/src/testFixtures/java/tools/refinery/store/query/tests/MismatchDescribingDnfEqualityChecker.java68
-rw-r--r--subprojects/store-query/src/testFixtures/java/tools/refinery/store/query/tests/QueryMatchers.java46
-rw-r--r--subprojects/store-query/src/testFixtures/java/tools/refinery/store/query/tests/StructurallyEqualTo.java41
-rw-r--r--subprojects/store-query/src/testFixtures/java/tools/refinery/store/query/tests/StructurallyEqualToRaw.java51
189 files changed, 37 insertions, 10262 deletions
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/Constraint.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/Constraint.java
deleted file mode 100644
index 916fb35c..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/Constraint.java
+++ /dev/null
@@ -1,72 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query;
7
8import tools.refinery.store.query.equality.LiteralEqualityHelper;
9import tools.refinery.store.query.literal.*;
10import tools.refinery.store.query.term.*;
11
12import java.util.List;
13
14public interface Constraint {
15 String name();
16
17 List<Parameter> getParameters();
18
19 default int arity() {
20 return getParameters().size();
21 }
22
23 default boolean invalidIndex(int i) {
24 return i < 0 || i >= arity();
25 }
26
27 default Reduction getReduction() {
28 return Reduction.NOT_REDUCIBLE;
29 }
30
31 default boolean equals(LiteralEqualityHelper helper, Constraint other) {
32 return equals(other);
33 }
34
35 default String toReferenceString() {
36 return name();
37 }
38
39 default CallLiteral call(CallPolarity polarity, List<Variable> arguments) {
40 return new CallLiteral(polarity, this, arguments);
41 }
42
43 default CallLiteral call(CallPolarity polarity, Variable... arguments) {
44 return call(polarity, List.of(arguments));
45 }
46
47 default CallLiteral call(Variable... arguments) {
48 return call(CallPolarity.POSITIVE, arguments);
49 }
50
51 default CallLiteral callTransitive(NodeVariable left, NodeVariable right) {
52 return call(CallPolarity.TRANSITIVE, List.of(left, right));
53 }
54
55 default AssignedValue<Integer> count(List<Variable> arguments) {
56 return targetVariable -> new CountLiteral(targetVariable, this, arguments);
57 }
58
59 default AssignedValue<Integer> count(Variable... arguments) {
60 return count(List.of(arguments));
61 }
62
63 default <R, T> AssignedValue<R> aggregateBy(DataVariable<T> inputVariable, Aggregator<R, T> aggregator,
64 List<Variable> arguments) {
65 return targetVariable -> new AggregationLiteral<>(targetVariable, aggregator, inputVariable, this, arguments);
66 }
67
68 default <R, T> AssignedValue<R> aggregateBy(DataVariable<T> inputVariable, Aggregator<R, T> aggregator,
69 Variable... arguments) {
70 return aggregateBy(inputVariable, aggregator, List.of(arguments));
71 }
72}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/InvalidQueryException.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/InvalidQueryException.java
deleted file mode 100644
index c39277a0..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/InvalidQueryException.java
+++ /dev/null
@@ -1,23 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query;
7
8public class InvalidQueryException extends RuntimeException {
9 public InvalidQueryException() {
10 }
11
12 public InvalidQueryException(String message) {
13 super(message);
14 }
15
16 public InvalidQueryException(String message, Throwable cause) {
17 super(message, cause);
18 }
19
20 public InvalidQueryException(Throwable cause) {
21 super(cause);
22 }
23}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/ModelQueryAdapter.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/ModelQueryAdapter.java
index 1fa96a07..513825b7 100644
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/ModelQueryAdapter.java
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/ModelQueryAdapter.java
@@ -6,8 +6,8 @@
6package tools.refinery.store.query; 6package tools.refinery.store.query;
7 7
8import tools.refinery.store.adapter.ModelAdapter; 8import tools.refinery.store.adapter.ModelAdapter;
9import tools.refinery.store.query.dnf.AnyQuery; 9import tools.refinery.logic.dnf.AnyQuery;
10import tools.refinery.store.query.dnf.Query; 10import tools.refinery.logic.dnf.Query;
11import tools.refinery.store.query.resultset.AnyResultSet; 11import tools.refinery.store.query.resultset.AnyResultSet;
12import tools.refinery.store.query.resultset.ResultSet; 12import tools.refinery.store.query.resultset.ResultSet;
13 13
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/ModelQueryBuilder.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/ModelQueryBuilder.java
index 332e6381..71e2c5bf 100644
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/ModelQueryBuilder.java
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/ModelQueryBuilder.java
@@ -7,8 +7,8 @@ package tools.refinery.store.query;
7 7
8import tools.refinery.store.adapter.ModelAdapterBuilder; 8import tools.refinery.store.adapter.ModelAdapterBuilder;
9import tools.refinery.store.model.ModelStore; 9import tools.refinery.store.model.ModelStore;
10import tools.refinery.store.query.dnf.AnyQuery; 10import tools.refinery.logic.dnf.AnyQuery;
11import tools.refinery.store.query.rewriter.DnfRewriter; 11import tools.refinery.logic.rewriter.DnfRewriter;
12 12
13import java.util.Collection; 13import java.util.Collection;
14import java.util.List; 14import java.util.List;
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/ModelQueryStoreAdapter.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/ModelQueryStoreAdapter.java
index 8b67c5c1..fec8c999 100644
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/ModelQueryStoreAdapter.java
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/ModelQueryStoreAdapter.java
@@ -7,8 +7,8 @@ package tools.refinery.store.query;
7 7
8import tools.refinery.store.adapter.ModelStoreAdapter; 8import tools.refinery.store.adapter.ModelStoreAdapter;
9import tools.refinery.store.model.Model; 9import tools.refinery.store.model.Model;
10import tools.refinery.store.query.dnf.AnyQuery; 10import tools.refinery.logic.dnf.AnyQuery;
11import tools.refinery.store.query.dnf.Query; 11import tools.refinery.logic.dnf.Query;
12import tools.refinery.store.query.view.AnySymbolView; 12import tools.refinery.store.query.view.AnySymbolView;
13 13
14import java.util.Collection; 14import java.util.Collection;
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/AbstractQueryBuilder.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/AbstractQueryBuilder.java
deleted file mode 100644
index 2a3e3ce0..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/AbstractQueryBuilder.java
+++ /dev/null
@@ -1,175 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.dnf;
7
8import tools.refinery.store.query.dnf.callback.*;
9import tools.refinery.store.query.literal.Literal;
10import tools.refinery.store.query.term.NodeVariable;
11import tools.refinery.store.query.term.ParameterDirection;
12import tools.refinery.store.query.term.Variable;
13
14import java.util.Collection;
15import java.util.List;
16import java.util.Set;
17
18public abstract class AbstractQueryBuilder<T extends AbstractQueryBuilder<T>> {
19 protected final DnfBuilder dnfBuilder;
20
21 protected AbstractQueryBuilder(DnfBuilder dnfBuilder) {
22 this.dnfBuilder = dnfBuilder;
23 }
24
25 protected abstract T self();
26
27 public NodeVariable parameter() {
28 return dnfBuilder.parameter();
29 }
30
31 public NodeVariable parameter(String name) {
32 return dnfBuilder.parameter(name);
33 }
34
35 public NodeVariable parameter(ParameterDirection direction) {
36 return dnfBuilder.parameter(direction);
37 }
38
39 public NodeVariable parameter(String name, ParameterDirection direction) {
40 return dnfBuilder.parameter(name, direction);
41 }
42
43 public T parameter(NodeVariable variable) {
44 dnfBuilder.parameter(variable);
45 return self();
46 }
47
48 public T parameter(NodeVariable variable, ParameterDirection direction) {
49 dnfBuilder.parameter(variable, direction);
50 return self();
51 }
52
53 public T parameters(NodeVariable... variables) {
54 dnfBuilder.parameters(variables);
55 return self();
56 }
57
58 public T parameters(List<NodeVariable> variables) {
59 dnfBuilder.parameters(variables);
60 return self();
61 }
62
63 public T parameters(List<NodeVariable> variables, ParameterDirection direction) {
64 dnfBuilder.parameters(variables, direction);
65 return self();
66 }
67
68 public T symbolicParameters(List<SymbolicParameter> parameters) {
69 dnfBuilder.symbolicParameters(parameters);
70 return self();
71 }
72
73 public T functionalDependencies(Collection<FunctionalDependency<Variable>> functionalDependencies) {
74 dnfBuilder.functionalDependencies(functionalDependencies);
75 return self();
76 }
77
78 public T functionalDependency(FunctionalDependency<Variable> functionalDependency) {
79 dnfBuilder.functionalDependency(functionalDependency);
80 return self();
81 }
82
83 public T functionalDependency(Set<? extends Variable> forEach, Set<? extends Variable> unique) {
84 dnfBuilder.functionalDependency(forEach, unique);
85 return self();
86 }
87
88 public T clause(ClauseCallback0 callback) {
89 dnfBuilder.clause(callback);
90 return self();
91 }
92
93 public T clause(ClauseCallback1Data0 callback) {
94 dnfBuilder.clause(callback);
95 return self();
96 }
97
98 public <U1> T clause(Class<U1> type1, ClauseCallback1Data1<U1> callback) {
99 dnfBuilder.clause(type1, callback);
100 return self();
101 }
102
103 public T clause(ClauseCallback2Data0 callback) {
104 dnfBuilder.clause(callback);
105 return self();
106 }
107
108 public <U1> T clause(Class<U1> type1, ClauseCallback2Data1<U1> callback) {
109 dnfBuilder.clause(type1, callback);
110 return self();
111 }
112
113 public <U1, U2> T clause(Class<U1> type1, Class<U2> type2, ClauseCallback2Data2<U1, U2> callback) {
114 dnfBuilder.clause(type1, type2, callback);
115 return self();
116 }
117
118 public T clause(ClauseCallback3Data0 callback) {
119 dnfBuilder.clause(callback);
120 return self();
121 }
122
123 public <U1> T clause(Class<U1> type1, ClauseCallback3Data1<U1> callback) {
124 dnfBuilder.clause(type1, callback);
125 return self();
126 }
127
128 public <U1, U2> T clause(Class<U1> type1, Class<U2> type2, ClauseCallback3Data2<U1, U2> callback) {
129 dnfBuilder.clause(type1, type2, callback);
130 return self();
131 }
132
133 public <U1, U2, U3> T clause(Class<U1> type1, Class<U2> type2, Class<U3> type3,
134 ClauseCallback3Data3<U1, U2, U3> callback) {
135 dnfBuilder.clause(type1, type2, type3, callback);
136 return self();
137 }
138
139 public T clause(ClauseCallback4Data0 callback) {
140 dnfBuilder.clause(callback);
141 return self();
142 }
143
144 public <U1> T clause(Class<U1> type1, ClauseCallback4Data1<U1> callback) {
145 dnfBuilder.clause(type1, callback);
146 return self();
147 }
148
149 public <U1, U2> T clause(Class<U1> type1, Class<U2> type2, ClauseCallback4Data2<U1, U2> callback) {
150 dnfBuilder.clause(type1, type2, callback);
151 return self();
152 }
153
154 public <U1, U2, U3> T clause(Class<U1> type1, Class<U2> type2, Class<U3> type3,
155 ClauseCallback4Data3<U1, U2, U3> callback) {
156 dnfBuilder.clause(type1, type2, type3, callback);
157 return self();
158 }
159
160 public <U1, U2, U3, U4> T clause(Class<U1> type1, Class<U2> type2, Class<U3> type3, Class<U4> type4,
161 ClauseCallback4Data4<U1, U2, U3, U4> callback) {
162 dnfBuilder.clause(type1, type2, type3, type4, callback);
163 return self();
164 }
165
166 public T clause(Literal... literals) {
167 dnfBuilder.clause(literals);
168 return self();
169 }
170
171 public T clause(Collection<? extends Literal> literals) {
172 dnfBuilder.clause(literals);
173 return self();
174 }
175}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/AnyQuery.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/AnyQuery.java
deleted file mode 100644
index 5e28af68..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/AnyQuery.java
+++ /dev/null
@@ -1,16 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.dnf;
7
8public sealed interface AnyQuery permits Query {
9 String name();
10
11 int arity();
12
13 Class<?> valueType();
14
15 Dnf getDnf();
16}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/ClausePostProcessor.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/ClausePostProcessor.java
deleted file mode 100644
index 8800a155..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/ClausePostProcessor.java
+++ /dev/null
@@ -1,362 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.dnf;
7
8import org.jetbrains.annotations.NotNull;
9import tools.refinery.store.query.Constraint;
10import tools.refinery.store.query.InvalidQueryException;
11import tools.refinery.store.query.literal.*;
12import tools.refinery.store.query.substitution.MapBasedSubstitution;
13import tools.refinery.store.query.substitution.StatelessSubstitution;
14import tools.refinery.store.query.substitution.Substitution;
15import tools.refinery.store.query.term.ParameterDirection;
16import tools.refinery.store.query.term.Variable;
17
18import java.util.*;
19import java.util.function.Function;
20
21class ClausePostProcessor {
22 private final Map<Variable, ParameterInfo> parameters;
23 private final List<Literal> literals;
24 private final Map<Variable, Variable> representatives = new LinkedHashMap<>();
25 private final Map<Variable, Set<Variable>> equivalencePartition = new HashMap<>();
26 private List<Literal> substitutedLiterals;
27 private final Set<Variable> existentiallyQuantifiedVariables = new LinkedHashSet<>();
28 private Set<Variable> positiveVariables;
29 private Map<Variable, Set<SortableLiteral>> variableToLiteralInputMap;
30 private PriorityQueue<SortableLiteral> literalsWithAllInputsBound;
31 private LinkedHashSet<Literal> topologicallySortedLiterals;
32
33 public ClausePostProcessor(Map<Variable, ParameterInfo> parameters, List<Literal> literals) {
34 this.parameters = parameters;
35 this.literals = literals;
36 }
37
38 public Result postProcessClause() {
39 mergeEquivalentNodeVariables();
40 substitutedLiterals = new ArrayList<>(literals.size());
41 keepParameterEquivalences();
42 substituteLiterals();
43 computeExistentiallyQuantifiedVariables();
44 computePositiveVariables();
45 validatePositiveRepresentatives();
46 validatePrivateVariables();
47 topologicallySortLiterals();
48 var filteredLiterals = new ArrayList<Literal>(topologicallySortedLiterals.size());
49 for (var literal : topologicallySortedLiterals) {
50 var reducedLiteral = literal.reduce();
51 if (BooleanLiteral.FALSE.equals(reducedLiteral)) {
52 return ConstantResult.ALWAYS_FALSE;
53 } else if (!BooleanLiteral.TRUE.equals(reducedLiteral)) {
54 filteredLiterals.add(reducedLiteral);
55 }
56 }
57 if (filteredLiterals.isEmpty()) {
58 return ConstantResult.ALWAYS_TRUE;
59 }
60 if (hasContradictoryCall(filteredLiterals)) {
61 return ConstantResult.ALWAYS_FALSE;
62 }
63 var clause = new DnfClause(Collections.unmodifiableSet(positiveVariables),
64 Collections.unmodifiableList(filteredLiterals));
65 return new ClauseResult(clause);
66 }
67
68 private void mergeEquivalentNodeVariables() {
69 for (var literal : literals) {
70 if (isPositiveEquivalence(literal)) {
71 var equivalenceLiteral = (EquivalenceLiteral) literal;
72 mergeVariables(equivalenceLiteral.getLeft(), equivalenceLiteral.getRight());
73 }
74 }
75 }
76
77 private static boolean isPositiveEquivalence(Literal literal) {
78 return literal instanceof EquivalenceLiteral equivalenceLiteral && equivalenceLiteral.isPositive();
79 }
80
81 private void mergeVariables(Variable left, Variable right) {
82 var leftRepresentative = getRepresentative(left);
83 var rightRepresentative = getRepresentative(right);
84 var leftInfo = parameters.get(leftRepresentative);
85 var rightInfo = parameters.get(rightRepresentative);
86 if (leftInfo != null && (rightInfo == null || leftInfo.index() <= rightInfo.index())) {
87 // Prefer the variable occurring earlier in the parameter list as a representative.
88 doMergeVariables(leftRepresentative, rightRepresentative);
89 } else {
90 doMergeVariables(rightRepresentative, leftRepresentative);
91 }
92 }
93
94 private void doMergeVariables(Variable parentRepresentative, Variable newChildRepresentative) {
95 var parentSet = getEquivalentVariables(parentRepresentative);
96 var childSet = getEquivalentVariables(newChildRepresentative);
97 parentSet.addAll(childSet);
98 equivalencePartition.remove(newChildRepresentative);
99 for (var childEquivalentNodeVariable : childSet) {
100 representatives.put(childEquivalentNodeVariable, parentRepresentative);
101 }
102 }
103
104 private Variable getRepresentative(Variable variable) {
105 return representatives.computeIfAbsent(variable, Function.identity());
106 }
107
108 private Set<Variable> getEquivalentVariables(Variable variable) {
109 var representative = getRepresentative(variable);
110 if (!representative.equals(variable)) {
111 throw new AssertionError("NodeVariable %s already has a representative %s"
112 .formatted(variable, representative));
113 }
114 return equivalencePartition.computeIfAbsent(variable, key -> {
115 var set = new HashSet<Variable>(1);
116 set.add(key);
117 return set;
118 });
119 }
120
121 private void keepParameterEquivalences() {
122 for (var pair : representatives.entrySet()) {
123 var left = pair.getKey();
124 var right = pair.getValue();
125 if (!left.equals(right) && parameters.containsKey(left) && parameters.containsKey(right)) {
126 substitutedLiterals.add(new EquivalenceLiteral(true, left, right));
127 }
128 }
129 }
130
131 private void substituteLiterals() {
132 Substitution substitution;
133 if (representatives.isEmpty()) {
134 substitution = null;
135 } else {
136 substitution = new MapBasedSubstitution(Collections.unmodifiableMap(representatives),
137 StatelessSubstitution.IDENTITY);
138 }
139 for (var literal : literals) {
140 if (isPositiveEquivalence(literal)) {
141 // We already retained all equivalences that cannot be replaced with substitutions in
142 // {@link#keepParameterEquivalences()}.
143 continue;
144 }
145 var substitutedLiteral = substitution == null ? literal : literal.substitute(substitution);
146 substitutedLiterals.add(substitutedLiteral);
147 }
148 }
149
150 private void computeExistentiallyQuantifiedVariables() {
151 for (var literal : substitutedLiterals) {
152 existentiallyQuantifiedVariables.addAll(literal.getOutputVariables());
153 }
154 }
155
156 private void computePositiveVariables() {
157 positiveVariables = new LinkedHashSet<>();
158 for (var pair : parameters.entrySet()) {
159 var variable = pair.getKey();
160 if (pair.getValue().direction() == ParameterDirection.IN) {
161 // Inputs count as positive, because they are already bound when we evaluate literals.
162 positiveVariables.add(variable);
163 } else if (!existentiallyQuantifiedVariables.contains(variable)) {
164 throw new InvalidQueryException("Unbound %s parameter %s"
165 .formatted(ParameterDirection.OUT, variable));
166 }
167 }
168 positiveVariables.addAll(existentiallyQuantifiedVariables);
169 }
170
171 private void validatePositiveRepresentatives() {
172 for (var pair : equivalencePartition.entrySet()) {
173 var representative = pair.getKey();
174 if (!positiveVariables.contains(representative)) {
175 var variableSet = pair.getValue();
176 throw new InvalidQueryException("Variables %s were merged by equivalence but are not bound"
177 .formatted(variableSet));
178 }
179 }
180 }
181
182 private void validatePrivateVariables() {
183 var negativeVariablesMap = new HashMap<Variable, Literal>();
184 for (var literal : substitutedLiterals) {
185 for (var variable : literal.getPrivateVariables(positiveVariables)) {
186 var oldLiteral = negativeVariablesMap.put(variable, literal);
187 if (oldLiteral != null) {
188 throw new InvalidQueryException("Unbound variable %s appears in multiple literals %s and %s"
189 .formatted(variable, oldLiteral, literal));
190 }
191 }
192 }
193 }
194
195 private void topologicallySortLiterals() {
196 topologicallySortedLiterals = new LinkedHashSet<>(substitutedLiterals.size());
197 variableToLiteralInputMap = new HashMap<>();
198 literalsWithAllInputsBound = new PriorityQueue<>();
199 int size = substitutedLiterals.size();
200 for (int i = 0; i < size; i++) {
201 var literal = substitutedLiterals.get(i);
202 var sortableLiteral = new SortableLiteral(i, literal);
203 sortableLiteral.enqueue();
204 }
205 while (!literalsWithAllInputsBound.isEmpty()) {
206 var variable = literalsWithAllInputsBound.remove();
207 variable.addToSortedLiterals();
208 }
209 if (!variableToLiteralInputMap.isEmpty()) {
210 throw new InvalidQueryException("Unbound input variables %s"
211 .formatted(variableToLiteralInputMap.keySet()));
212 }
213 }
214
215 private boolean hasContradictoryCall(Collection<Literal> filteredLiterals) {
216 var positiveCalls = new HashMap<Constraint, Set<CallLiteral>>();
217 for (var literal : filteredLiterals) {
218 if (literal instanceof CallLiteral callLiteral && callLiteral.getPolarity() == CallPolarity.POSITIVE) {
219 var callsOfTarget = positiveCalls.computeIfAbsent(callLiteral.getTarget(), key -> new HashSet<>());
220 callsOfTarget.add(callLiteral);
221 }
222 }
223 for (var literal : filteredLiterals) {
224 if (literal instanceof CallLiteral callLiteral && callLiteral.getPolarity() == CallPolarity.NEGATIVE) {
225 var callsOfTarget = positiveCalls.get(callLiteral.getTarget());
226 if (contradicts(callLiteral, callsOfTarget)) {
227 return true;
228 }
229 }
230 }
231 return false;
232 }
233
234 private boolean contradicts(CallLiteral negativeCall, Collection<CallLiteral> positiveCalls) {
235 if (positiveCalls == null) {
236 return false;
237 }
238 for (var positiveCall : positiveCalls) {
239 if (contradicts(negativeCall, positiveCall)) {
240 return true;
241 }
242 }
243 return false;
244 }
245
246 private boolean contradicts(CallLiteral negativeCall, CallLiteral positiveCall) {
247 var privateVariables = negativeCall.getPrivateVariables(positiveVariables);
248 var negativeArguments = negativeCall.getArguments();
249 var positiveArguments = positiveCall.getArguments();
250 int arity = negativeArguments.size();
251 for (int i = 0; i < arity; i++) {
252 var negativeArgument = negativeArguments.get(i);
253 if (privateVariables.contains(negativeArgument)) {
254 continue;
255 }
256 var positiveArgument = positiveArguments.get(i);
257 if (!negativeArgument.equals(positiveArgument)) {
258 return false;
259 }
260 }
261 return true;
262 }
263
264 private class SortableLiteral implements Comparable<SortableLiteral> {
265 private final int index;
266 private final Literal literal;
267 private final Set<Variable> remainingInputs;
268
269 private SortableLiteral(int index, Literal literal) {
270 this.index = index;
271 this.literal = literal;
272 remainingInputs = new HashSet<>(literal.getInputVariables(positiveVariables));
273 for (var pair : parameters.entrySet()) {
274 if (pair.getValue().direction() == ParameterDirection.IN) {
275 remainingInputs.remove(pair.getKey());
276 }
277 }
278 }
279
280 public void enqueue() {
281 if (allInputsBound()) {
282 addToAllInputsBoundQueue();
283 } else {
284 addToVariableToLiteralInputMap();
285 }
286 }
287
288 private void bindVariable(Variable input) {
289 if (!remainingInputs.remove(input)) {
290 throw new AssertionError("Already processed input %s of literal %s".formatted(input, literal));
291 }
292 if (allInputsBound()) {
293 addToAllInputsBoundQueue();
294 }
295 }
296
297 private boolean allInputsBound() {
298 return remainingInputs.isEmpty();
299 }
300
301 private void addToVariableToLiteralInputMap() {
302 for (var inputVariable : remainingInputs) {
303 var literalSetForInput = variableToLiteralInputMap.computeIfAbsent(
304 inputVariable, key -> new HashSet<>());
305 literalSetForInput.add(this);
306 }
307 }
308
309 private void addToAllInputsBoundQueue() {
310 literalsWithAllInputsBound.add(this);
311 }
312
313 public void addToSortedLiterals() {
314 if (!allInputsBound()) {
315 throw new AssertionError("Inputs %s of %s are not yet bound".formatted(remainingInputs, literal));
316 }
317 // Add literal if we haven't yet added a duplicate of this literal.
318 topologicallySortedLiterals.add(literal);
319 for (var variable : literal.getOutputVariables()) {
320 var literalSetForInput = variableToLiteralInputMap.remove(variable);
321 if (literalSetForInput == null) {
322 continue;
323 }
324 for (var targetSortableLiteral : literalSetForInput) {
325 targetSortableLiteral.bindVariable(variable);
326 }
327 }
328 }
329
330 @Override
331 public int compareTo(@NotNull ClausePostProcessor.SortableLiteral other) {
332 return Integer.compare(index, other.index);
333 }
334
335 @Override
336 public boolean equals(Object o) {
337 if (this == o) return true;
338 if (o == null || getClass() != o.getClass()) return false;
339 SortableLiteral that = (SortableLiteral) o;
340 return index == that.index && Objects.equals(literal, that.literal);
341 }
342
343 @Override
344 public int hashCode() {
345 return Objects.hash(index, literal);
346 }
347 }
348
349 public sealed interface Result permits ClauseResult, ConstantResult {
350 }
351
352 public record ClauseResult(DnfClause clause) implements Result {
353 }
354
355 public enum ConstantResult implements Result {
356 ALWAYS_TRUE,
357 ALWAYS_FALSE
358 }
359
360 public record ParameterInfo(ParameterDirection direction, int index) {
361 }
362}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/Dnf.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/Dnf.java
deleted file mode 100644
index 86a1b6b2..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/Dnf.java
+++ /dev/null
@@ -1,235 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.dnf;
7
8import tools.refinery.store.query.Constraint;
9import tools.refinery.store.query.InvalidQueryException;
10import tools.refinery.store.query.equality.DnfEqualityChecker;
11import tools.refinery.store.query.equality.LiteralEqualityHelper;
12import tools.refinery.store.query.equality.SubstitutingLiteralEqualityHelper;
13import tools.refinery.store.query.equality.SubstitutingLiteralHashCodeHelper;
14import tools.refinery.store.query.literal.Reduction;
15import tools.refinery.store.query.term.Parameter;
16import tools.refinery.store.query.term.Variable;
17
18import java.util.Collection;
19import java.util.Collections;
20import java.util.List;
21import java.util.Set;
22import java.util.function.Consumer;
23import java.util.stream.Collectors;
24
25public final class Dnf implements Constraint {
26 private static final String INDENTATION = " ";
27
28 private final String name;
29 private final String uniqueName;
30 private final List<SymbolicParameter> symbolicParameters;
31 private final List<FunctionalDependency<Variable>> functionalDependencies;
32 private final List<DnfClause> clauses;
33
34 Dnf(String name, List<SymbolicParameter> symbolicParameters,
35 List<FunctionalDependency<Variable>> functionalDependencies, List<DnfClause> clauses) {
36 validateFunctionalDependencies(symbolicParameters, functionalDependencies);
37 this.name = name;
38 this.uniqueName = DnfUtils.generateUniqueName(name);
39 this.symbolicParameters = symbolicParameters;
40 this.functionalDependencies = functionalDependencies;
41 this.clauses = clauses;
42 }
43
44 private static void validateFunctionalDependencies(
45 Collection<SymbolicParameter> symbolicParameters,
46 Collection<FunctionalDependency<Variable>> functionalDependencies) {
47 var parameterSet = symbolicParameters.stream().map(SymbolicParameter::getVariable).collect(Collectors.toSet());
48 for (var functionalDependency : functionalDependencies) {
49 validateParameters(symbolicParameters, parameterSet, functionalDependency.forEach(), functionalDependency);
50 validateParameters(symbolicParameters, parameterSet, functionalDependency.unique(), functionalDependency);
51 }
52 }
53
54 private static void validateParameters(Collection<SymbolicParameter> symbolicParameters,
55 Set<Variable> parameterSet, Collection<Variable> toValidate,
56 FunctionalDependency<Variable> functionalDependency) {
57 for (var variable : toValidate) {
58 if (!parameterSet.contains(variable)) {
59 throw new InvalidQueryException(
60 "Variable %s of functional dependency %s does not appear in the parameter list %s"
61 .formatted(variable, functionalDependency, symbolicParameters));
62 }
63 }
64 }
65
66 @Override
67 public String name() {
68 return name == null ? uniqueName : name;
69 }
70
71 public boolean isExplicitlyNamed() {
72 return name != null;
73 }
74
75 public String getUniqueName() {
76 return uniqueName;
77 }
78
79 public List<SymbolicParameter> getSymbolicParameters() {
80 return symbolicParameters;
81 }
82
83 public List<Parameter> getParameters() {
84 return Collections.unmodifiableList(symbolicParameters);
85 }
86
87 public List<FunctionalDependency<Variable>> getFunctionalDependencies() {
88 return functionalDependencies;
89 }
90
91 @Override
92 public int arity() {
93 return symbolicParameters.size();
94 }
95
96 public List<DnfClause> getClauses() {
97 return clauses;
98 }
99
100 public RelationalQuery asRelation() {
101 return new RelationalQuery(this);
102 }
103
104 public <T> FunctionalQuery<T> asFunction(Class<T> type) {
105 return new FunctionalQuery<>(this, type);
106 }
107
108 @Override
109 public Reduction getReduction() {
110 if (clauses.isEmpty()) {
111 return Reduction.ALWAYS_FALSE;
112 }
113 for (var clause : clauses) {
114 if (clause.literals().isEmpty()) {
115 return Reduction.ALWAYS_TRUE;
116 }
117 }
118 return Reduction.NOT_REDUCIBLE;
119 }
120
121 public boolean equalsWithSubstitution(DnfEqualityChecker callEqualityChecker, Dnf other) {
122 if (arity() != other.arity()) {
123 return false;
124 }
125 for (int i = 0; i < arity(); i++) {
126 if (!symbolicParameters.get(i).getDirection().equals(other.getSymbolicParameters().get(i).getDirection())) {
127 return false;
128 }
129 }
130 int numClauses = clauses.size();
131 if (numClauses != other.clauses.size()) {
132 return false;
133 }
134 for (int i = 0; i < numClauses; i++) {
135 var literalEqualityHelper = new SubstitutingLiteralEqualityHelper(callEqualityChecker, symbolicParameters,
136 other.symbolicParameters);
137 if (!clauses.get(i).equalsWithSubstitution(literalEqualityHelper, other.clauses.get(i))) {
138 return false;
139 }
140 }
141 return true;
142 }
143
144 @Override
145 public boolean equals(LiteralEqualityHelper helper, Constraint other) {
146 if (other instanceof Dnf otherDnf) {
147 return helper.dnfEqual(this, otherDnf);
148 }
149 return false;
150 }
151
152 public int hashCodeWithSubstitution() {
153 var helper = new SubstitutingLiteralHashCodeHelper();
154 int result = 0;
155 for (var symbolicParameter : symbolicParameters) {
156 result = result * 31 + symbolicParameter.hashCodeWithSubstitution(helper);
157 }
158 for (var clause : clauses) {
159 result = result * 31 + clause.hashCodeWithSubstitution(helper);
160 }
161 return result;
162 }
163
164 @Override
165 public String toString() {
166 return "%s/%d".formatted(name(), arity());
167 }
168
169 @Override
170 public String toReferenceString() {
171 return "@Dnf " + name();
172 }
173
174 public String toDefinitionString() {
175 var builder = new StringBuilder();
176 builder.append("pred ").append(name()).append("(");
177 var parameterIterator = symbolicParameters.iterator();
178 if (parameterIterator.hasNext()) {
179 builder.append(parameterIterator.next());
180 while (parameterIterator.hasNext()) {
181 builder.append(", ").append(parameterIterator.next());
182 }
183 }
184 builder.append(") <->");
185 var clauseIterator = clauses.iterator();
186 if (clauseIterator.hasNext()) {
187 appendClause(clauseIterator.next(), builder);
188 while (clauseIterator.hasNext()) {
189 builder.append("\n;");
190 appendClause(clauseIterator.next(), builder);
191 }
192 } else {
193 builder.append("\n").append(INDENTATION).append("<no clauses>");
194 }
195 builder.append(".\n");
196 return builder.toString();
197 }
198
199 private static void appendClause(DnfClause clause, StringBuilder builder) {
200 var iterator = clause.literals().iterator();
201 if (!iterator.hasNext()) {
202 builder.append("\n").append(INDENTATION).append("<empty>");
203 return;
204 }
205 builder.append("\n").append(INDENTATION).append(iterator.next());
206 while (iterator.hasNext()) {
207 builder.append(",\n").append(INDENTATION).append(iterator.next());
208 }
209 }
210
211 public static DnfBuilder builder() {
212 return builder(null);
213 }
214
215 public static DnfBuilder builder(String name) {
216 return new DnfBuilder(name);
217 }
218
219 public static DnfBuilder builderFrom(Dnf original) {
220 var builder = builder(original.name());
221 builder.symbolicParameters(original.getSymbolicParameters());
222 builder.functionalDependencies(original.getFunctionalDependencies());
223 return builder;
224 }
225
226 public static Dnf of(Consumer<DnfBuilder> callback) {
227 return of(null, callback);
228 }
229
230 public static Dnf of(String name, Consumer<DnfBuilder> callback) {
231 var builder = builder(name);
232 callback.accept(builder);
233 return builder.build();
234 }
235}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/DnfBuilder.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/DnfBuilder.java
deleted file mode 100644
index 0f9fd366..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/DnfBuilder.java
+++ /dev/null
@@ -1,225 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.dnf;
7
8import tools.refinery.store.query.InvalidQueryException;
9import tools.refinery.store.query.dnf.callback.*;
10import tools.refinery.store.query.literal.Literal;
11import tools.refinery.store.query.term.*;
12
13import java.util.*;
14
15@SuppressWarnings("UnusedReturnValue")
16public final class DnfBuilder {
17 private final String name;
18 private final Set<Variable> parameterVariables = new LinkedHashSet<>();
19 private final List<SymbolicParameter> parameters = new ArrayList<>();
20 private final List<FunctionalDependency<Variable>> functionalDependencies = new ArrayList<>();
21 private final List<List<Literal>> clauses = new ArrayList<>();
22
23 DnfBuilder(String name) {
24 this.name = name;
25 }
26
27 public NodeVariable parameter() {
28 return parameter((String) null);
29 }
30
31 public NodeVariable parameter(String name) {
32 return parameter(name, ParameterDirection.OUT);
33 }
34
35 public NodeVariable parameter(ParameterDirection direction) {
36 return parameter((String) null, direction);
37 }
38
39 public NodeVariable parameter(String name, ParameterDirection direction) {
40 var variable = Variable.of(name);
41 parameter(variable, direction);
42 return variable;
43 }
44
45 public <T> DataVariable<T> parameter(Class<T> type) {
46 return parameter(null, type);
47 }
48
49 public <T> DataVariable<T> parameter(String name, Class<T> type) {
50 return parameter(name, type, ParameterDirection.OUT);
51 }
52
53 public <T> DataVariable<T> parameter(Class<T> type, ParameterDirection direction) {
54 return parameter(null, type, direction);
55 }
56
57 public <T> DataVariable<T> parameter(String name, Class<T> type, ParameterDirection direction) {
58 var variable = Variable.of(name, type);
59 parameter(variable, direction);
60 return variable;
61 }
62
63 public Variable parameter(Parameter parameter) {
64 return parameter(null, parameter);
65 }
66
67 public Variable parameter(String name, Parameter parameter) {
68 var type = parameter.tryGetType();
69 if (type.isPresent()) {
70 return parameter(name, type.get(), parameter.getDirection());
71 }
72 return parameter(name, parameter.getDirection());
73 }
74
75 public DnfBuilder parameter(Variable variable) {
76 return parameter(variable, ParameterDirection.OUT);
77 }
78
79 public DnfBuilder parameter(Variable variable, ParameterDirection direction) {
80 return symbolicParameter(new SymbolicParameter(variable, direction));
81 }
82
83 public DnfBuilder parameters(Variable... variables) {
84 return parameters(List.of(variables));
85 }
86
87 public DnfBuilder parameters(Collection<? extends Variable> variables) {
88 return parameters(variables, ParameterDirection.OUT);
89 }
90
91 public DnfBuilder parameters(Collection<? extends Variable> variables, ParameterDirection direction) {
92 for (var variable : variables) {
93 parameter(variable, direction);
94 }
95 return this;
96 }
97
98 public DnfBuilder symbolicParameter(SymbolicParameter symbolicParameter) {
99 var variable = symbolicParameter.getVariable();
100 if (!parameterVariables.add(variable)) {
101 throw new InvalidQueryException("Variable %s is already on the parameter list %s"
102 .formatted(variable, parameters));
103 }
104 parameters.add(symbolicParameter);
105 return this;
106 }
107
108 public DnfBuilder symbolicParameters(SymbolicParameter... symbolicParameters) {
109 return symbolicParameters(List.of(symbolicParameters));
110 }
111
112 public DnfBuilder symbolicParameters(Collection<SymbolicParameter> symbolicParameters) {
113 for (var symbolicParameter : symbolicParameters) {
114 symbolicParameter(symbolicParameter);
115 }
116 return this;
117 }
118
119 public DnfBuilder functionalDependencies(Collection<FunctionalDependency<Variable>> functionalDependencies) {
120 this.functionalDependencies.addAll(functionalDependencies);
121 return this;
122 }
123
124 public DnfBuilder functionalDependency(FunctionalDependency<Variable> functionalDependency) {
125 functionalDependencies.add(functionalDependency);
126 return this;
127 }
128
129 public DnfBuilder functionalDependency(Set<? extends Variable> forEach, Set<? extends Variable> unique) {
130 return functionalDependency(new FunctionalDependency<>(Set.copyOf(forEach), Set.copyOf(unique)));
131 }
132
133 public DnfBuilder clause(ClauseCallback0 callback) {
134 return clause(callback.toLiterals());
135 }
136
137 public DnfBuilder clause(ClauseCallback1Data0 callback) {
138 return clause(callback.toLiterals(Variable.of("v1")));
139 }
140
141 public <T> DnfBuilder clause(Class<T> type1, ClauseCallback1Data1<T> callback) {
142 return clause(callback.toLiterals(Variable.of("d1", type1)));
143 }
144
145 public DnfBuilder clause(ClauseCallback2Data0 callback) {
146 return clause(callback.toLiterals(Variable.of("v1"), Variable.of("v2")));
147 }
148
149 public <T> DnfBuilder clause(Class<T> type1, ClauseCallback2Data1<T> callback) {
150 return clause(callback.toLiterals(Variable.of("v1"), Variable.of("d1", type1)));
151 }
152
153 public <T1, T2> DnfBuilder clause(Class<T1> type1, Class<T2> type2, ClauseCallback2Data2<T1, T2> callback) {
154 return clause(callback.toLiterals(Variable.of("d1", type1), Variable.of("d2", type2)));
155 }
156
157 public DnfBuilder clause(ClauseCallback3Data0 callback) {
158 return clause(callback.toLiterals(Variable.of("v1"), Variable.of("v2"), Variable.of("v3")));
159 }
160
161 public <T> DnfBuilder clause(Class<T> type1, ClauseCallback3Data1<T> callback) {
162 return clause(callback.toLiterals(Variable.of("v1"), Variable.of("v2"), Variable.of("d1", type1)));
163 }
164
165 public <T1, T2> DnfBuilder clause(Class<T1> type1, Class<T2> type2, ClauseCallback3Data2<T1, T2> callback) {
166 return clause(callback.toLiterals(Variable.of("v1"), Variable.of("d1", type1), Variable.of("d2", type2)));
167 }
168
169 public <T1, T2, T3> DnfBuilder clause(Class<T1> type1, Class<T2> type2, Class<T3> type3,
170 ClauseCallback3Data3<T1, T2, T3> callback) {
171 return clause(callback.toLiterals(Variable.of("d1", type1), Variable.of("d2", type2),
172 Variable.of("d3", type3)));
173 }
174
175 public DnfBuilder clause(ClauseCallback4Data0 callback) {
176 return clause(callback.toLiterals(Variable.of("v1"), Variable.of("v2"), Variable.of("v3"), Variable.of("v4")));
177 }
178
179 public <T> DnfBuilder clause(Class<T> type1, ClauseCallback4Data1<T> callback) {
180 return clause(callback.toLiterals(Variable.of("v1"), Variable.of("v2"), Variable.of("v3"), Variable.of("d1",
181 type1)));
182 }
183
184 public <T1, T2> DnfBuilder clause(Class<T1> type1, Class<T2> type2, ClauseCallback4Data2<T1, T2> callback) {
185 return clause(callback.toLiterals(Variable.of("v1"), Variable.of("v2"), Variable.of("d1", type1),
186 Variable.of("d2", type2)));
187 }
188
189 public <T1, T2, T3> DnfBuilder clause(Class<T1> type1, Class<T2> type2, Class<T3> type3,
190 ClauseCallback4Data3<T1, T2, T3> callback) {
191 return clause(callback.toLiterals(Variable.of("v1"), Variable.of("d1", type1), Variable.of("d2", type2),
192 Variable.of("d3", type3)));
193 }
194
195 public <T1, T2, T3, T4> DnfBuilder clause(Class<T1> type1, Class<T2> type2, Class<T3> type3, Class<T4> type4,
196 ClauseCallback4Data4<T1, T2, T3, T4> callback) {
197 return clause(callback.toLiterals(Variable.of("d1", type1), Variable.of("d2", type2),
198 Variable.of("d3", type3), Variable.of("d4", type4)));
199 }
200
201 public DnfBuilder clause(Literal... literals) {
202 clause(List.of(literals));
203 return this;
204 }
205
206 public DnfBuilder clause(Collection<? extends Literal> literals) {
207 clauses.add(List.copyOf(literals));
208 return this;
209 }
210
211 <T> void output(DataVariable<T> outputVariable) {
212 // Copy parameter variables to exclude the newly added {@code outputVariable}.
213 var fromParameters = Set.copyOf(parameterVariables);
214 parameter(outputVariable, ParameterDirection.OUT);
215 functionalDependency(fromParameters, Set.of(outputVariable));
216 }
217
218 public Dnf build() {
219 var postProcessor = new DnfPostProcessor(parameters, clauses);
220 var postProcessedClauses = postProcessor.postProcessClauses();
221 return new Dnf(name, Collections.unmodifiableList(parameters),
222 Collections.unmodifiableList(functionalDependencies),
223 Collections.unmodifiableList(postProcessedClauses));
224 }
225}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/DnfClause.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/DnfClause.java
deleted file mode 100644
index 94327bad..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/DnfClause.java
+++ /dev/null
@@ -1,37 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.dnf;
7
8import tools.refinery.store.query.equality.LiteralEqualityHelper;
9import tools.refinery.store.query.equality.LiteralHashCodeHelper;
10import tools.refinery.store.query.literal.Literal;
11import tools.refinery.store.query.term.Variable;
12
13import java.util.List;
14import java.util.Set;
15
16public record DnfClause(Set<Variable> positiveVariables, List<Literal> literals) {
17 public boolean equalsWithSubstitution(LiteralEqualityHelper helper, DnfClause other) {
18 int size = literals.size();
19 if (size != other.literals.size()) {
20 return false;
21 }
22 for (int i = 0; i < size; i++) {
23 if (!literals.get(i).equalsWithSubstitution(helper, other.literals.get(i))) {
24 return false;
25 }
26 }
27 return true;
28 }
29
30 public int hashCodeWithSubstitution(LiteralHashCodeHelper helper) {
31 int result = 0;
32 for (var literal : literals) {
33 result = result * 31 + literal.hashCodeWithSubstitution(helper);
34 }
35 return result;
36 }
37}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/DnfPostProcessor.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/DnfPostProcessor.java
deleted file mode 100644
index 50236642..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/DnfPostProcessor.java
+++ /dev/null
@@ -1,112 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.dnf;
7
8import tools.refinery.store.query.InvalidQueryException;
9import tools.refinery.store.query.equality.DnfEqualityChecker;
10import tools.refinery.store.query.equality.SubstitutingLiteralEqualityHelper;
11import tools.refinery.store.query.equality.SubstitutingLiteralHashCodeHelper;
12import tools.refinery.store.query.literal.Literal;
13import tools.refinery.store.query.term.ParameterDirection;
14import tools.refinery.store.query.term.Variable;
15
16import java.util.*;
17
18class DnfPostProcessor {
19 private final List<SymbolicParameter> parameters;
20 private final List<List<Literal>> clauses;
21
22 public DnfPostProcessor(List<SymbolicParameter> parameters, List<List<Literal>> clauses) {
23 this.parameters = parameters;
24 this.clauses = clauses;
25 }
26
27 public List<DnfClause> postProcessClauses() {
28 var parameterInfoMap = getParameterInfoMap();
29 var postProcessedClauses = new LinkedHashSet<CanonicalClause>(clauses.size());
30 int index = 0;
31 for (var literals : clauses) {
32 var postProcessor = new ClausePostProcessor(parameterInfoMap, literals);
33 ClausePostProcessor.Result result;
34 try {
35 result = postProcessor.postProcessClause();
36 } catch (InvalidQueryException e) {
37 throw new InvalidClauseException(index, e);
38 }
39 if (result instanceof ClausePostProcessor.ClauseResult clauseResult) {
40 postProcessedClauses.add(new CanonicalClause(clauseResult.clause()));
41 } else if (result instanceof ClausePostProcessor.ConstantResult constantResult) {
42 switch (constantResult) {
43 case ALWAYS_TRUE -> {
44 var inputVariables = getInputVariables();
45 return List.of(new DnfClause(inputVariables, List.of()));
46 }
47 case ALWAYS_FALSE -> {
48 // Skip this clause because it can never match.
49 }
50 default -> throw new IllegalStateException("Unexpected ClausePostProcessor.ConstantResult: " +
51 constantResult);
52 }
53 } else {
54 throw new IllegalStateException("Unexpected ClausePostProcessor.Result: " + result);
55 }
56 index++;
57 }
58 return postProcessedClauses.stream().map(CanonicalClause::getDnfClause).toList();
59 }
60
61 private Map<Variable, ClausePostProcessor.ParameterInfo> getParameterInfoMap() {
62 var mutableParameterInfoMap = new LinkedHashMap<Variable, ClausePostProcessor.ParameterInfo>();
63 int arity = parameters.size();
64 for (int i = 0; i < arity; i++) {
65 var parameter = parameters.get(i);
66 mutableParameterInfoMap.put(parameter.getVariable(),
67 new ClausePostProcessor.ParameterInfo(parameter.getDirection(), i));
68 }
69 return Collections.unmodifiableMap(mutableParameterInfoMap);
70 }
71
72 private Set<Variable> getInputVariables() {
73 var inputParameters = new LinkedHashSet<Variable>();
74 for (var parameter : parameters) {
75 if (parameter.getDirection() == ParameterDirection.IN) {
76 inputParameters.add(parameter.getVariable());
77 }
78 }
79 return Collections.unmodifiableSet(inputParameters);
80 }
81
82 private class CanonicalClause {
83 private final DnfClause dnfClause;
84
85 public CanonicalClause(DnfClause dnfClause) {
86 this.dnfClause = dnfClause;
87 }
88
89 public DnfClause getDnfClause() {
90 return dnfClause;
91 }
92
93 @Override
94 public boolean equals(Object obj) {
95 if (this == obj) {
96 return true;
97 }
98 if (obj == null || getClass() != obj.getClass()) {
99 return false;
100 }
101 var otherCanonicalClause = (CanonicalClause) obj;
102 var helper = new SubstitutingLiteralEqualityHelper(DnfEqualityChecker.DEFAULT, parameters, parameters);
103 return dnfClause.equalsWithSubstitution(helper, otherCanonicalClause.dnfClause);
104 }
105
106 @Override
107 public int hashCode() {
108 var helper = new SubstitutingLiteralHashCodeHelper(parameters);
109 return dnfClause.hashCodeWithSubstitution(helper);
110 }
111 }
112}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/DnfUtils.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/DnfUtils.java
deleted file mode 100644
index 65ab3634..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/DnfUtils.java
+++ /dev/null
@@ -1,24 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.dnf;
7
8import java.util.UUID;
9
10public final class DnfUtils {
11 private DnfUtils() {
12 throw new IllegalStateException("This is a static utility class and should not be instantiated directly");
13 }
14
15 public static String generateUniqueName(String originalName) {
16 UUID uuid = UUID.randomUUID();
17 String uniqueString = "_" + uuid.toString().replace('-', '_');
18 if (originalName == null) {
19 return uniqueString;
20 } else {
21 return originalName + uniqueString;
22 }
23 }
24}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/FunctionalDependency.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/FunctionalDependency.java
deleted file mode 100644
index aef07ee3..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/FunctionalDependency.java
+++ /dev/null
@@ -1,22 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.dnf;
7
8import tools.refinery.store.query.InvalidQueryException;
9
10import java.util.HashSet;
11import java.util.Set;
12
13public record FunctionalDependency<T>(Set<T> forEach, Set<T> unique) {
14 public FunctionalDependency {
15 var uniqueForEach = new HashSet<>(unique);
16 uniqueForEach.retainAll(forEach);
17 if (!uniqueForEach.isEmpty()) {
18 throw new InvalidQueryException("Variables %s appear on both sides of the functional dependency"
19 .formatted(uniqueForEach));
20 }
21 }
22}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/FunctionalQuery.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/FunctionalQuery.java
deleted file mode 100644
index 225f6844..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/FunctionalQuery.java
+++ /dev/null
@@ -1,110 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.dnf;
7
8import tools.refinery.store.query.InvalidQueryException;
9import tools.refinery.store.query.literal.CallPolarity;
10import tools.refinery.store.query.term.Aggregator;
11import tools.refinery.store.query.term.AssignedValue;
12import tools.refinery.store.query.term.NodeVariable;
13import tools.refinery.store.query.term.Variable;
14
15import java.util.ArrayList;
16import java.util.List;
17import java.util.Objects;
18
19public final class FunctionalQuery<T> extends Query<T> {
20 private final Class<T> type;
21
22 FunctionalQuery(Dnf dnf, Class<T> type) {
23 super(dnf);
24 var parameters = dnf.getSymbolicParameters();
25 int outputIndex = dnf.arity() - 1;
26 for (int i = 0; i < outputIndex; i++) {
27 var parameter = parameters.get(i);
28 var parameterType = parameter.tryGetType();
29 if (parameterType.isPresent()) {
30 throw new InvalidQueryException("Expected parameter %s of %s to be a node variable, got %s instead"
31 .formatted(parameter, dnf, parameterType.get().getName()));
32 }
33 }
34 var outputParameter = parameters.get(outputIndex);
35 var outputParameterType = outputParameter.tryGetType();
36 if (outputParameterType.isEmpty() || !outputParameterType.get().equals(type)) {
37 throw new InvalidQueryException("Expected parameter %s of %s to be %s, but got %s instead".formatted(
38 outputParameter, dnf, type, outputParameterType.map(Class::getName).orElse("node")));
39 }
40 this.type = type;
41 }
42
43 @Override
44 public int arity() {
45 return getDnf().arity() - 1;
46 }
47
48 @Override
49 public Class<T> valueType() {
50 return type;
51 }
52
53 @Override
54 public T defaultValue() {
55 return null;
56 }
57
58 @Override
59 protected FunctionalQuery<T> withDnfInternal(Dnf newDnf) {
60 return newDnf.asFunction(type);
61 }
62
63 @Override
64 public FunctionalQuery<T> withDnf(Dnf newDnf) {
65 return (FunctionalQuery<T>) super.withDnf(newDnf);
66 }
67
68 public AssignedValue<T> call(List<NodeVariable> arguments) {
69 return targetVariable -> {
70 var argumentsWithTarget = new ArrayList<Variable>(arguments.size() + 1);
71 argumentsWithTarget.addAll(arguments);
72 argumentsWithTarget.add(targetVariable);
73 return getDnf().call(CallPolarity.POSITIVE, argumentsWithTarget);
74 };
75 }
76
77 public AssignedValue<T> call(NodeVariable... arguments) {
78 return call(List.of(arguments));
79 }
80
81 public <R> AssignedValue<R> aggregate(Aggregator<R, T> aggregator, List<NodeVariable> arguments) {
82 return targetVariable -> {
83 var placeholderVariable = Variable.of(type);
84 var argumentsWithPlaceholder = new ArrayList<Variable>(arguments.size() + 1);
85 argumentsWithPlaceholder.addAll(arguments);
86 argumentsWithPlaceholder.add(placeholderVariable);
87 return getDnf()
88 .aggregateBy(placeholderVariable, aggregator, argumentsWithPlaceholder)
89 .toLiteral(targetVariable);
90 };
91 }
92
93 public <R> AssignedValue<R> aggregate(Aggregator<R, T> aggregator, NodeVariable... arguments) {
94 return aggregate(aggregator, List.of(arguments));
95 }
96
97 @Override
98 public boolean equals(Object o) {
99 if (this == o) return true;
100 if (o == null || getClass() != o.getClass()) return false;
101 if (!super.equals(o)) return false;
102 FunctionalQuery<?> that = (FunctionalQuery<?>) o;
103 return Objects.equals(type, that.type);
104 }
105
106 @Override
107 public int hashCode() {
108 return Objects.hash(super.hashCode(), type);
109 }
110}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/FunctionalQueryBuilder.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/FunctionalQueryBuilder.java
deleted file mode 100644
index d1cd7ba8..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/FunctionalQueryBuilder.java
+++ /dev/null
@@ -1,29 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.dnf;
7
8import tools.refinery.store.query.term.DataVariable;
9
10public final class FunctionalQueryBuilder<T> extends AbstractQueryBuilder<FunctionalQueryBuilder<T>> {
11 private final DataVariable<T> outputVariable;
12 private final Class<T> type;
13
14 FunctionalQueryBuilder(DataVariable<T> outputVariable, DnfBuilder dnfBuilder, Class<T> type) {
15 super(dnfBuilder);
16 this.outputVariable = outputVariable;
17 this.type = type;
18 }
19
20 @Override
21 protected FunctionalQueryBuilder<T> self() {
22 return this;
23 }
24
25 public FunctionalQuery<T> build() {
26 dnfBuilder.output(outputVariable);
27 return dnfBuilder.build().asFunction(type);
28 }
29}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/InvalidClauseException.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/InvalidClauseException.java
deleted file mode 100644
index 747574b9..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/InvalidClauseException.java
+++ /dev/null
@@ -1,35 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.dnf;
7
8import tools.refinery.store.query.InvalidQueryException;
9
10public class InvalidClauseException extends InvalidQueryException {
11 private final int clauseIndex;
12
13 public InvalidClauseException(int clauseIndex) {
14 this.clauseIndex = clauseIndex;
15 }
16
17 public InvalidClauseException(int clauseIndex, String message) {
18 super(message);
19 this.clauseIndex = clauseIndex;
20 }
21
22 public InvalidClauseException(int clauseIndex, String message, Throwable cause) {
23 super(message, cause);
24 this.clauseIndex = clauseIndex;
25 }
26
27 public InvalidClauseException(int clauseIndex, Throwable cause) {
28 super(cause);
29 this.clauseIndex = clauseIndex;
30 }
31
32 public int getClauseIndex() {
33 return clauseIndex;
34 }
35}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/Query.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/Query.java
deleted file mode 100644
index 83fe6ccd..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/Query.java
+++ /dev/null
@@ -1,202 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.dnf;
7
8import tools.refinery.store.query.dnf.callback.*;
9import tools.refinery.store.query.term.ParameterDirection;
10import tools.refinery.store.query.term.Variable;
11
12import java.util.Objects;
13
14public abstract sealed class Query<T> implements AnyQuery permits FunctionalQuery, RelationalQuery {
15 private static final String OUTPUT_VARIABLE_NAME = "output";
16
17 private final Dnf dnf;
18
19 protected Query(Dnf dnf) {
20 for (var parameter : dnf.getSymbolicParameters()) {
21 if (parameter.getDirection() != ParameterDirection.OUT) {
22 throw new IllegalArgumentException("Query parameter %s with direction %s is not allowed"
23 .formatted(parameter.getVariable(), parameter.getDirection()));
24 }
25 }
26 this.dnf = dnf;
27 }
28
29 @Override
30 public String name() {
31 return dnf.name();
32 }
33
34 @Override
35 public Dnf getDnf() {
36 return dnf;
37 }
38
39 // Allow redeclaration of the method with refined return type.
40 @SuppressWarnings("squid:S3038")
41 @Override
42 public abstract Class<T> valueType();
43
44 public abstract T defaultValue();
45
46 public Query<T> withDnf(Dnf newDnf) {
47 if (dnf.equals(newDnf)) {
48 return this;
49 }
50 int arity = dnf.arity();
51 if (newDnf.arity() != arity) {
52 throw new IllegalArgumentException("Arity of %s and %s do not match".formatted(dnf, newDnf));
53 }
54 var parameters = dnf.getParameters();
55 var newParameters = newDnf.getParameters();
56 for (int i = 0; i < arity; i++) {
57 var parameter = parameters.get(i);
58 var newParameter = newParameters.get(i);
59 if (!parameter.matches(newParameter)) {
60 throw new IllegalArgumentException("Parameter #%d mismatch: %s does not match %s"
61 .formatted(i, parameter, newParameter));
62 }
63 }
64 return withDnfInternal(newDnf);
65 }
66
67 protected abstract Query<T> withDnfInternal(Dnf newDnf);
68
69 @Override
70 public boolean equals(Object o) {
71 if (this == o) return true;
72 if (o == null || getClass() != o.getClass()) return false;
73 Query<?> that = (Query<?>) o;
74 return Objects.equals(dnf, that.dnf);
75 }
76
77 @Override
78 public int hashCode() {
79 return Objects.hash(dnf);
80 }
81
82 @Override
83 public String toString() {
84 return dnf.toString();
85 }
86
87 public static QueryBuilder builder() {
88 return builder(null);
89 }
90
91 public static QueryBuilder builder(String name) {
92 return new QueryBuilder(name);
93 }
94
95 public static RelationalQuery of(QueryCallback0 callback) {
96 return of(null, callback);
97 }
98
99 public static RelationalQuery of(String name, QueryCallback0 callback) {
100 var builder = builder(name);
101 callback.accept(builder);
102 return builder.build();
103 }
104
105 public static RelationalQuery of(QueryCallback1 callback) {
106 return of(null, callback);
107 }
108
109 public static RelationalQuery of(String name, QueryCallback1 callback) {
110 var builder = builder(name);
111 callback.accept(builder, builder.parameter("p1"));
112 return builder.build();
113 }
114
115 public static RelationalQuery of(QueryCallback2 callback) {
116 return of(null, callback);
117 }
118
119 public static RelationalQuery of(String name, QueryCallback2 callback) {
120 var builder = builder(name);
121 callback.accept(builder, builder.parameter("p1"), builder.parameter("p2"));
122 return builder.build();
123 }
124
125 public static RelationalQuery of(QueryCallback3 callback) {
126 return of(null, callback);
127 }
128
129 public static RelationalQuery of(String name, QueryCallback3 callback) {
130 var builder = builder(name);
131 callback.accept(builder, builder.parameter("p1"), builder.parameter("p2"), builder.parameter("p3"));
132 return builder.build();
133 }
134
135 public static RelationalQuery of(QueryCallback4 callback) {
136 return of(null, callback);
137 }
138
139 public static RelationalQuery of(String name, QueryCallback4 callback) {
140 var builder = builder(name);
141 callback.accept(builder, builder.parameter("p1"), builder.parameter("p2"), builder.parameter("p3"),
142 builder.parameter("p4"));
143 return builder.build();
144 }
145
146 public static <T> FunctionalQuery<T> of(Class<T> type, FunctionalQueryCallback0<T> callback) {
147 return of(null, type, callback);
148 }
149
150 public static <T> FunctionalQuery<T> of(String name, Class<T> type, FunctionalQueryCallback0<T> callback) {
151 var outputVariable = Variable.of(OUTPUT_VARIABLE_NAME, type);
152 var builder = builder(name).output(outputVariable);
153 callback.accept(builder, outputVariable);
154 return builder.build();
155 }
156
157 public static <T> FunctionalQuery<T> of(Class<T> type, FunctionalQueryCallback1<T> callback) {
158 return of(null, type, callback);
159 }
160
161 public static <T> FunctionalQuery<T> of(String name, Class<T> type, FunctionalQueryCallback1<T> callback) {
162 var outputVariable = Variable.of(OUTPUT_VARIABLE_NAME, type);
163 var builder = builder(name).output(outputVariable);
164 callback.accept(builder, builder.parameter("p1"), outputVariable);
165 return builder.build();
166 }
167
168 public static <T> FunctionalQuery<T> of(Class<T> type, FunctionalQueryCallback2<T> callback) {
169 return of(null, type, callback);
170 }
171
172 public static <T> FunctionalQuery<T> of(String name, Class<T> type, FunctionalQueryCallback2<T> callback) {
173 var outputVariable = Variable.of(OUTPUT_VARIABLE_NAME, type);
174 var builder = builder(name).output(outputVariable);
175 callback.accept(builder, builder.parameter("p1"), builder.parameter("p2"), outputVariable);
176 return builder.build();
177 }
178
179 public static <T> FunctionalQuery<T> of(Class<T> type, FunctionalQueryCallback3<T> callback) {
180 return of(null, type, callback);
181 }
182
183 public static <T> FunctionalQuery<T> of(String name, Class<T> type, FunctionalQueryCallback3<T> callback) {
184 var outputVariable = Variable.of(OUTPUT_VARIABLE_NAME, type);
185 var builder = builder(name).output(outputVariable);
186 callback.accept(builder, builder.parameter("p1"), builder.parameter("p2"), builder.parameter("p3"),
187 outputVariable);
188 return builder.build();
189 }
190
191 public static <T> FunctionalQuery<T> of(Class<T> type, FunctionalQueryCallback4<T> callback) {
192 return of(null, type, callback);
193 }
194
195 public static <T> FunctionalQuery<T> of(String name, Class<T> type, FunctionalQueryCallback4<T> callback) {
196 var outputVariable = Variable.of(OUTPUT_VARIABLE_NAME, type);
197 var builder = builder(name).output(outputVariable);
198 callback.accept(builder, builder.parameter("p1"), builder.parameter("p2"), builder.parameter("p3"),
199 builder.parameter("p4"), outputVariable);
200 return builder.build();
201 }
202}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/QueryBuilder.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/QueryBuilder.java
deleted file mode 100644
index 138911bc..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/QueryBuilder.java
+++ /dev/null
@@ -1,27 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.dnf;
7
8import tools.refinery.store.query.term.DataVariable;
9
10public final class QueryBuilder extends AbstractQueryBuilder<QueryBuilder> {
11 QueryBuilder(String name) {
12 super(Dnf.builder(name));
13 }
14
15 @Override
16 protected QueryBuilder self() {
17 return this;
18 }
19
20 public <T> FunctionalQueryBuilder<T> output(DataVariable<T> outputVariable) {
21 return new FunctionalQueryBuilder<>(outputVariable, dnfBuilder, outputVariable.getType());
22 }
23
24 public RelationalQuery build() {
25 return dnfBuilder.build().asRelation();
26 }
27}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/RelationalQuery.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/RelationalQuery.java
deleted file mode 100644
index 98f71e11..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/RelationalQuery.java
+++ /dev/null
@@ -1,77 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.dnf;
7
8import tools.refinery.store.query.InvalidQueryException;
9import tools.refinery.store.query.literal.CallLiteral;
10import tools.refinery.store.query.literal.CallPolarity;
11import tools.refinery.store.query.term.AssignedValue;
12import tools.refinery.store.query.term.NodeVariable;
13
14import java.util.Collections;
15import java.util.List;
16
17public final class RelationalQuery extends Query<Boolean> {
18 RelationalQuery(Dnf dnf) {
19 super(dnf);
20 for (var parameter : dnf.getSymbolicParameters()) {
21 var parameterType = parameter.tryGetType();
22 if (parameterType.isPresent()) {
23 throw new InvalidQueryException("Expected parameter %s of %s to be a node variable, got %s instead"
24 .formatted(parameter, dnf, parameterType.get().getName()));
25 }
26 }
27 }
28
29 @Override
30 public int arity() {
31 return getDnf().arity();
32 }
33
34 @Override
35 public Class<Boolean> valueType() {
36 return Boolean.class;
37 }
38
39 @Override
40 public Boolean defaultValue() {
41 return false;
42 }
43
44 @Override
45 protected RelationalQuery withDnfInternal(Dnf newDnf) {
46 return newDnf.asRelation();
47 }
48
49 @Override
50 public RelationalQuery withDnf(Dnf newDnf) {
51 return (RelationalQuery) super.withDnf(newDnf);
52 }
53
54 public CallLiteral call(CallPolarity polarity, List<NodeVariable> arguments) {
55 return getDnf().call(polarity, Collections.unmodifiableList(arguments));
56 }
57
58 public CallLiteral call(CallPolarity polarity, NodeVariable... arguments) {
59 return getDnf().call(polarity, arguments);
60 }
61
62 public CallLiteral call(NodeVariable... arguments) {
63 return getDnf().call(arguments);
64 }
65
66 public CallLiteral callTransitive(NodeVariable left, NodeVariable right) {
67 return getDnf().callTransitive(left, right);
68 }
69
70 public AssignedValue<Integer> count(List<NodeVariable> arguments) {
71 return getDnf().count(Collections.unmodifiableList(arguments));
72 }
73
74 public AssignedValue<Integer> count(NodeVariable... arguments) {
75 return getDnf().count(arguments);
76 }
77}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/SymbolicParameter.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/SymbolicParameter.java
deleted file mode 100644
index fe9cefcc..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/SymbolicParameter.java
+++ /dev/null
@@ -1,53 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.dnf;
7
8import tools.refinery.store.query.equality.LiteralHashCodeHelper;
9import tools.refinery.store.query.term.Parameter;
10import tools.refinery.store.query.term.ParameterDirection;
11import tools.refinery.store.query.term.Variable;
12
13import java.util.Objects;
14
15public final class SymbolicParameter extends Parameter {
16 private final Variable variable;
17
18 public SymbolicParameter(Variable variable, ParameterDirection direction) {
19 super(variable.tryGetType().orElse(null), direction);
20 this.variable = variable;
21 }
22
23 public Variable getVariable() {
24 return variable;
25 }
26
27 public int hashCodeWithSubstitution(LiteralHashCodeHelper helper) {
28 return Objects.hash(super.hashCode(), helper.getVariableHashCode(variable));
29 }
30
31 @Override
32 public String toString() {
33 var direction = getDirection();
34 if (direction == ParameterDirection.OUT) {
35 return variable.toString();
36 }
37 return "%s %s".formatted(getDirection(), variable);
38 }
39
40 @Override
41 public boolean equals(Object o) {
42 if (this == o) return true;
43 if (o == null || getClass() != o.getClass()) return false;
44 if (!super.equals(o)) return false;
45 SymbolicParameter that = (SymbolicParameter) o;
46 return Objects.equals(variable, that.variable);
47 }
48
49 @Override
50 public int hashCode() {
51 return Objects.hash(super.hashCode(), variable);
52 }
53}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/ClauseCallback0.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/ClauseCallback0.java
deleted file mode 100644
index d98dda2e..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/ClauseCallback0.java
+++ /dev/null
@@ -1,15 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.dnf.callback;
7
8import tools.refinery.store.query.literal.Literal;
9
10import java.util.Collection;
11
12@FunctionalInterface
13public interface ClauseCallback0 {
14 Collection<Literal> toLiterals();
15}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/ClauseCallback1Data0.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/ClauseCallback1Data0.java
deleted file mode 100644
index 4c01a527..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/ClauseCallback1Data0.java
+++ /dev/null
@@ -1,16 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.dnf.callback;
7
8import tools.refinery.store.query.literal.Literal;
9import tools.refinery.store.query.term.NodeVariable;
10
11import java.util.Collection;
12
13@FunctionalInterface
14public interface ClauseCallback1Data0 {
15 Collection<Literal> toLiterals(NodeVariable v1);
16}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/ClauseCallback1Data1.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/ClauseCallback1Data1.java
deleted file mode 100644
index 2c0cb6eb..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/ClauseCallback1Data1.java
+++ /dev/null
@@ -1,16 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.dnf.callback;
7
8import tools.refinery.store.query.literal.Literal;
9import tools.refinery.store.query.term.DataVariable;
10
11import java.util.Collection;
12
13@FunctionalInterface
14public interface ClauseCallback1Data1<T> {
15 Collection<Literal> toLiterals(DataVariable<T> d1);
16}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/ClauseCallback2Data0.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/ClauseCallback2Data0.java
deleted file mode 100644
index d764bdba..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/ClauseCallback2Data0.java
+++ /dev/null
@@ -1,16 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.dnf.callback;
7
8import tools.refinery.store.query.literal.Literal;
9import tools.refinery.store.query.term.NodeVariable;
10
11import java.util.Collection;
12
13@FunctionalInterface
14public interface ClauseCallback2Data0 {
15 Collection<Literal> toLiterals(NodeVariable v1, NodeVariable v2);
16}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/ClauseCallback2Data1.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/ClauseCallback2Data1.java
deleted file mode 100644
index 140af03a..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/ClauseCallback2Data1.java
+++ /dev/null
@@ -1,17 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.dnf.callback;
7
8import tools.refinery.store.query.literal.Literal;
9import tools.refinery.store.query.term.DataVariable;
10import tools.refinery.store.query.term.NodeVariable;
11
12import java.util.Collection;
13
14@FunctionalInterface
15public interface ClauseCallback2Data1<T> {
16 Collection<Literal> toLiterals(NodeVariable v1, DataVariable<T> x1);
17}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/ClauseCallback2Data2.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/ClauseCallback2Data2.java
deleted file mode 100644
index bfc8637c..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/ClauseCallback2Data2.java
+++ /dev/null
@@ -1,16 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.dnf.callback;
7
8import tools.refinery.store.query.literal.Literal;
9import tools.refinery.store.query.term.DataVariable;
10
11import java.util.Collection;
12
13@FunctionalInterface
14public interface ClauseCallback2Data2<T1, T2> {
15 Collection<Literal> toLiterals(DataVariable<T1> x1, DataVariable<T2> x2);
16}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/ClauseCallback3Data0.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/ClauseCallback3Data0.java
deleted file mode 100644
index 074df65b..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/ClauseCallback3Data0.java
+++ /dev/null
@@ -1,16 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.dnf.callback;
7
8import tools.refinery.store.query.literal.Literal;
9import tools.refinery.store.query.term.NodeVariable;
10
11import java.util.Collection;
12
13@FunctionalInterface
14public interface ClauseCallback3Data0 {
15 Collection<Literal> toLiterals(NodeVariable v1, NodeVariable v2, NodeVariable v3);
16}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/ClauseCallback3Data1.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/ClauseCallback3Data1.java
deleted file mode 100644
index 24ba5187..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/ClauseCallback3Data1.java
+++ /dev/null
@@ -1,17 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.dnf.callback;
7
8import tools.refinery.store.query.literal.Literal;
9import tools.refinery.store.query.term.DataVariable;
10import tools.refinery.store.query.term.NodeVariable;
11
12import java.util.Collection;
13
14@FunctionalInterface
15public interface ClauseCallback3Data1<T> {
16 Collection<Literal> toLiterals(NodeVariable v1, NodeVariable v2, DataVariable<T> d1);
17}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/ClauseCallback3Data2.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/ClauseCallback3Data2.java
deleted file mode 100644
index 2a2e837a..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/ClauseCallback3Data2.java
+++ /dev/null
@@ -1,17 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.dnf.callback;
7
8import tools.refinery.store.query.literal.Literal;
9import tools.refinery.store.query.term.DataVariable;
10import tools.refinery.store.query.term.NodeVariable;
11
12import java.util.Collection;
13
14@FunctionalInterface
15public interface ClauseCallback3Data2<T1, T2> {
16 Collection<Literal> toLiterals(NodeVariable v1, DataVariable<T1> d1, DataVariable<T2> d2);
17}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/ClauseCallback3Data3.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/ClauseCallback3Data3.java
deleted file mode 100644
index 8f4bdd01..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/ClauseCallback3Data3.java
+++ /dev/null
@@ -1,16 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.dnf.callback;
7
8import tools.refinery.store.query.literal.Literal;
9import tools.refinery.store.query.term.DataVariable;
10
11import java.util.Collection;
12
13@FunctionalInterface
14public interface ClauseCallback3Data3<T1, T2, T3> {
15 Collection<Literal> toLiterals(DataVariable<T1> d1, DataVariable<T2> d2, DataVariable<T3> d3);
16}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/ClauseCallback4Data0.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/ClauseCallback4Data0.java
deleted file mode 100644
index ed0f87b2..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/ClauseCallback4Data0.java
+++ /dev/null
@@ -1,16 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.dnf.callback;
7
8import tools.refinery.store.query.literal.Literal;
9import tools.refinery.store.query.term.NodeVariable;
10
11import java.util.Collection;
12
13@FunctionalInterface
14public interface ClauseCallback4Data0 {
15 Collection<Literal> toLiterals(NodeVariable v1, NodeVariable v2, NodeVariable v3, NodeVariable v4);
16}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/ClauseCallback4Data1.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/ClauseCallback4Data1.java
deleted file mode 100644
index 9b27e2e1..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/ClauseCallback4Data1.java
+++ /dev/null
@@ -1,17 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.dnf.callback;
7
8import tools.refinery.store.query.literal.Literal;
9import tools.refinery.store.query.term.DataVariable;
10import tools.refinery.store.query.term.NodeVariable;
11
12import java.util.Collection;
13
14@FunctionalInterface
15public interface ClauseCallback4Data1<T> {
16 Collection<Literal> toLiterals(NodeVariable v1, NodeVariable v2, NodeVariable v3, DataVariable<T> d1);
17}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/ClauseCallback4Data2.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/ClauseCallback4Data2.java
deleted file mode 100644
index cbc4808e..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/ClauseCallback4Data2.java
+++ /dev/null
@@ -1,17 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.dnf.callback;
7
8import tools.refinery.store.query.literal.Literal;
9import tools.refinery.store.query.term.DataVariable;
10import tools.refinery.store.query.term.NodeVariable;
11
12import java.util.Collection;
13
14@FunctionalInterface
15public interface ClauseCallback4Data2<T1, T2> {
16 Collection<Literal> toLiterals(NodeVariable v1, NodeVariable v2, DataVariable<T1> d1, DataVariable<T2> d2);
17}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/ClauseCallback4Data3.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/ClauseCallback4Data3.java
deleted file mode 100644
index a6258f36..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/ClauseCallback4Data3.java
+++ /dev/null
@@ -1,17 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.dnf.callback;
7
8import tools.refinery.store.query.literal.Literal;
9import tools.refinery.store.query.term.DataVariable;
10import tools.refinery.store.query.term.NodeVariable;
11
12import java.util.Collection;
13
14@FunctionalInterface
15public interface ClauseCallback4Data3<T1, T2, T3> {
16 Collection<Literal> toLiterals(NodeVariable v1, DataVariable<T1> d1, DataVariable<T2> d2, DataVariable<T3> d3);
17}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/ClauseCallback4Data4.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/ClauseCallback4Data4.java
deleted file mode 100644
index b52a911a..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/ClauseCallback4Data4.java
+++ /dev/null
@@ -1,16 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.dnf.callback;
7
8import tools.refinery.store.query.literal.Literal;
9import tools.refinery.store.query.term.DataVariable;
10
11import java.util.Collection;
12
13@FunctionalInterface
14public interface ClauseCallback4Data4<T1, T2, T3, T4> {
15 Collection<Literal> toLiterals(DataVariable<T1> d1, DataVariable<T2> d2, DataVariable<T3> d3, DataVariable<T4> d4);
16}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/FunctionalQueryCallback0.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/FunctionalQueryCallback0.java
deleted file mode 100644
index 63b3eee6..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/FunctionalQueryCallback0.java
+++ /dev/null
@@ -1,14 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.dnf.callback;
7
8import tools.refinery.store.query.dnf.FunctionalQueryBuilder;
9import tools.refinery.store.query.term.DataVariable;
10
11@FunctionalInterface
12public interface FunctionalQueryCallback0<T> {
13 void accept(FunctionalQueryBuilder<T> builder, DataVariable<T> output);
14}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/FunctionalQueryCallback1.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/FunctionalQueryCallback1.java
deleted file mode 100644
index 1295a118..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/FunctionalQueryCallback1.java
+++ /dev/null
@@ -1,15 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.dnf.callback;
7
8import tools.refinery.store.query.dnf.FunctionalQueryBuilder;
9import tools.refinery.store.query.term.DataVariable;
10import tools.refinery.store.query.term.NodeVariable;
11
12@FunctionalInterface
13public interface FunctionalQueryCallback1<T> {
14 void accept(FunctionalQueryBuilder<T> builder, NodeVariable p1, DataVariable<T> output);
15}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/FunctionalQueryCallback2.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/FunctionalQueryCallback2.java
deleted file mode 100644
index d5b7f9ff..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/FunctionalQueryCallback2.java
+++ /dev/null
@@ -1,15 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.dnf.callback;
7
8import tools.refinery.store.query.dnf.FunctionalQueryBuilder;
9import tools.refinery.store.query.term.DataVariable;
10import tools.refinery.store.query.term.NodeVariable;
11
12@FunctionalInterface
13public interface FunctionalQueryCallback2<T> {
14 void accept(FunctionalQueryBuilder<T> builder, NodeVariable p1, NodeVariable p2, DataVariable<T> output);
15}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/FunctionalQueryCallback3.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/FunctionalQueryCallback3.java
deleted file mode 100644
index dc8404a0..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/FunctionalQueryCallback3.java
+++ /dev/null
@@ -1,16 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.dnf.callback;
7
8import tools.refinery.store.query.dnf.FunctionalQueryBuilder;
9import tools.refinery.store.query.term.DataVariable;
10import tools.refinery.store.query.term.NodeVariable;
11
12@FunctionalInterface
13public interface FunctionalQueryCallback3<T> {
14 void accept(FunctionalQueryBuilder<T> builder, NodeVariable p1, NodeVariable p2, NodeVariable p3,
15 DataVariable<T> output);
16}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/FunctionalQueryCallback4.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/FunctionalQueryCallback4.java
deleted file mode 100644
index b6d3ddb0..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/FunctionalQueryCallback4.java
+++ /dev/null
@@ -1,16 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.dnf.callback;
7
8import tools.refinery.store.query.dnf.FunctionalQueryBuilder;
9import tools.refinery.store.query.term.DataVariable;
10import tools.refinery.store.query.term.NodeVariable;
11
12@FunctionalInterface
13public interface FunctionalQueryCallback4<T> {
14 void accept(FunctionalQueryBuilder<T> builder, NodeVariable p1, NodeVariable p2, NodeVariable p3, NodeVariable p4,
15 DataVariable<T> output);
16}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/QueryCallback0.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/QueryCallback0.java
deleted file mode 100644
index 3cf1de48..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/QueryCallback0.java
+++ /dev/null
@@ -1,13 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.dnf.callback;
7
8import tools.refinery.store.query.dnf.QueryBuilder;
9
10@FunctionalInterface
11public interface QueryCallback0 {
12 void accept(QueryBuilder builder);
13}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/QueryCallback1.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/QueryCallback1.java
deleted file mode 100644
index 0a150955..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/QueryCallback1.java
+++ /dev/null
@@ -1,14 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.dnf.callback;
7
8import tools.refinery.store.query.dnf.QueryBuilder;
9import tools.refinery.store.query.term.NodeVariable;
10
11@FunctionalInterface
12public interface QueryCallback1 {
13 void accept(QueryBuilder builder, NodeVariable p1);
14}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/QueryCallback2.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/QueryCallback2.java
deleted file mode 100644
index 9493a7b4..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/QueryCallback2.java
+++ /dev/null
@@ -1,14 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.dnf.callback;
7
8import tools.refinery.store.query.dnf.QueryBuilder;
9import tools.refinery.store.query.term.NodeVariable;
10
11@FunctionalInterface
12public interface QueryCallback2 {
13 void accept(QueryBuilder builder, NodeVariable p1, NodeVariable p2);
14}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/QueryCallback3.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/QueryCallback3.java
deleted file mode 100644
index 358c7da7..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/QueryCallback3.java
+++ /dev/null
@@ -1,14 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.dnf.callback;
7
8import tools.refinery.store.query.dnf.QueryBuilder;
9import tools.refinery.store.query.term.NodeVariable;
10
11@FunctionalInterface
12public interface QueryCallback3 {
13 void accept(QueryBuilder builder, NodeVariable p1, NodeVariable p2, NodeVariable p3);
14}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/QueryCallback4.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/QueryCallback4.java
deleted file mode 100644
index 890dda16..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/QueryCallback4.java
+++ /dev/null
@@ -1,14 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.dnf.callback;
7
8import tools.refinery.store.query.dnf.QueryBuilder;
9import tools.refinery.store.query.term.NodeVariable;
10
11@FunctionalInterface
12public interface QueryCallback4 {
13 void accept(QueryBuilder builder, NodeVariable p1, NodeVariable p2, NodeVariable p3, NodeVariable p4);
14}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/equality/DeepDnfEqualityChecker.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/equality/DeepDnfEqualityChecker.java
deleted file mode 100644
index d6171314..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/equality/DeepDnfEqualityChecker.java
+++ /dev/null
@@ -1,77 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.equality;
7
8import tools.refinery.store.query.dnf.Dnf;
9import tools.refinery.store.query.dnf.DnfClause;
10import tools.refinery.store.query.dnf.SymbolicParameter;
11import tools.refinery.store.query.literal.Literal;
12import tools.refinery.store.util.CycleDetectingMapper;
13
14import java.util.List;
15
16public class DeepDnfEqualityChecker implements DnfEqualityChecker {
17 private final CycleDetectingMapper<Pair, Boolean> mapper = new CycleDetectingMapper<>(this::doCheckEqual);
18
19 @Override
20 public boolean dnfEqual(Dnf left, Dnf right) {
21 return mapper.map(new Pair(left, right));
22 }
23
24 public boolean dnfEqualRaw(List<SymbolicParameter> symbolicParameters,
25 List<? extends List<? extends Literal>> clauses, Dnf other) {
26 int arity = symbolicParameters.size();
27 if (arity != other.arity()) {
28 return false;
29 }
30 for (int i = 0; i < arity; i++) {
31 if (!symbolicParameters.get(i).getDirection().equals(other.getSymbolicParameters().get(i).getDirection())) {
32 return false;
33 }
34 }
35 int numClauses = clauses.size();
36 if (numClauses != other.getClauses().size()) {
37 return false;
38 }
39 for (int i = 0; i < numClauses; i++) {
40 var literalEqualityHelper = new SubstitutingLiteralEqualityHelper(this, symbolicParameters,
41 other.getSymbolicParameters());
42 if (!equalsWithSubstitutionRaw(literalEqualityHelper, clauses.get(i), other.getClauses().get(i))) {
43 return false;
44 }
45 }
46 return true;
47 }
48
49 private boolean equalsWithSubstitutionRaw(LiteralEqualityHelper helper, List<? extends Literal> literals,
50 DnfClause other) {
51 int size = literals.size();
52 if (size != other.literals().size()) {
53 return false;
54 }
55 for (int i = 0; i < size; i++) {
56 if (!literals.get(i).equalsWithSubstitution(helper, other.literals().get(i))) {
57 return false;
58 }
59 }
60 return true;
61 }
62
63 protected boolean doCheckEqual(Pair pair) {
64 return pair.left.equalsWithSubstitution(this, pair.right);
65 }
66
67 protected List<Pair> getInProgress() {
68 return mapper.getInProgress();
69 }
70
71 protected record Pair(Dnf left, Dnf right) {
72 @Override
73 public String toString() {
74 return "(%s, %s)".formatted(left.name(), right.name());
75 }
76 }
77}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/equality/DnfEqualityChecker.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/equality/DnfEqualityChecker.java
deleted file mode 100644
index e2cfd79b..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/equality/DnfEqualityChecker.java
+++ /dev/null
@@ -1,17 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.equality;
7
8import tools.refinery.store.query.dnf.Dnf;
9
10import java.util.Objects;
11
12@FunctionalInterface
13public interface DnfEqualityChecker {
14 DnfEqualityChecker DEFAULT = Objects::equals;
15
16 boolean dnfEqual(Dnf left, Dnf right);
17}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/equality/LiteralEqualityHelper.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/equality/LiteralEqualityHelper.java
deleted file mode 100644
index 5abc76ce..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/equality/LiteralEqualityHelper.java
+++ /dev/null
@@ -1,27 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.equality;
7
8import tools.refinery.store.query.dnf.Dnf;
9import tools.refinery.store.query.term.Variable;
10
11import java.util.Objects;
12
13public interface LiteralEqualityHelper extends DnfEqualityChecker {
14 LiteralEqualityHelper DEFAULT = new LiteralEqualityHelper() {
15 @Override
16 public boolean variableEqual(Variable left, Variable right) {
17 return Objects.equals(left, right);
18 }
19
20 @Override
21 public boolean dnfEqual(Dnf left, Dnf right) {
22 return DnfEqualityChecker.DEFAULT.dnfEqual(left, right);
23 }
24 };
25
26 boolean variableEqual(Variable left, Variable right);
27}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/equality/LiteralHashCodeHelper.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/equality/LiteralHashCodeHelper.java
deleted file mode 100644
index 5495160a..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/equality/LiteralHashCodeHelper.java
+++ /dev/null
@@ -1,17 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.equality;
7
8import tools.refinery.store.query.term.Variable;
9
10import java.util.Objects;
11
12@FunctionalInterface
13public interface LiteralHashCodeHelper {
14 LiteralHashCodeHelper DEFAULT = Objects::hashCode;
15
16 int getVariableHashCode(Variable variable);
17}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/equality/SubstitutingLiteralEqualityHelper.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/equality/SubstitutingLiteralEqualityHelper.java
deleted file mode 100644
index 50a79e07..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/equality/SubstitutingLiteralEqualityHelper.java
+++ /dev/null
@@ -1,59 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.equality;
7
8import tools.refinery.store.query.dnf.Dnf;
9import tools.refinery.store.query.dnf.SymbolicParameter;
10import tools.refinery.store.query.term.Variable;
11
12import java.util.HashMap;
13import java.util.List;
14import java.util.Map;
15
16public class SubstitutingLiteralEqualityHelper implements LiteralEqualityHelper {
17 private final DnfEqualityChecker dnfEqualityChecker;
18 private final Map<Variable, Variable> leftToRight;
19 private final Map<Variable, Variable> rightToLeft;
20
21 public SubstitutingLiteralEqualityHelper(DnfEqualityChecker dnfEqualityChecker,
22 List<SymbolicParameter> leftParameters,
23 List<SymbolicParameter> rightParameters) {
24 this.dnfEqualityChecker = dnfEqualityChecker;
25 var arity = leftParameters.size();
26 if (arity != rightParameters.size()) {
27 throw new IllegalArgumentException("Parameter lists have unequal length");
28 }
29 leftToRight = new HashMap<>(arity);
30 rightToLeft = new HashMap<>(arity);
31 for (int i = 0; i < arity; i++) {
32 if (!variableEqual(leftParameters.get(i).getVariable(), rightParameters.get(i).getVariable())) {
33 throw new IllegalArgumentException("Parameter lists cannot be unified: duplicate parameter " + i);
34 }
35 }
36 }
37
38 @Override
39 public boolean dnfEqual(Dnf left, Dnf right) {
40 return dnfEqualityChecker.dnfEqual(left, right);
41 }
42
43 @Override
44 public boolean variableEqual(Variable left, Variable right) {
45 if (left.tryGetType().equals(right.tryGetType()) &&
46 checkMapping(leftToRight, left, right) &&
47 checkMapping(rightToLeft, right, left)) {
48 leftToRight.put(left, right);
49 rightToLeft.put(right, left);
50 return true;
51 }
52 return false;
53 }
54
55 private static boolean checkMapping(Map<Variable, Variable> map, Variable key, Variable expectedValue) {
56 var currentValue = map.get(key);
57 return currentValue == null || currentValue.equals(expectedValue);
58 }
59}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/equality/SubstitutingLiteralHashCodeHelper.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/equality/SubstitutingLiteralHashCodeHelper.java
deleted file mode 100644
index 754f6976..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/equality/SubstitutingLiteralHashCodeHelper.java
+++ /dev/null
@@ -1,42 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.equality;
7
8import tools.refinery.store.query.dnf.SymbolicParameter;
9import tools.refinery.store.query.term.Variable;
10
11import java.util.LinkedHashMap;
12import java.util.List;
13import java.util.Map;
14
15public class SubstitutingLiteralHashCodeHelper implements LiteralHashCodeHelper {
16 private final Map<Variable, Integer> assignedHashCodes = new LinkedHashMap<>();
17
18 // 0 is for {@code null}, so we start with 1.
19 private int next = 1;
20
21 public SubstitutingLiteralHashCodeHelper() {
22 this(List.of());
23 }
24
25 public SubstitutingLiteralHashCodeHelper(List<SymbolicParameter> parameters) {
26 for (var parameter : parameters) {
27 getVariableHashCode(parameter.getVariable());
28 }
29 }
30
31 @Override
32 public int getVariableHashCode(Variable variable) {
33 if (variable == null) {
34 return 0;
35 }
36 return assignedHashCodes.computeIfAbsent(variable, key -> {
37 int sequenceNumber = next;
38 next++;
39 return variable.hashCodeWithSubstitution(sequenceNumber);
40 });
41 }
42}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/AbstractCallLiteral.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/AbstractCallLiteral.java
deleted file mode 100644
index 0e99d441..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/AbstractCallLiteral.java
+++ /dev/null
@@ -1,135 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.literal;
7
8import tools.refinery.store.query.Constraint;
9import tools.refinery.store.query.InvalidQueryException;
10import tools.refinery.store.query.equality.LiteralEqualityHelper;
11import tools.refinery.store.query.equality.LiteralHashCodeHelper;
12import tools.refinery.store.query.substitution.Substitution;
13import tools.refinery.store.query.term.ParameterDirection;
14import tools.refinery.store.query.term.Variable;
15
16import java.util.*;
17
18// {@link Object#equals(Object)} is implemented by {@link AbstractLiteral}.
19@SuppressWarnings("squid:S2160")
20public abstract class AbstractCallLiteral extends AbstractLiteral {
21 private final Constraint target;
22 private final List<Variable> arguments;
23 private final Set<Variable> inArguments;
24 private final Set<Variable> outArguments;
25
26 // Use exhaustive switch over enums.
27 @SuppressWarnings("squid:S1301")
28 protected AbstractCallLiteral(Constraint target, List<Variable> arguments) {
29 int arity = target.arity();
30 if (arguments.size() != arity) {
31 throw new InvalidQueryException("%s needs %d arguments, but got %s".formatted(target.name(),
32 target.arity(), arguments.size()));
33 }
34 this.target = target;
35 this.arguments = arguments;
36 var mutableInArguments = new LinkedHashSet<Variable>();
37 var mutableOutArguments = new LinkedHashSet<Variable>();
38 var parameters = target.getParameters();
39 for (int i = 0; i < arity; i++) {
40 var argument = arguments.get(i);
41 var parameter = parameters.get(i);
42 if (!parameter.isAssignable(argument)) {
43 throw new InvalidQueryException("Argument %d of %s is not assignable to parameter %s"
44 .formatted(i, target, parameter));
45 }
46 switch (parameter.getDirection()) {
47 case IN -> {
48 mutableOutArguments.remove(argument);
49 mutableInArguments.add(argument);
50 }
51 case OUT -> {
52 if (!mutableInArguments.contains(argument)) {
53 mutableOutArguments.add(argument);
54 }
55 }
56 }
57 }
58 inArguments = Collections.unmodifiableSet(mutableInArguments);
59 outArguments = Collections.unmodifiableSet(mutableOutArguments);
60 }
61
62 public Constraint getTarget() {
63 return target;
64 }
65
66 public List<Variable> getArguments() {
67 return arguments;
68 }
69
70 protected Set<Variable> getArgumentsOfDirection(ParameterDirection direction) {
71 return switch (direction) {
72 case IN -> inArguments;
73 case OUT -> outArguments;
74 };
75 }
76
77 @Override
78 public Set<Variable> getInputVariables(Set<? extends Variable> positiveVariablesInClause) {
79 var inputVariables = new LinkedHashSet<>(getArgumentsOfDirection(ParameterDirection.OUT));
80 inputVariables.retainAll(positiveVariablesInClause);
81 inputVariables.addAll(getArgumentsOfDirection(ParameterDirection.IN));
82 return Collections.unmodifiableSet(inputVariables);
83 }
84
85 @Override
86 public Set<Variable> getPrivateVariables(Set<? extends Variable> positiveVariablesInClause) {
87 var privateVariables = new LinkedHashSet<>(getArgumentsOfDirection(ParameterDirection.OUT));
88 privateVariables.removeAll(positiveVariablesInClause);
89 return Collections.unmodifiableSet(privateVariables);
90 }
91
92 @Override
93 public Literal substitute(Substitution substitution) {
94 var substitutedArguments = arguments.stream().map(substitution::getSubstitute).toList();
95 return doSubstitute(substitution, substitutedArguments);
96 }
97
98 protected abstract Literal doSubstitute(Substitution substitution, List<Variable> substitutedArguments);
99
100 public AbstractCallLiteral withTarget(Constraint newTarget) {
101 if (Objects.equals(target, newTarget)) {
102 return this;
103 }
104 return withArguments(newTarget, arguments);
105 }
106
107 public abstract AbstractCallLiteral withArguments(Constraint newTarget, List<Variable> newArguments);
108
109 @Override
110 public boolean equalsWithSubstitution(LiteralEqualityHelper helper, Literal other) {
111 if (!super.equalsWithSubstitution(helper, other)) {
112 return false;
113 }
114 var otherCallLiteral = (AbstractCallLiteral) other;
115 var arity = arguments.size();
116 if (arity != otherCallLiteral.arguments.size()) {
117 return false;
118 }
119 for (int i = 0; i < arity; i++) {
120 if (!helper.variableEqual(arguments.get(i), otherCallLiteral.arguments.get(i))) {
121 return false;
122 }
123 }
124 return target.equals(helper, otherCallLiteral.target);
125 }
126
127 @Override
128 public int hashCodeWithSubstitution(LiteralHashCodeHelper helper) {
129 int result = super.hashCodeWithSubstitution(helper) * 31 + target.hashCode();
130 for (var argument : arguments) {
131 result = result * 31 + helper.getVariableHashCode(argument);
132 }
133 return result;
134 }
135}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/AbstractCountLiteral.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/AbstractCountLiteral.java
deleted file mode 100644
index 9bb572c0..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/AbstractCountLiteral.java
+++ /dev/null
@@ -1,107 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.literal;
7
8import tools.refinery.store.query.Constraint;
9import tools.refinery.store.query.InvalidQueryException;
10import tools.refinery.store.query.equality.LiteralEqualityHelper;
11import tools.refinery.store.query.equality.LiteralHashCodeHelper;
12import tools.refinery.store.query.term.ConstantTerm;
13import tools.refinery.store.query.term.DataVariable;
14import tools.refinery.store.query.term.Variable;
15
16import java.util.List;
17import java.util.Objects;
18import java.util.Set;
19
20// {@link Object#equals(Object)} is implemented by {@link AbstractLiteral}.
21@SuppressWarnings("squid:S2160")
22public abstract class AbstractCountLiteral<T> extends AbstractCallLiteral {
23 private final Class<T> resultType;
24 private final DataVariable<T> resultVariable;
25
26 protected AbstractCountLiteral(Class<T> resultType, DataVariable<T> resultVariable, Constraint target,
27 List<Variable> arguments) {
28 super(target, arguments);
29 if (!resultVariable.getType().equals(resultType)) {
30 throw new InvalidQueryException("Count result variable %s must be of type %s, got %s instead".formatted(
31 resultVariable, resultType, resultVariable.getType().getName()));
32 }
33 if (arguments.contains(resultVariable)) {
34 throw new InvalidQueryException("Count result variable %s must not appear in the argument list"
35 .formatted(resultVariable));
36 }
37 this.resultType = resultType;
38 this.resultVariable = resultVariable;
39 }
40
41 public Class<T> getResultType() {
42 return resultType;
43 }
44
45 public DataVariable<T> getResultVariable() {
46 return resultVariable;
47 }
48
49 @Override
50 public Set<Variable> getOutputVariables() {
51 return Set.of(resultVariable);
52 }
53
54 protected abstract T zero();
55
56 protected abstract T one();
57
58 @Override
59 public Literal reduce() {
60 var reduction = getTarget().getReduction();
61 return switch (reduction) {
62 case ALWAYS_FALSE -> getResultVariable().assign(new ConstantTerm<>(resultType, zero()));
63 // The only way a constant {@code true} predicate can be called in a negative position is to have all of
64 // its arguments bound as input variables. Thus, there will only be a single match.
65 case ALWAYS_TRUE -> getResultVariable().assign(new ConstantTerm<>(resultType, one()));
66 case NOT_REDUCIBLE -> this;
67 };
68 }
69
70 @Override
71 public boolean equalsWithSubstitution(LiteralEqualityHelper helper, Literal other) {
72 if (!super.equalsWithSubstitution(helper, other)) {
73 return false;
74 }
75 var otherCountLiteral = (AbstractCountLiteral<?>) other;
76 return Objects.equals(resultType, otherCountLiteral.resultType) &&
77 helper.variableEqual(resultVariable, otherCountLiteral.resultVariable);
78 }
79
80 @Override
81 public int hashCodeWithSubstitution(LiteralHashCodeHelper helper) {
82 return Objects.hash(super.hashCodeWithSubstitution(helper), resultType,
83 helper.getVariableHashCode(resultVariable));
84 }
85
86 protected abstract String operatorName();
87
88 @Override
89 public String toString() {
90 var builder = new StringBuilder();
91 builder.append(resultVariable);
92 builder.append(" is ");
93 builder.append(operatorName());
94 builder.append(' ');
95 builder.append(getTarget().toReferenceString());
96 builder.append('(');
97 var argumentIterator = getArguments().iterator();
98 if (argumentIterator.hasNext()) {
99 builder.append(argumentIterator.next());
100 while (argumentIterator.hasNext()) {
101 builder.append(", ").append(argumentIterator.next());
102 }
103 }
104 builder.append(')');
105 return builder.toString();
106 }
107}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/AbstractLiteral.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/AbstractLiteral.java
deleted file mode 100644
index 7d3cabd7..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/AbstractLiteral.java
+++ /dev/null
@@ -1,34 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.literal;
7
8import tools.refinery.store.query.equality.LiteralEqualityHelper;
9import tools.refinery.store.query.equality.LiteralHashCodeHelper;
10
11public abstract class AbstractLiteral implements Literal {
12 @Override
13 public boolean equalsWithSubstitution(LiteralEqualityHelper helper, Literal other) {
14 return other != null && getClass() == other.getClass();
15 }
16
17 @Override
18 public int hashCodeWithSubstitution(LiteralHashCodeHelper helper) {
19 return getClass().hashCode();
20 }
21
22 @Override
23 public boolean equals(Object o) {
24 if (this == o) return true;
25 if (o == null || getClass() != o.getClass()) return false;
26 AbstractLiteral that = (AbstractLiteral) o;
27 return equalsWithSubstitution(LiteralEqualityHelper.DEFAULT, that);
28 }
29
30 @Override
31 public int hashCode() {
32 return hashCodeWithSubstitution(LiteralHashCodeHelper.DEFAULT);
33 }
34}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/AggregationLiteral.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/AggregationLiteral.java
deleted file mode 100644
index e3acfacc..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/AggregationLiteral.java
+++ /dev/null
@@ -1,138 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.literal;
7
8import tools.refinery.store.query.Constraint;
9import tools.refinery.store.query.InvalidQueryException;
10import tools.refinery.store.query.equality.LiteralEqualityHelper;
11import tools.refinery.store.query.equality.LiteralHashCodeHelper;
12import tools.refinery.store.query.substitution.Substitution;
13import tools.refinery.store.query.term.*;
14
15import java.util.List;
16import java.util.Objects;
17import java.util.Set;
18
19// {@link Object#equals(Object)} is implemented by {@link AbstractLiteral}.
20@SuppressWarnings("squid:S2160")
21public class AggregationLiteral<R, T> extends AbstractCallLiteral {
22 private final DataVariable<R> resultVariable;
23 private final DataVariable<T> inputVariable;
24 private final Aggregator<R, T> aggregator;
25
26 public AggregationLiteral(DataVariable<R> resultVariable, Aggregator<R, T> aggregator,
27 DataVariable<T> inputVariable, Constraint target, List<Variable> arguments) {
28 super(target, arguments);
29 if (!inputVariable.getType().equals(aggregator.getInputType())) {
30 throw new InvalidQueryException("Input variable %s must of type %s, got %s instead".formatted(
31 inputVariable, aggregator.getInputType().getName(), inputVariable.getType().getName()));
32 }
33 if (!getArgumentsOfDirection(ParameterDirection.OUT).contains(inputVariable)) {
34 throw new InvalidQueryException("Input variable %s must be bound with direction %s in the argument list"
35 .formatted(inputVariable, ParameterDirection.OUT));
36 }
37 if (!resultVariable.getType().equals(aggregator.getResultType())) {
38 throw new InvalidQueryException("Result variable %s must of type %s, got %s instead".formatted(
39 resultVariable, aggregator.getResultType().getName(), resultVariable.getType().getName()));
40 }
41 if (arguments.contains(resultVariable)) {
42 throw new InvalidQueryException("Result variable %s must not appear in the argument list".formatted(
43 resultVariable));
44 }
45 this.resultVariable = resultVariable;
46 this.inputVariable = inputVariable;
47 this.aggregator = aggregator;
48 }
49
50 public DataVariable<R> getResultVariable() {
51 return resultVariable;
52 }
53
54 public DataVariable<T> getInputVariable() {
55 return inputVariable;
56 }
57
58 public Aggregator<R, T> getAggregator() {
59 return aggregator;
60 }
61
62 @Override
63 public Set<Variable> getOutputVariables() {
64 return Set.of(resultVariable);
65 }
66
67 @Override
68 public Set<Variable> getInputVariables(Set<? extends Variable> positiveVariablesInClause) {
69 if (positiveVariablesInClause.contains(inputVariable)) {
70 throw new InvalidQueryException("Aggregation variable %s must not be bound".formatted(inputVariable));
71 }
72 return super.getInputVariables(positiveVariablesInClause);
73 }
74
75 @Override
76 public Literal reduce() {
77 var reduction = getTarget().getReduction();
78 return switch (reduction) {
79 case ALWAYS_FALSE -> {
80 var emptyValue = aggregator.getEmptyResult();
81 yield emptyValue == null ? BooleanLiteral.FALSE :
82 resultVariable.assign(new ConstantTerm<>(resultVariable.getType(), emptyValue));
83 }
84 case ALWAYS_TRUE -> throw new InvalidQueryException("Trying to aggregate over an infinite set");
85 case NOT_REDUCIBLE -> this;
86 };
87 }
88
89 @Override
90 protected Literal doSubstitute(Substitution substitution, List<Variable> substitutedArguments) {
91 return new AggregationLiteral<>(substitution.getTypeSafeSubstitute(resultVariable), aggregator,
92 substitution.getTypeSafeSubstitute(inputVariable), getTarget(), substitutedArguments);
93 }
94
95 @Override
96 public AbstractCallLiteral withArguments(Constraint newTarget, List<Variable> newArguments) {
97 return new AggregationLiteral<>(resultVariable, aggregator, inputVariable, newTarget, newArguments);
98 }
99
100 @Override
101 public boolean equalsWithSubstitution(LiteralEqualityHelper helper, Literal other) {
102 if (!super.equalsWithSubstitution(helper, other)) {
103 return false;
104 }
105 var otherAggregationLiteral = (AggregationLiteral<?, ?>) other;
106 return helper.variableEqual(resultVariable, otherAggregationLiteral.resultVariable) &&
107 aggregator.equals(otherAggregationLiteral.aggregator) &&
108 helper.variableEqual(inputVariable, otherAggregationLiteral.inputVariable);
109 }
110
111 @Override
112 public int hashCodeWithSubstitution(LiteralHashCodeHelper helper) {
113 return Objects.hash(super.hashCodeWithSubstitution(helper), helper.getVariableHashCode(resultVariable),
114 helper.getVariableHashCode(inputVariable), aggregator);
115 }
116
117 @Override
118 public String toString() {
119 var builder = new StringBuilder();
120 builder.append(resultVariable);
121 builder.append(" is ");
122 builder.append(getTarget().toReferenceString());
123 builder.append("(");
124 var argumentIterator = getArguments().iterator();
125 if (argumentIterator.hasNext()) {
126 var argument = argumentIterator.next();
127 if (inputVariable.equals(argument)) {
128 builder.append("@Aggregate(\"").append(aggregator).append("\") ");
129 }
130 builder.append(argument);
131 while (argumentIterator.hasNext()) {
132 builder.append(", ").append(argumentIterator.next());
133 }
134 }
135 builder.append(")");
136 return builder.toString();
137 }
138}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/AssignLiteral.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/AssignLiteral.java
deleted file mode 100644
index dadf487f..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/AssignLiteral.java
+++ /dev/null
@@ -1,88 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.literal;
7
8import tools.refinery.store.query.InvalidQueryException;
9import tools.refinery.store.query.equality.LiteralEqualityHelper;
10import tools.refinery.store.query.equality.LiteralHashCodeHelper;
11import tools.refinery.store.query.substitution.Substitution;
12import tools.refinery.store.query.term.DataVariable;
13import tools.refinery.store.query.term.Term;
14import tools.refinery.store.query.term.Variable;
15
16import java.util.Collections;
17import java.util.Objects;
18import java.util.Set;
19
20// {@link Object#equals(Object)} is implemented by {@link AbstractLiteral}.
21@SuppressWarnings("squid:S2160")
22public class AssignLiteral<T> extends AbstractLiteral {
23 private final DataVariable<T> variable;
24 private final Term<T> term;
25
26 public AssignLiteral(DataVariable<T> variable, Term<T> term) {
27 if (!term.getType().equals(variable.getType())) {
28 throw new InvalidQueryException("Term %s must be of type %s, got %s instead".formatted(
29 term, variable.getType().getName(), term.getType().getName()));
30 }
31 var inputVariables = term.getInputVariables();
32 if (inputVariables.contains(variable)) {
33 throw new InvalidQueryException("Result variable %s must not appear in the term %s".formatted(
34 variable, term));
35 }
36 this.variable = variable;
37 this.term = term;
38 }
39
40 public DataVariable<T> getVariable() {
41 return variable;
42 }
43
44 public Term<T> getTerm() {
45 return term;
46 }
47
48 @Override
49 public Set<Variable> getOutputVariables() {
50 return Set.of(variable);
51 }
52
53 @Override
54 public Set<Variable> getInputVariables(Set<? extends Variable> positiveVariablesInClause) {
55 return Collections.unmodifiableSet(term.getInputVariables());
56 }
57
58 @Override
59 public Set<Variable> getPrivateVariables(Set<? extends Variable> positiveVariablesInClause) {
60 return Set.of();
61 }
62
63 @Override
64 public Literal substitute(Substitution substitution) {
65 return new AssignLiteral<>(substitution.getTypeSafeSubstitute(variable), term.substitute(substitution));
66 }
67
68 @Override
69 public boolean equalsWithSubstitution(LiteralEqualityHelper helper, Literal other) {
70 if (other == null || getClass() != other.getClass()) {
71 return false;
72 }
73 var otherAssignLiteral = (AssignLiteral<?>) other;
74 return helper.variableEqual(variable, otherAssignLiteral.variable) &&
75 term.equalsWithSubstitution(helper, otherAssignLiteral.term);
76 }
77
78 @Override
79 public int hashCodeWithSubstitution(LiteralHashCodeHelper helper) {
80 return Objects.hash(super.hashCodeWithSubstitution(helper), helper.getVariableHashCode(variable),
81 term.hashCodeWithSubstitution(helper));
82 }
83
84 @Override
85 public String toString() {
86 return "%s is (%s)".formatted(variable, term);
87 }
88}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/BooleanLiteral.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/BooleanLiteral.java
deleted file mode 100644
index 6cd320da..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/BooleanLiteral.java
+++ /dev/null
@@ -1,69 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.literal;
7
8import tools.refinery.store.query.equality.LiteralEqualityHelper;
9import tools.refinery.store.query.equality.LiteralHashCodeHelper;
10import tools.refinery.store.query.substitution.Substitution;
11import tools.refinery.store.query.term.Variable;
12
13import java.util.Set;
14
15public enum BooleanLiteral implements CanNegate<BooleanLiteral> {
16 TRUE(true),
17 FALSE(false);
18
19 private final boolean value;
20
21 BooleanLiteral(boolean value) {
22 this.value = value;
23 }
24
25 @Override
26 public Set<Variable> getOutputVariables() {
27 return Set.of();
28 }
29
30 @Override
31 public Set<Variable> getInputVariables(Set<? extends Variable> positiveVariablesInClause) {
32 return Set.of();
33 }
34
35 @Override
36 public Set<Variable> getPrivateVariables(Set<? extends Variable> positiveVariablesInClause) {
37 return Set.of();
38 }
39
40 @Override
41 public Literal substitute(Substitution substitution) {
42 // No variables to substitute.
43 return this;
44 }
45
46 @Override
47 public BooleanLiteral negate() {
48 return fromBoolean(!value);
49 }
50
51 @Override
52 public boolean equalsWithSubstitution(LiteralEqualityHelper helper, Literal other) {
53 return equals(other);
54 }
55
56 @Override
57 public int hashCodeWithSubstitution(LiteralHashCodeHelper helper) {
58 return hashCode();
59 }
60
61 @Override
62 public String toString() {
63 return Boolean.toString(value);
64 }
65
66 public static BooleanLiteral fromBoolean(boolean value) {
67 return value ? TRUE : FALSE;
68 }
69}
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
deleted file mode 100644
index 2d0e4e97..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/CallLiteral.java
+++ /dev/null
@@ -1,134 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.literal;
7
8import tools.refinery.store.query.Constraint;
9import tools.refinery.store.query.InvalidQueryException;
10import tools.refinery.store.query.equality.LiteralEqualityHelper;
11import tools.refinery.store.query.equality.LiteralHashCodeHelper;
12import tools.refinery.store.query.substitution.Substitution;
13import tools.refinery.store.query.term.ParameterDirection;
14import tools.refinery.store.query.term.Variable;
15
16import java.util.*;
17
18// {@link Object#equals(Object)} is implemented by {@link AbstractLiteral}.
19@SuppressWarnings("squid:S2160")
20public final class CallLiteral extends AbstractCallLiteral implements CanNegate<CallLiteral> {
21 private final CallPolarity polarity;
22
23 public CallLiteral(CallPolarity polarity, Constraint target, List<Variable> arguments) {
24 super(target, arguments);
25 var parameters = target.getParameters();
26 int arity = target.arity();
27 if (polarity.isTransitive()) {
28 if (arity != 2) {
29 throw new InvalidQueryException("Transitive closures can only take binary relations");
30 }
31 if (parameters.get(0).isDataVariable() || parameters.get(1).isDataVariable()) {
32 throw new InvalidQueryException("Transitive closures can only be computed over nodes");
33 }
34 if (parameters.get(0).getDirection() != ParameterDirection.OUT ||
35 parameters.get(1).getDirection() != ParameterDirection.OUT) {
36 throw new InvalidQueryException("Transitive closures cannot take input parameters");
37 }
38 }
39 this.polarity = polarity;
40 }
41
42 public CallPolarity getPolarity() {
43 return polarity;
44 }
45
46 @Override
47 protected Literal doSubstitute(Substitution substitution, List<Variable> substitutedArguments) {
48 return new CallLiteral(polarity, getTarget(), substitutedArguments);
49 }
50
51 @Override
52 public Set<Variable> getOutputVariables() {
53 if (polarity.isPositive()) {
54 return getArgumentsOfDirection(ParameterDirection.OUT);
55 }
56 return Set.of();
57 }
58
59 @Override
60 public Set<Variable> getInputVariables(Set<? extends Variable> positiveVariablesInClause) {
61 if (polarity.isPositive()) {
62 return getArgumentsOfDirection(ParameterDirection.IN);
63 }
64 return super.getInputVariables(positiveVariablesInClause);
65 }
66
67 @Override
68 public Set<Variable> getPrivateVariables(Set<? extends Variable> positiveVariablesInClause) {
69 if (polarity.isPositive()) {
70 return Set.of();
71 }
72 return super.getPrivateVariables(positiveVariablesInClause);
73 }
74
75 @Override
76 public Literal reduce() {
77 var reduction = getTarget().getReduction();
78 var negatedReduction = polarity.isPositive() ? reduction : reduction.negate();
79 return switch (negatedReduction) {
80 case ALWAYS_TRUE -> BooleanLiteral.TRUE;
81 case ALWAYS_FALSE -> BooleanLiteral.FALSE;
82 default -> this;
83 };
84 }
85
86 @Override
87 public boolean equalsWithSubstitution(LiteralEqualityHelper helper, Literal other) {
88 if (!super.equalsWithSubstitution(helper, other)) {
89 return false;
90 }
91 var otherCallLiteral = (CallLiteral) other;
92 return polarity.equals(otherCallLiteral.polarity);
93 }
94
95 @Override
96 public int hashCodeWithSubstitution(LiteralHashCodeHelper helper) {
97 return Objects.hash(super.hashCodeWithSubstitution(helper), polarity);
98 }
99
100 @Override
101 public CallLiteral negate() {
102 return new CallLiteral(polarity.negate(), getTarget(), getArguments());
103 }
104
105 @Override
106 public AbstractCallLiteral withArguments(Constraint newTarget, List<Variable> newArguments) {
107 return new CallLiteral(polarity, newTarget, newArguments);
108 }
109
110 @Override
111 public String toString() {
112 var builder = new StringBuilder();
113 if (!polarity.isPositive()) {
114 builder.append("!(");
115 }
116 builder.append(getTarget().toReferenceString());
117 if (polarity.isTransitive()) {
118 builder.append("+");
119 }
120 builder.append("(");
121 var argumentIterator = getArguments().iterator();
122 if (argumentIterator.hasNext()) {
123 builder.append(argumentIterator.next());
124 while (argumentIterator.hasNext()) {
125 builder.append(", ").append(argumentIterator.next());
126 }
127 }
128 builder.append(")");
129 if (!polarity.isPositive()) {
130 builder.append(")");
131 }
132 return builder.toString();
133 }
134}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/CallPolarity.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/CallPolarity.java
deleted file mode 100644
index 716c7109..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/CallPolarity.java
+++ /dev/null
@@ -1,39 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.literal;
7
8import tools.refinery.store.query.InvalidQueryException;
9
10public enum CallPolarity {
11 POSITIVE(true, false),
12 NEGATIVE(false, false),
13 TRANSITIVE(true, true);
14
15 private final boolean positive;
16
17 private final boolean transitive;
18
19 CallPolarity(boolean positive, boolean transitive) {
20 this.positive = positive;
21 this.transitive = transitive;
22 }
23
24 public boolean isPositive() {
25 return positive;
26 }
27
28 public boolean isTransitive() {
29 return transitive;
30 }
31
32 public CallPolarity negate() {
33 return switch (this) {
34 case POSITIVE -> NEGATIVE;
35 case NEGATIVE -> POSITIVE;
36 case TRANSITIVE -> throw new InvalidQueryException("Transitive polarity cannot be negated");
37 };
38 }
39}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/CanNegate.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/CanNegate.java
deleted file mode 100644
index 35dcb3fb..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/CanNegate.java
+++ /dev/null
@@ -1,10 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.literal;
7
8public interface CanNegate<T extends CanNegate<T>> extends Literal {
9 T negate();
10}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/CheckLiteral.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/CheckLiteral.java
deleted file mode 100644
index dfedd2cb..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/CheckLiteral.java
+++ /dev/null
@@ -1,95 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.literal;
7
8import tools.refinery.store.query.InvalidQueryException;
9import tools.refinery.store.query.equality.LiteralEqualityHelper;
10import tools.refinery.store.query.equality.LiteralHashCodeHelper;
11import tools.refinery.store.query.substitution.Substitution;
12import tools.refinery.store.query.term.ConstantTerm;
13import tools.refinery.store.query.term.Term;
14import tools.refinery.store.query.term.Variable;
15import tools.refinery.store.query.term.bool.BoolNotTerm;
16import tools.refinery.store.query.term.bool.BoolTerms;
17
18import java.util.Collections;
19import java.util.Objects;
20import java.util.Set;
21
22// {@link Object#equals(Object)} is implemented by {@link AbstractLiteral}.
23@SuppressWarnings("squid:S2160")
24public class CheckLiteral extends AbstractLiteral implements CanNegate<CheckLiteral> {
25 private final Term<Boolean> term;
26
27 public CheckLiteral(Term<Boolean> term) {
28 if (!term.getType().equals(Boolean.class)) {
29 throw new InvalidQueryException("Term %s must be of type %s, got %s instead".formatted(
30 term, Boolean.class.getName(), term.getType().getName()));
31 }
32 this.term = term;
33 }
34
35 public Term<Boolean> getTerm() {
36 return term;
37 }
38
39 @Override
40 public Set<Variable> getOutputVariables() {
41 return Set.of();
42 }
43
44 @Override
45 public Set<Variable> getInputVariables(Set<? extends Variable> positiveVariablesInClause) {
46 return Collections.unmodifiableSet(term.getInputVariables());
47 }
48
49 @Override
50 public Set<Variable> getPrivateVariables(Set<? extends Variable> positiveVariablesInClause) {
51 return Set.of();
52 }
53
54 @Override
55 public Literal substitute(Substitution substitution) {
56 return new CheckLiteral(term.substitute(substitution));
57 }
58
59 @Override
60 public CheckLiteral negate() {
61 if (term instanceof BoolNotTerm notTerm) {
62 return new CheckLiteral(notTerm.getBody());
63 }
64 return new CheckLiteral(BoolTerms.not(term));
65 }
66
67 @Override
68 public boolean equalsWithSubstitution(LiteralEqualityHelper helper, Literal other) {
69 if (other == null || getClass() != other.getClass()) {
70 return false;
71 }
72 var otherAssumeLiteral = (CheckLiteral) other;
73 return term.equalsWithSubstitution(helper, otherAssumeLiteral.term);
74 }
75
76 @Override
77 public int hashCodeWithSubstitution(LiteralHashCodeHelper helper) {
78 return Objects.hash(super.hashCodeWithSubstitution(helper), term.hashCodeWithSubstitution(helper));
79 }
80
81 @Override
82 public Literal reduce() {
83 if (term instanceof ConstantTerm<Boolean> constantTerm) {
84 // Return {@link BooleanLiteral#FALSE} for {@code false} or {@code null} literals.
85 return Boolean.TRUE.equals(constantTerm.getValue()) ? BooleanLiteral.TRUE :
86 BooleanLiteral.FALSE;
87 }
88 return this;
89 }
90
91 @Override
92 public String toString() {
93 return "(%s)".formatted(term);
94 }
95}
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
deleted file mode 100644
index a058094d..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/Connectivity.java
+++ /dev/null
@@ -1,18 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.literal;
7
8import java.util.Locale;
9
10public enum Connectivity {
11 WEAK,
12 STRONG;
13
14 @Override
15 public String toString() {
16 return name().toLowerCase(Locale.ROOT);
17 }
18}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/ConstantLiteral.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/ConstantLiteral.java
deleted file mode 100644
index d83bd584..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/ConstantLiteral.java
+++ /dev/null
@@ -1,73 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.literal;
7
8import tools.refinery.store.query.equality.LiteralEqualityHelper;
9import tools.refinery.store.query.equality.LiteralHashCodeHelper;
10import tools.refinery.store.query.substitution.Substitution;
11import tools.refinery.store.query.term.NodeVariable;
12import tools.refinery.store.query.term.Variable;
13
14import java.util.Objects;
15import java.util.Set;
16
17public class ConstantLiteral extends AbstractLiteral {
18 private final NodeVariable variable;
19 private final int nodeId;
20
21 public ConstantLiteral(NodeVariable variable, int nodeId) {
22 this.variable = variable;
23 this.nodeId = nodeId;
24 }
25
26 public NodeVariable getVariable() {
27 return variable;
28 }
29
30 public int getNodeId() {
31 return nodeId;
32 }
33
34
35 @Override
36 public Set<Variable> getOutputVariables() {
37 return Set.of(variable);
38 }
39
40 @Override
41 public Set<Variable> getInputVariables(Set<? extends Variable> positiveVariablesInClause) {
42 return Set.of();
43 }
44
45 @Override
46 public Set<Variable> getPrivateVariables(Set<? extends Variable> positiveVariablesInClause) {
47 return Set.of();
48 }
49
50 @Override
51 public ConstantLiteral substitute(Substitution substitution) {
52 return new ConstantLiteral(substitution.getTypeSafeSubstitute(variable), nodeId);
53 }
54
55 @Override
56 public boolean equalsWithSubstitution(LiteralEqualityHelper helper, Literal other) {
57 if (other.getClass() != getClass()) {
58 return false;
59 }
60 var otherConstantLiteral = (ConstantLiteral) other;
61 return helper.variableEqual(variable, otherConstantLiteral.variable) && nodeId == otherConstantLiteral.nodeId;
62 }
63
64 @Override
65 public int hashCodeWithSubstitution(LiteralHashCodeHelper helper) {
66 return Objects.hash(super.hashCodeWithSubstitution(helper), helper.getVariableHashCode(variable), nodeId);
67 }
68
69 @Override
70 public String toString() {
71 return "%s === @Constant %d".formatted(variable, nodeId);
72 }
73}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/CountLiteral.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/CountLiteral.java
deleted file mode 100644
index 3d078d89..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/CountLiteral.java
+++ /dev/null
@@ -1,45 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.literal;
7
8import tools.refinery.store.query.Constraint;
9import tools.refinery.store.query.substitution.Substitution;
10import tools.refinery.store.query.term.DataVariable;
11import tools.refinery.store.query.term.Variable;
12
13import java.util.List;
14
15public class CountLiteral extends AbstractCountLiteral<Integer> {
16 public CountLiteral(DataVariable<Integer> resultVariable, Constraint target, List<Variable> arguments) {
17 super(Integer.class, resultVariable, target, arguments);
18 }
19
20 @Override
21 protected Integer zero() {
22 return 0;
23 }
24
25 @Override
26 protected Integer one() {
27 return 1;
28 }
29
30 @Override
31 protected Literal doSubstitute(Substitution substitution, List<Variable> substitutedArguments) {
32 return new CountLiteral(substitution.getTypeSafeSubstitute(getResultVariable()), getTarget(),
33 substitutedArguments);
34 }
35
36 @Override
37 public AbstractCallLiteral withArguments(Constraint newTarget, List<Variable> newArguments) {
38 return new CountLiteral(getResultVariable(), newTarget, newArguments);
39 }
40
41 @Override
42 protected String operatorName() {
43 return "count";
44 }
45}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/EquivalenceLiteral.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/EquivalenceLiteral.java
deleted file mode 100644
index 7343f709..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/EquivalenceLiteral.java
+++ /dev/null
@@ -1,100 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.literal;
7
8import tools.refinery.store.query.InvalidQueryException;
9import tools.refinery.store.query.equality.LiteralEqualityHelper;
10import tools.refinery.store.query.equality.LiteralHashCodeHelper;
11import tools.refinery.store.query.substitution.Substitution;
12import tools.refinery.store.query.term.Variable;
13
14import java.util.Objects;
15import java.util.Set;
16
17// {@link Object#equals(Object)} is implemented by {@link AbstractLiteral}.
18@SuppressWarnings("squid:S2160")
19public final class EquivalenceLiteral extends AbstractLiteral implements CanNegate<EquivalenceLiteral> {
20 private final boolean positive;
21 private final Variable left;
22 private final Variable right;
23
24 public EquivalenceLiteral(boolean positive, Variable left, Variable right) {
25 if (!left.tryGetType().equals(right.tryGetType())) {
26 throw new InvalidQueryException("Variables %s and %s of different type cannot be equivalent"
27 .formatted(left, right));
28 }
29 this.positive = positive;
30 this.left = left;
31 this.right = right;
32 }
33
34 public boolean isPositive() {
35 return positive;
36 }
37
38 public Variable getLeft() {
39 return left;
40 }
41
42 public Variable getRight() {
43 return right;
44 }
45
46 @Override
47 public Set<Variable> getOutputVariables() {
48 return Set.of(left);
49 }
50
51 @Override
52 public Set<Variable> getInputVariables(Set<? extends Variable> positiveVariablesInClause) {
53 return Set.of(right);
54 }
55
56 @Override
57 public Set<Variable> getPrivateVariables(Set<? extends Variable> positiveVariablesInClause) {
58 return Set.of();
59 }
60
61 @Override
62 public EquivalenceLiteral negate() {
63 return new EquivalenceLiteral(!positive, left, right);
64 }
65
66 @Override
67 public EquivalenceLiteral substitute(Substitution substitution) {
68 return new EquivalenceLiteral(positive, substitution.getSubstitute(left),
69 substitution.getSubstitute(right));
70 }
71
72 @Override
73 public Literal reduce() {
74 if (left.equals(right)) {
75 return positive ? BooleanLiteral.TRUE : BooleanLiteral.FALSE;
76 }
77 return this;
78 }
79
80 @Override
81 public boolean equalsWithSubstitution(LiteralEqualityHelper helper, Literal other) {
82 if (other.getClass() != getClass()) {
83 return false;
84 }
85 var otherEquivalenceLiteral = (EquivalenceLiteral) other;
86 return helper.variableEqual(left, otherEquivalenceLiteral.left) &&
87 helper.variableEqual(right, otherEquivalenceLiteral.right);
88 }
89
90 @Override
91 public int hashCodeWithSubstitution(LiteralHashCodeHelper helper) {
92 return Objects.hash(super.hashCodeWithSubstitution(helper), helper.getVariableHashCode(left),
93 helper.getVariableHashCode(right));
94 }
95
96 @Override
97 public String toString() {
98 return "%s %s %s".formatted(left, positive ? "===" : "!==", right);
99 }
100}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/Literal.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/Literal.java
deleted file mode 100644
index cb16ab00..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/Literal.java
+++ /dev/null
@@ -1,32 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.literal;
7
8import tools.refinery.store.query.equality.LiteralEqualityHelper;
9import tools.refinery.store.query.equality.LiteralHashCodeHelper;
10import tools.refinery.store.query.substitution.Substitution;
11import tools.refinery.store.query.term.Variable;
12
13import java.util.Set;
14
15public interface Literal {
16 Set<Variable> getOutputVariables();
17
18 Set<Variable> getInputVariables(Set<? extends Variable> positiveVariablesInClause);
19
20 Set<Variable> getPrivateVariables(Set<? extends Variable> positiveVariablesInClause);
21
22 Literal substitute(Substitution substitution);
23
24 default Literal reduce() {
25 return this;
26 }
27
28 @SuppressWarnings("BooleanMethodIsAlwaysInverted")
29 boolean equalsWithSubstitution(LiteralEqualityHelper helper, Literal other);
30
31 int hashCodeWithSubstitution(LiteralHashCodeHelper helper);
32}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/Literals.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/Literals.java
deleted file mode 100644
index 6056da45..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/Literals.java
+++ /dev/null
@@ -1,22 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.literal;
7
8import tools.refinery.store.query.term.Term;
9
10public final class Literals {
11 private Literals() {
12 throw new IllegalStateException("This is a static utility class and should not be instantiated directly");
13 }
14
15 public static <T extends CanNegate<T>> T not(CanNegate<T> literal) {
16 return literal.negate();
17 }
18
19 public static CheckLiteral check(Term<Boolean> term) {
20 return new CheckLiteral(term);
21 }
22}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/Reduction.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/Reduction.java
deleted file mode 100644
index ee155a9a..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/Reduction.java
+++ /dev/null
@@ -1,31 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.literal;
7
8public enum Reduction {
9 /**
10 * Signifies that a literal should be preserved in the clause.
11 */
12 NOT_REDUCIBLE,
13
14 /**
15 * Signifies that the literal may be omitted from the cause (if the model being queried is nonempty).
16 */
17 ALWAYS_TRUE,
18
19 /**
20 * Signifies that the clause with the literal may be omitted entirely.
21 */
22 ALWAYS_FALSE;
23
24 public Reduction negate() {
25 return switch (this) {
26 case NOT_REDUCIBLE -> NOT_REDUCIBLE;
27 case ALWAYS_TRUE -> ALWAYS_FALSE;
28 case ALWAYS_FALSE -> ALWAYS_TRUE;
29 };
30 }
31}
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
deleted file mode 100644
index f7323947..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/RepresentativeElectionLiteral.java
+++ /dev/null
@@ -1,119 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.literal;
7
8import tools.refinery.store.query.Constraint;
9import tools.refinery.store.query.InvalidQueryException;
10import tools.refinery.store.query.equality.LiteralEqualityHelper;
11import tools.refinery.store.query.equality.LiteralHashCodeHelper;
12import tools.refinery.store.query.substitution.Substitution;
13import tools.refinery.store.query.term.NodeVariable;
14import tools.refinery.store.query.term.ParameterDirection;
15import tools.refinery.store.query.term.Variable;
16
17import java.util.List;
18import java.util.Set;
19
20// {@link Object#equals(Object)} is implemented by {@link AbstractLiteral}.
21@SuppressWarnings("squid:S2160")
22public class RepresentativeElectionLiteral extends AbstractCallLiteral {
23 private final Connectivity connectivity;
24
25 public RepresentativeElectionLiteral(Connectivity connectivity, Constraint target, NodeVariable specific,
26 NodeVariable representative) {
27 this(connectivity, target, List.of(specific, representative));
28 }
29
30 private RepresentativeElectionLiteral(Connectivity connectivity, Constraint target, List<Variable> arguments) {
31 super(target, arguments);
32 this.connectivity = connectivity;
33 var parameters = target.getParameters();
34 int arity = target.arity();
35 if (arity != 2) {
36 throw new InvalidQueryException("SCCs can only take binary relations");
37 }
38 if (parameters.get(0).isDataVariable() || parameters.get(1).isDataVariable()) {
39 throw new InvalidQueryException("SCCs can only be computed over nodes");
40 }
41 if (parameters.get(0).getDirection() != ParameterDirection.OUT ||
42 parameters.get(1).getDirection() != ParameterDirection.OUT) {
43 throw new InvalidQueryException("SCCs cannot take input parameters");
44 }
45 }
46
47 public Connectivity getConnectivity() {
48 return connectivity;
49 }
50
51 @Override
52 protected Literal doSubstitute(Substitution substitution, List<Variable> substitutedArguments) {
53 return new RepresentativeElectionLiteral(connectivity, getTarget(), substitutedArguments);
54 }
55
56 @Override
57 public Set<Variable> getOutputVariables() {
58 return getArgumentsOfDirection(ParameterDirection.OUT);
59 }
60
61 @Override
62 public Set<Variable> getInputVariables(Set<? extends Variable> positiveVariablesInClause) {
63 return Set.of();
64 }
65
66 @Override
67 public Set<Variable> getPrivateVariables(Set<? extends Variable> positiveVariablesInClause) {
68 return Set.of();
69 }
70
71 @Override
72 public Literal reduce() {
73 var reduction = getTarget().getReduction();
74 return switch (reduction) {
75 case ALWAYS_FALSE -> BooleanLiteral.FALSE;
76 case ALWAYS_TRUE -> throw new InvalidQueryException(
77 "Trying to elect representatives over an infinite set");
78 case NOT_REDUCIBLE -> this;
79 };
80 }
81
82 @Override
83 public AbstractCallLiteral withArguments(Constraint newTarget, List<Variable> newArguments) {
84 return new RepresentativeElectionLiteral(connectivity, newTarget, newArguments);
85 }
86
87 @Override
88 public boolean equalsWithSubstitution(LiteralEqualityHelper helper, Literal other) {
89 if (!super.equalsWithSubstitution(helper, other)) {
90 return false;
91 }
92 var otherRepresentativeElectionLiteral = (RepresentativeElectionLiteral) other;
93 return connectivity.equals(otherRepresentativeElectionLiteral.connectivity);
94 }
95
96 @Override
97 public int hashCodeWithSubstitution(LiteralHashCodeHelper helper) {
98 return super.hashCodeWithSubstitution(helper) * 31 + connectivity.hashCode();
99 }
100
101 @Override
102 public String toString() {
103 var builder = new StringBuilder();
104 builder.append("@Representative(\"");
105 builder.append(connectivity);
106 builder.append("\") ");
107 builder.append(getTarget().toReferenceString());
108 builder.append("(");
109 var argumentIterator = getArguments().iterator();
110 if (argumentIterator.hasNext()) {
111 builder.append(argumentIterator.next());
112 while (argumentIterator.hasNext()) {
113 builder.append(", ").append(argumentIterator.next());
114 }
115 }
116 builder.append(")");
117 return builder.toString();
118 }
119}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/resultset/AbstractResultSet.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/resultset/AbstractResultSet.java
index dcfe6cc5..f8290b48 100644
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/resultset/AbstractResultSet.java
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/resultset/AbstractResultSet.java
@@ -6,7 +6,7 @@
6package tools.refinery.store.query.resultset; 6package tools.refinery.store.query.resultset;
7 7
8import tools.refinery.store.query.ModelQueryAdapter; 8import tools.refinery.store.query.ModelQueryAdapter;
9import tools.refinery.store.query.dnf.Query; 9import tools.refinery.logic.dnf.Query;
10import tools.refinery.store.tuple.Tuple; 10import tools.refinery.store.tuple.Tuple;
11 11
12import java.util.ArrayList; 12import java.util.ArrayList;
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/resultset/AnyResultSet.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/resultset/AnyResultSet.java
index 5b75b103..038ca7f9 100644
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/resultset/AnyResultSet.java
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/resultset/AnyResultSet.java
@@ -6,7 +6,7 @@
6package tools.refinery.store.query.resultset; 6package tools.refinery.store.query.resultset;
7 7
8import tools.refinery.store.query.ModelQueryAdapter; 8import tools.refinery.store.query.ModelQueryAdapter;
9import tools.refinery.store.query.dnf.AnyQuery; 9import tools.refinery.logic.dnf.AnyQuery;
10 10
11public sealed interface AnyResultSet permits ResultSet { 11public sealed interface AnyResultSet permits ResultSet {
12 ModelQueryAdapter getAdapter(); 12 ModelQueryAdapter getAdapter();
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/resultset/EmptyResultSet.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/resultset/EmptyResultSet.java
index 991b1e32..daebfe7c 100644
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/resultset/EmptyResultSet.java
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/resultset/EmptyResultSet.java
@@ -8,7 +8,7 @@ package tools.refinery.store.query.resultset;
8import tools.refinery.store.map.Cursor; 8import tools.refinery.store.map.Cursor;
9import tools.refinery.store.map.Cursors; 9import tools.refinery.store.map.Cursors;
10import tools.refinery.store.query.ModelQueryAdapter; 10import tools.refinery.store.query.ModelQueryAdapter;
11import tools.refinery.store.query.dnf.Query; 11import tools.refinery.logic.dnf.Query;
12import tools.refinery.store.tuple.Tuple; 12import tools.refinery.store.tuple.Tuple;
13 13
14public record EmptyResultSet<T>(ModelQueryAdapter adapter, Query<T> query) implements ResultSet<T> { 14public record EmptyResultSet<T>(ModelQueryAdapter adapter, Query<T> query) implements ResultSet<T> {
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/resultset/OrderedResultSet.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/resultset/OrderedResultSet.java
index df12b967..606e197c 100644
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/resultset/OrderedResultSet.java
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/resultset/OrderedResultSet.java
@@ -7,7 +7,7 @@ package tools.refinery.store.query.resultset;
7 7
8import tools.refinery.store.map.Cursor; 8import tools.refinery.store.map.Cursor;
9import tools.refinery.store.query.ModelQueryAdapter; 9import tools.refinery.store.query.ModelQueryAdapter;
10import tools.refinery.store.query.dnf.Query; 10import tools.refinery.logic.dnf.Query;
11import tools.refinery.store.query.utils.OrderStatisticTree; 11import tools.refinery.store.query.utils.OrderStatisticTree;
12import tools.refinery.store.tuple.Tuple; 12import tools.refinery.store.tuple.Tuple;
13 13
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/resultset/ResultSet.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/resultset/ResultSet.java
index a6e99784..e84634ac 100644
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/resultset/ResultSet.java
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/resultset/ResultSet.java
@@ -6,7 +6,7 @@
6package tools.refinery.store.query.resultset; 6package tools.refinery.store.query.resultset;
7 7
8import tools.refinery.store.map.Cursor; 8import tools.refinery.store.map.Cursor;
9import tools.refinery.store.query.dnf.Query; 9import tools.refinery.logic.dnf.Query;
10import tools.refinery.store.tuple.Tuple; 10import tools.refinery.store.tuple.Tuple;
11 11
12public non-sealed interface ResultSet<T> extends AnyResultSet { 12public non-sealed interface ResultSet<T> extends AnyResultSet {
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/rewriter/AbstractRecursiveRewriter.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/rewriter/AbstractRecursiveRewriter.java
deleted file mode 100644
index fb4c14a7..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/rewriter/AbstractRecursiveRewriter.java
+++ /dev/null
@@ -1,26 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.rewriter;
7
8import tools.refinery.store.query.dnf.Dnf;
9import tools.refinery.store.query.equality.DnfEqualityChecker;
10import tools.refinery.store.util.CycleDetectingMapper;
11
12public abstract class AbstractRecursiveRewriter implements DnfRewriter {
13 private final CycleDetectingMapper<Dnf, Dnf> mapper = new CycleDetectingMapper<>(Dnf::name, this::map);
14
15 @Override
16 public Dnf rewrite(Dnf dnf) {
17 return mapper.map(dnf);
18 }
19
20 protected Dnf map(Dnf dnf) {
21 var result = doRewrite(dnf);
22 return dnf.equalsWithSubstitution(DnfEqualityChecker.DEFAULT, result) ? dnf : result;
23 }
24
25 protected abstract Dnf doRewrite(Dnf dnf);
26}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/rewriter/ClauseInputParameterResolver.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/rewriter/ClauseInputParameterResolver.java
deleted file mode 100644
index aa06a05a..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/rewriter/ClauseInputParameterResolver.java
+++ /dev/null
@@ -1,160 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.rewriter;
7
8import tools.refinery.store.query.dnf.Dnf;
9import tools.refinery.store.query.dnf.DnfClause;
10import tools.refinery.store.query.literal.*;
11import tools.refinery.store.query.substitution.Substitution;
12import tools.refinery.store.query.term.ParameterDirection;
13import tools.refinery.store.query.term.Variable;
14
15import java.util.*;
16
17class ClauseInputParameterResolver {
18 private final InputParameterResolver rewriter;
19 private final String dnfName;
20 private final int clauseIndex;
21 private final Set<Variable> positiveVariables = new LinkedHashSet<>();
22 private final List<Literal> inlinedLiterals = new ArrayList<>();
23 private final Deque<Literal> workList;
24 private int helperIndex = 0;
25
26 public ClauseInputParameterResolver(InputParameterResolver rewriter, List<Literal> context, DnfClause clause,
27 String dnfName, int clauseIndex) {
28 this.rewriter = rewriter;
29 this.dnfName = dnfName;
30 this.clauseIndex = clauseIndex;
31 workList = new ArrayDeque<>(clause.literals().size() + context.size());
32 for (var literal : context) {
33 workList.addLast(literal);
34 }
35 for (var literal : clause.literals()) {
36 workList.addLast(literal);
37 }
38 }
39
40 public List<Literal> rewriteClause() {
41 while (!workList.isEmpty()) {
42 var literal = workList.removeFirst();
43 processLiteral(literal);
44 }
45 return inlinedLiterals;
46 }
47
48 private void processLiteral(Literal literal) {
49 if (!(literal instanceof AbstractCallLiteral abstractCallLiteral) ||
50 !(abstractCallLiteral.getTarget() instanceof Dnf targetDnf)) {
51 markAsDone(literal);
52 return;
53 }
54 boolean hasInputParameter = hasInputParameter(targetDnf);
55 if (!hasInputParameter) {
56 targetDnf = rewriter.rewrite(targetDnf);
57 }
58 if (inlinePositiveClause(abstractCallLiteral, targetDnf)) {
59 return;
60 }
61 if (eliminateDoubleNegation(abstractCallLiteral, targetDnf)) {
62 return;
63 }
64 if (hasInputParameter) {
65 rewriteWithCurrentContext(abstractCallLiteral, targetDnf);
66 return;
67 }
68 markAsDone(abstractCallLiteral.withTarget(targetDnf));
69 }
70
71 private void markAsDone(Literal literal) {
72 positiveVariables.addAll(literal.getOutputVariables());
73 inlinedLiterals.add(literal);
74 }
75
76 private boolean inlinePositiveClause(AbstractCallLiteral abstractCallLiteral, Dnf targetDnf) {
77 var targetLiteral = getSingleLiteral(abstractCallLiteral, targetDnf, CallPolarity.POSITIVE);
78 if (targetLiteral == null) {
79 return false;
80 }
81 var substitution = asSubstitution(abstractCallLiteral, targetDnf);
82 var substitutedLiteral = targetLiteral.substitute(substitution);
83 workList.addFirst(substitutedLiteral);
84 return true;
85 }
86
87 private boolean eliminateDoubleNegation(AbstractCallLiteral abstractCallLiteral, Dnf targetDnf) {
88 var targetLiteral = getSingleLiteral(abstractCallLiteral, targetDnf, CallPolarity.NEGATIVE);
89 if (!(targetLiteral instanceof CallLiteral targetCallLiteral) ||
90 targetCallLiteral.getPolarity() != CallPolarity.NEGATIVE) {
91 return false;
92 }
93 var substitution = asSubstitution(abstractCallLiteral, targetDnf);
94 var substitutedLiteral = (CallLiteral) targetCallLiteral.substitute(substitution);
95 workList.addFirst(substitutedLiteral.negate());
96 return true;
97 }
98
99 private void rewriteWithCurrentContext(AbstractCallLiteral abstractCallLiteral, Dnf targetDnf) {
100 var contextBuilder = Dnf.builder("%s#clause%d#helper%d".formatted(dnfName, clauseIndex, helperIndex));
101 helperIndex++;
102 contextBuilder.parameters(positiveVariables, ParameterDirection.OUT);
103 contextBuilder.clause(inlinedLiterals);
104 var contextDnf = contextBuilder.build();
105 var contextCall = new CallLiteral(CallPolarity.POSITIVE, contextDnf, List.copyOf(positiveVariables));
106 inlinedLiterals.clear();
107 var substitution = Substitution.builder().renewing().build();
108 var context = new ArrayList<Literal>();
109 context.add(contextCall.substitute(substitution));
110 int arity = targetDnf.arity();
111 for (int i = 0; i < arity; i++) {
112 var parameter = targetDnf.getSymbolicParameters().get(i).getVariable();
113 var argument = abstractCallLiteral.getArguments().get(i);
114 context.add(new EquivalenceLiteral(true, parameter, substitution.getSubstitute(argument)));
115 }
116 var rewrittenDnf = rewriter.rewriteWithContext(context, targetDnf);
117 workList.addFirst(abstractCallLiteral.withTarget(rewrittenDnf));
118 workList.addFirst(contextCall);
119 }
120
121 private static boolean hasInputParameter(Dnf targetDnf) {
122 for (var parameter : targetDnf.getParameters()) {
123 if (parameter.getDirection() != ParameterDirection.OUT) {
124 return true;
125 }
126 }
127 return false;
128 }
129
130 private static Literal getSingleLiteral(AbstractCallLiteral abstractCallLiteral, Dnf targetDnf,
131 CallPolarity polarity) {
132 if (!(abstractCallLiteral instanceof CallLiteral callLiteral) ||
133 callLiteral.getPolarity() != polarity) {
134 return null;
135 }
136 var clauses = targetDnf.getClauses();
137 if (clauses.size() != 1) {
138 return null;
139 }
140 var targetLiterals = clauses.get(0).literals();
141 if (targetLiterals.size() != 1) {
142 return null;
143 }
144 return targetLiterals.get(0);
145 }
146
147 private static Substitution asSubstitution(AbstractCallLiteral callLiteral, Dnf targetDnf) {
148 var builder = Substitution.builder().renewing();
149 var arguments = callLiteral.getArguments();
150 var parameters = targetDnf.getSymbolicParameters();
151 int arity = arguments.size();
152 if (parameters.size() != arity) {
153 throw new IllegalArgumentException("Call %s of %s arity mismatch".formatted(callLiteral, targetDnf));
154 }
155 for (int i = 0; i < arity; i++) {
156 builder.putChecked(parameters.get(i).getVariable(), arguments.get(i));
157 }
158 return builder.build();
159 }
160}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/rewriter/CompositeRewriter.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/rewriter/CompositeRewriter.java
deleted file mode 100644
index 5b4f65e5..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/rewriter/CompositeRewriter.java
+++ /dev/null
@@ -1,29 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.rewriter;
7
8import tools.refinery.store.query.dnf.Dnf;
9
10import java.util.ArrayList;
11import java.util.List;
12
13public class CompositeRewriter implements DnfRewriter {
14 private final List<DnfRewriter> rewriterList = new ArrayList<>();
15
16 public void addFirst(DnfRewriter rewriter) {
17 rewriterList.add(rewriter);
18 }
19
20 @Override
21 public Dnf rewrite(Dnf dnf) {
22 Dnf rewrittenDnf = dnf;
23 for (int i = rewriterList.size() - 1; i >= 0; i--) {
24 var rewriter = rewriterList.get(i);
25 rewrittenDnf = rewriter.rewrite(rewrittenDnf);
26 }
27 return rewrittenDnf;
28 }
29}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/rewriter/DnfRewriter.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/rewriter/DnfRewriter.java
deleted file mode 100644
index 5d8359d1..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/rewriter/DnfRewriter.java
+++ /dev/null
@@ -1,24 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.rewriter;
7
8import tools.refinery.store.query.dnf.AnyQuery;
9import tools.refinery.store.query.dnf.Dnf;
10import tools.refinery.store.query.dnf.Query;
11
12@FunctionalInterface
13public interface DnfRewriter {
14 Dnf rewrite(Dnf dnf);
15
16 default AnyQuery rewrite(AnyQuery query) {
17 return rewrite((Query<?>) query);
18 }
19
20 default <T> Query<T> rewrite(Query<T> query) {
21 var rewrittenDnf = rewrite(query.getDnf());
22 return query.withDnf(rewrittenDnf);
23 }
24}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/rewriter/DuplicateDnfRemover.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/rewriter/DuplicateDnfRemover.java
deleted file mode 100644
index 0c786470..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/rewriter/DuplicateDnfRemover.java
+++ /dev/null
@@ -1,98 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.rewriter;
7
8import tools.refinery.store.query.dnf.Dnf;
9import tools.refinery.store.query.dnf.DnfClause;
10import tools.refinery.store.query.dnf.Query;
11import tools.refinery.store.query.equality.DnfEqualityChecker;
12import tools.refinery.store.query.literal.AbstractCallLiteral;
13import tools.refinery.store.query.literal.Literal;
14
15import java.util.ArrayList;
16import java.util.HashMap;
17import java.util.List;
18import java.util.Map;
19
20public class DuplicateDnfRemover extends AbstractRecursiveRewriter {
21 private final Map<CanonicalDnf, Dnf> dnfCache = new HashMap<>();
22 private final Map<Dnf, Query<?>> queryCache = new HashMap<>();
23
24 @Override
25 protected Dnf map(Dnf dnf) {
26 var result = super.map(dnf);
27 return dnfCache.computeIfAbsent(new CanonicalDnf(result), CanonicalDnf::getDnf);
28 }
29
30 @Override
31 protected Dnf doRewrite(Dnf dnf) {
32 var builder = Dnf.builderFrom(dnf);
33 for (var clause : dnf.getClauses()) {
34 builder.clause(rewriteClause(clause));
35 }
36 return builder.build();
37 }
38
39 private List<Literal> rewriteClause(DnfClause clause) {
40 var originalLiterals = clause.literals();
41 var literals = new ArrayList<Literal>(originalLiterals.size());
42 for (var literal : originalLiterals) {
43 var rewrittenLiteral = literal;
44 if (literal instanceof AbstractCallLiteral abstractCallLiteral &&
45 abstractCallLiteral.getTarget() instanceof Dnf targetDnf) {
46 var rewrittenTarget = rewrite(targetDnf);
47 rewrittenLiteral = abstractCallLiteral.withTarget(rewrittenTarget);
48 }
49 literals.add(rewrittenLiteral);
50 }
51 return literals;
52 }
53
54 @Override
55 public <T> Query<T> rewrite(Query<T> query) {
56 var rewrittenDnf = rewrite(query.getDnf());
57 // {@code withDnf} will always return the appropriate type.
58 @SuppressWarnings("unchecked")
59 var rewrittenQuery = (Query<T>) queryCache.computeIfAbsent(rewrittenDnf, query::withDnf);
60 return rewrittenQuery;
61 }
62
63 private static class CanonicalDnf {
64 private final Dnf dnf;
65 private final int hash;
66
67 public CanonicalDnf(Dnf dnf) {
68 this.dnf = dnf;
69 hash = dnf.hashCodeWithSubstitution();
70 }
71
72 public Dnf getDnf() {
73 return dnf;
74 }
75
76 @Override
77 public boolean equals(Object obj) {
78 if (this == obj) {
79 return true;
80 }
81 if (obj == null || getClass() != obj.getClass()) {
82 return false;
83 }
84 var otherCanonicalDnf = (CanonicalDnf) obj;
85 return dnf.equalsWithSubstitution(DnfEqualityChecker.DEFAULT, otherCanonicalDnf.dnf);
86 }
87
88 @Override
89 public int hashCode() {
90 return hash;
91 }
92
93 @Override
94 public String toString() {
95 return dnf.name();
96 }
97 }
98}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/rewriter/InputParameterResolver.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/rewriter/InputParameterResolver.java
deleted file mode 100644
index cd8a2e7d..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/rewriter/InputParameterResolver.java
+++ /dev/null
@@ -1,51 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.rewriter;
7
8import tools.refinery.store.query.dnf.Dnf;
9import tools.refinery.store.query.dnf.DnfBuilder;
10import tools.refinery.store.query.literal.Literal;
11import tools.refinery.store.query.term.ParameterDirection;
12import tools.refinery.store.query.term.Variable;
13
14import java.util.HashSet;
15import java.util.List;
16
17public class InputParameterResolver extends AbstractRecursiveRewriter {
18 @Override
19 protected Dnf doRewrite(Dnf dnf) {
20 return rewriteWithContext(List.of(), dnf);
21 }
22
23 Dnf rewriteWithContext(List<Literal> context, Dnf dnf) {
24 var dnfName = dnf.name();
25 var builder = Dnf.builder(dnfName);
26 createSymbolicParameters(context, dnf, builder);
27 builder.functionalDependencies(dnf.getFunctionalDependencies());
28 var clauses = dnf.getClauses();
29 int clauseCount = clauses.size();
30 for (int i = 0; i < clauseCount; i++) {
31 var clause = clauses.get(i);
32 var clauseRewriter = new ClauseInputParameterResolver(this, context, clause, dnfName, i);
33 builder.clause(clauseRewriter.rewriteClause());
34 }
35 return builder.build();
36 }
37
38 private static void createSymbolicParameters(List<Literal> context, Dnf dnf, DnfBuilder builder) {
39 var positiveInContext = new HashSet<Variable>();
40 for (var literal : context) {
41 positiveInContext.addAll(literal.getOutputVariables());
42 }
43 for (var symbolicParameter : dnf.getSymbolicParameters()) {
44 var variable = symbolicParameter.getVariable();
45 var isOutput = symbolicParameter.getDirection() == ParameterDirection.OUT ||
46 positiveInContext.contains(variable);
47 var direction = isOutput ? ParameterDirection.OUT : ParameterDirection.IN;
48 builder.parameter(variable, direction);
49 }
50 }
51}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/substitution/MapBasedSubstitution.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/substitution/MapBasedSubstitution.java
deleted file mode 100644
index a8201eef..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/substitution/MapBasedSubstitution.java
+++ /dev/null
@@ -1,18 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.substitution;
7
8import tools.refinery.store.query.term.Variable;
9
10import java.util.Map;
11
12public record MapBasedSubstitution(Map<Variable, Variable> map, Substitution fallback) implements Substitution {
13 @Override
14 public Variable getSubstitute(Variable variable) {
15 var value = map.get(variable);
16 return value == null ? fallback.getSubstitute(variable) : value;
17 }
18}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/substitution/RenewingSubstitution.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/substitution/RenewingSubstitution.java
deleted file mode 100644
index 9b737ceb..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/substitution/RenewingSubstitution.java
+++ /dev/null
@@ -1,20 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.substitution;
7
8import tools.refinery.store.query.term.Variable;
9
10import java.util.HashMap;
11import java.util.Map;
12
13public class RenewingSubstitution implements Substitution {
14 private final Map<Variable, Variable> alreadyRenewed = new HashMap<>();
15
16 @Override
17 public Variable getSubstitute(Variable variable) {
18 return alreadyRenewed.computeIfAbsent(variable, Variable::renew);
19 }
20}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/substitution/StatelessSubstitution.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/substitution/StatelessSubstitution.java
deleted file mode 100644
index bb3803d3..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/substitution/StatelessSubstitution.java
+++ /dev/null
@@ -1,23 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.substitution;
7
8import tools.refinery.store.query.term.Variable;
9
10public enum StatelessSubstitution implements Substitution {
11 FAILING {
12 @Override
13 public Variable getSubstitute(Variable variable) {
14 throw new IllegalArgumentException("No substitute for " + variable);
15 }
16 },
17 IDENTITY {
18 @Override
19 public Variable getSubstitute(Variable variable) {
20 return variable;
21 }
22 }
23}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/substitution/Substitution.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/substitution/Substitution.java
deleted file mode 100644
index 834fce12..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/substitution/Substitution.java
+++ /dev/null
@@ -1,29 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.substitution;
7
8import tools.refinery.store.query.term.DataVariable;
9import tools.refinery.store.query.term.NodeVariable;
10import tools.refinery.store.query.term.Variable;
11
12@FunctionalInterface
13public interface Substitution {
14 Variable getSubstitute(Variable variable);
15
16 default NodeVariable getTypeSafeSubstitute(NodeVariable variable) {
17 var substitute = getSubstitute(variable);
18 return substitute.asNodeVariable();
19 }
20
21 default <T> DataVariable<T> getTypeSafeSubstitute(DataVariable<T> variable) {
22 var substitute = getSubstitute(variable);
23 return substitute.asDataVariable(variable.getType());
24 }
25
26 static SubstitutionBuilder builder() {
27 return new SubstitutionBuilder();
28 }
29}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/substitution/SubstitutionBuilder.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/substitution/SubstitutionBuilder.java
deleted file mode 100644
index 37fb6908..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/substitution/SubstitutionBuilder.java
+++ /dev/null
@@ -1,79 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.substitution;
7
8import tools.refinery.store.query.term.DataVariable;
9import tools.refinery.store.query.term.NodeVariable;
10import tools.refinery.store.query.term.Variable;
11
12import java.util.Collections;
13import java.util.HashMap;
14import java.util.List;
15import java.util.Map;
16
17@SuppressWarnings("UnusedReturnValue")
18public class SubstitutionBuilder {
19 private final Map<Variable, Variable> map = new HashMap<>();
20 private Substitution fallback;
21
22 SubstitutionBuilder() {
23 total();
24 }
25
26 public SubstitutionBuilder put(NodeVariable original, NodeVariable substitute) {
27 return putChecked(original, substitute);
28 }
29
30 public <T> SubstitutionBuilder put(DataVariable<T> original, DataVariable<T> substitute) {
31 return putChecked(original, substitute);
32 }
33
34 public SubstitutionBuilder putChecked(Variable original, Variable substitute) {
35 if (!original.tryGetType().equals(substitute.tryGetType())) {
36 throw new IllegalArgumentException("Cannot substitute variable %s of sort %s with variable %s of sort %s"
37 .formatted(original, original.tryGetType().map(Class::getName).orElse("node"), substitute,
38 substitute.tryGetType().map(Class::getName).orElse("node")));
39 }
40 if (map.containsKey(original)) {
41 throw new IllegalArgumentException("Already has substitution for variable %s".formatted(original));
42 }
43 map.put(original, substitute);
44 return this;
45 }
46
47 public SubstitutionBuilder putManyChecked(List<Variable> originals, List<Variable> substitutes) {
48 int size = originals.size();
49 if (size != substitutes.size()) {
50 throw new IllegalArgumentException("Cannot substitute %d variables %s with %d variables %s"
51 .formatted(size, originals, substitutes.size(), substitutes));
52 }
53 for (int i = 0; i < size; i++) {
54 putChecked(originals.get(i), substitutes.get(i));
55 }
56 return this;
57 }
58
59 public SubstitutionBuilder fallback(Substitution newFallback) {
60 fallback = newFallback;
61 return this;
62 }
63
64 public SubstitutionBuilder total() {
65 return fallback(StatelessSubstitution.FAILING);
66 }
67
68 public SubstitutionBuilder partial() {
69 return fallback(StatelessSubstitution.IDENTITY);
70 }
71
72 public SubstitutionBuilder renewing() {
73 return fallback(new RenewingSubstitution());
74 }
75
76 public Substitution build() {
77 return map.isEmpty() ? fallback : new MapBasedSubstitution(Collections.unmodifiableMap(map), fallback);
78 }
79}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/AbstractTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/AbstractTerm.java
deleted file mode 100644
index 5cecc35b..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/AbstractTerm.java
+++ /dev/null
@@ -1,47 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.term;
7
8import tools.refinery.store.query.equality.LiteralEqualityHelper;
9import tools.refinery.store.query.equality.LiteralHashCodeHelper;
10
11import java.util.Objects;
12
13public abstract class AbstractTerm<T> implements Term<T> {
14 private final Class<T> type;
15
16 protected AbstractTerm(Class<T> type) {
17 this.type = type;
18 }
19
20 @Override
21 public Class<T> getType() {
22 return type;
23 }
24
25 @Override
26 public boolean equalsWithSubstitution(LiteralEqualityHelper helper, AnyTerm other) {
27 return other != null && getClass() == other.getClass() && type.equals(other.getType());
28 }
29
30 @Override
31 public int hashCodeWithSubstitution(LiteralHashCodeHelper helper) {
32 return Objects.hash(getClass(), type);
33 }
34
35 @Override
36 public boolean equals(Object o) {
37 if (this == o) return true;
38 if (o == null || getClass() != o.getClass()) return false;
39 AbstractTerm<?> that = (AbstractTerm<?>) o;
40 return equalsWithSubstitution(LiteralEqualityHelper.DEFAULT, that);
41 }
42
43 @Override
44 public int hashCode() {
45 return hashCodeWithSubstitution(LiteralHashCodeHelper.DEFAULT);
46 }
47}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/Aggregator.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/Aggregator.java
deleted file mode 100644
index 0684a9d9..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/Aggregator.java
+++ /dev/null
@@ -1,18 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.term;
7
8import java.util.stream.Stream;
9
10public interface Aggregator<R, T> {
11 Class<R> getResultType();
12
13 Class<T> getInputType();
14
15 R aggregateStream(Stream<T> stream);
16
17 R getEmptyResult();
18}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/AnyDataVariable.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/AnyDataVariable.java
deleted file mode 100644
index 3801bc11..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/AnyDataVariable.java
+++ /dev/null
@@ -1,55 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.term;
7
8import org.jetbrains.annotations.Nullable;
9import tools.refinery.store.query.InvalidQueryException;
10import tools.refinery.store.query.equality.LiteralEqualityHelper;
11
12import java.util.Optional;
13import java.util.Set;
14
15public abstract sealed class AnyDataVariable extends Variable implements AnyTerm permits DataVariable {
16 protected AnyDataVariable(String name) {
17 super(name);
18 }
19
20 @Override
21 public Optional<Class<?>> tryGetType() {
22 return Optional.of(getType());
23 }
24
25 @Override
26 public boolean isNodeVariable() {
27 return false;
28 }
29
30 @Override
31 public boolean isDataVariable() {
32 return true;
33 }
34
35 @Override
36 public NodeVariable asNodeVariable() {
37 throw new InvalidQueryException("%s is a data variable".formatted(this));
38 }
39
40 @Override
41 public boolean equalsWithSubstitution(LiteralEqualityHelper helper, AnyTerm other) {
42 return other instanceof AnyDataVariable dataVariable && helper.variableEqual(this, dataVariable);
43 }
44
45 @Override
46 public Set<AnyDataVariable> getInputVariables() {
47 return Set.of(this);
48 }
49
50 @Override
51 public abstract AnyDataVariable renew(@Nullable String name);
52
53 @Override
54 public abstract AnyDataVariable renew();
55}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/AnyTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/AnyTerm.java
deleted file mode 100644
index f136b68d..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/AnyTerm.java
+++ /dev/null
@@ -1,24 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.term;
7
8import tools.refinery.store.query.equality.LiteralEqualityHelper;
9import tools.refinery.store.query.equality.LiteralHashCodeHelper;
10import tools.refinery.store.query.substitution.Substitution;
11
12import java.util.Set;
13
14public sealed interface AnyTerm permits AnyDataVariable, Term {
15 Class<?> getType();
16
17 AnyTerm substitute(Substitution substitution);
18
19 boolean equalsWithSubstitution(LiteralEqualityHelper helper, AnyTerm other);
20
21 int hashCodeWithSubstitution(LiteralHashCodeHelper helper);
22
23 Set<AnyDataVariable> getInputVariables();
24}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/AssignedValue.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/AssignedValue.java
deleted file mode 100644
index 0cf30aa6..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/AssignedValue.java
+++ /dev/null
@@ -1,13 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.term;
7
8import tools.refinery.store.query.literal.Literal;
9
10@FunctionalInterface
11public interface AssignedValue<T> {
12 Literal toLiteral(DataVariable<T> targetVariable);
13}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/BinaryTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/BinaryTerm.java
deleted file mode 100644
index cdbf592a..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/BinaryTerm.java
+++ /dev/null
@@ -1,106 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.term;
7
8import tools.refinery.store.query.InvalidQueryException;
9import tools.refinery.store.query.equality.LiteralEqualityHelper;
10import tools.refinery.store.query.equality.LiteralHashCodeHelper;
11import tools.refinery.store.query.substitution.Substitution;
12import tools.refinery.store.query.valuation.Valuation;
13
14import java.util.Collections;
15import java.util.HashSet;
16import java.util.Objects;
17import java.util.Set;
18
19// {@link Object#equals(Object)} is implemented by {@link AbstractTerm}.
20@SuppressWarnings("squid:S2160")
21public abstract class BinaryTerm<R, T1, T2> extends AbstractTerm<R> {
22 private final Class<T1> leftType;
23 private final Class<T2> rightType;
24 private final Term<T1> left;
25 private final Term<T2> right;
26
27 protected BinaryTerm(Class<R> type, Class<T1> leftType, Class<T2> rightType, Term<T1> left, Term<T2> right) {
28 super(type);
29 if (!left.getType().equals(leftType)) {
30 throw new InvalidQueryException("Expected left %s to be of type %s, got %s instead".formatted(
31 left, leftType.getName(), left.getType().getName()));
32 }
33 if (!right.getType().equals(rightType)) {
34 throw new InvalidQueryException("Expected right %s to be of type %s, got %s instead".formatted(
35 right, rightType.getName(), right.getType().getName()));
36 }
37 this.leftType = leftType;
38 this.rightType = rightType;
39 this.left = left;
40 this.right = right;
41 }
42
43 public Class<T1> getLeftType() {
44 return leftType;
45 }
46
47 public Class<T2> getRightType() {
48 return rightType;
49 }
50
51 public Term<T1> getLeft() {
52 return left;
53 }
54
55 public Term<T2> getRight() {
56 return right;
57 }
58
59 @Override
60 public R evaluate(Valuation valuation) {
61 var leftValue = left.evaluate(valuation);
62 if (leftValue == null) {
63 return null;
64 }
65 var rightValue = right.evaluate(valuation);
66 if (rightValue == null) {
67 return null;
68 }
69 return doEvaluate(leftValue, rightValue);
70 }
71
72 protected abstract R doEvaluate(T1 leftValue, T2 rightValue);
73
74 @Override
75 public boolean equalsWithSubstitution(LiteralEqualityHelper helper, AnyTerm other) {
76 if (!super.equalsWithSubstitution(helper, other)) {
77 return false;
78 }
79 var otherBinaryTerm = (BinaryTerm<?, ?, ?>) other;
80 return leftType.equals(otherBinaryTerm.leftType) &&
81 rightType.equals(otherBinaryTerm.rightType) &&
82 left.equalsWithSubstitution(helper, otherBinaryTerm.left) &&
83 right.equalsWithSubstitution(helper, otherBinaryTerm.right);
84 }
85
86 @Override
87 public int hashCodeWithSubstitution(LiteralHashCodeHelper helper) {
88 return Objects.hash(super.hashCodeWithSubstitution(helper), leftType.hashCode(), rightType.hashCode(),
89 left.hashCodeWithSubstitution(helper), right.hashCodeWithSubstitution(helper));
90 }
91
92 @Override
93 public Term<R> substitute(Substitution substitution) {
94 return doSubstitute(substitution, left.substitute(substitution), right.substitute(substitution));
95 }
96
97 public abstract Term<R> doSubstitute(Substitution substitution, Term<T1> substitutedLeft,
98 Term<T2> substitutedRight);
99
100 @Override
101 public Set<AnyDataVariable> getInputVariables() {
102 var inputVariables = new HashSet<>(left.getInputVariables());
103 inputVariables.addAll(right.getInputVariables());
104 return Collections.unmodifiableSet(inputVariables);
105 }
106}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/ConstantTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/ConstantTerm.java
deleted file mode 100644
index 415ae286..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/ConstantTerm.java
+++ /dev/null
@@ -1,67 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.term;
7
8import tools.refinery.store.query.InvalidQueryException;
9import tools.refinery.store.query.equality.LiteralEqualityHelper;
10import tools.refinery.store.query.equality.LiteralHashCodeHelper;
11import tools.refinery.store.query.substitution.Substitution;
12import tools.refinery.store.query.valuation.Valuation;
13
14import java.util.Objects;
15import java.util.Set;
16
17// {@link Object#equals(Object)} is implemented by {@link AbstractTerm}.
18@SuppressWarnings("squid:S2160")
19public final class ConstantTerm<T> extends AbstractTerm<T> {
20 private final T value;
21
22 public ConstantTerm(Class<T> type, T value) {
23 super(type);
24 if (value != null && !type.isInstance(value)) {
25 throw new InvalidQueryException("Value %s is not an instance of %s".formatted(value, type.getName()));
26 }
27 this.value = value;
28 }
29
30 public T getValue() {
31 return value;
32 }
33
34 @Override
35 public T evaluate(Valuation valuation) {
36 return getValue();
37 }
38
39 @Override
40 public Term<T> substitute(Substitution substitution) {
41 return this;
42 }
43
44 @Override
45 public boolean equalsWithSubstitution(LiteralEqualityHelper helper, AnyTerm other) {
46 if (!super.equalsWithSubstitution(helper, other)) {
47 return false;
48 }
49 var otherConstantTerm = (ConstantTerm<?>) other;
50 return Objects.equals(value, otherConstantTerm.value);
51 }
52
53 @Override
54 public int hashCodeWithSubstitution(LiteralHashCodeHelper helper) {
55 return Objects.hash(super.hashCodeWithSubstitution(helper), Objects.hash(value));
56 }
57
58 @Override
59 public Set<AnyDataVariable> getInputVariables() {
60 return Set.of();
61 }
62
63 @Override
64 public String toString() {
65 return value.toString();
66 }
67}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/DataVariable.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/DataVariable.java
deleted file mode 100644
index 2206b522..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/DataVariable.java
+++ /dev/null
@@ -1,103 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.term;
7
8import org.jetbrains.annotations.Nullable;
9import tools.refinery.store.query.InvalidQueryException;
10import tools.refinery.store.query.equality.LiteralEqualityHelper;
11import tools.refinery.store.query.equality.LiteralHashCodeHelper;
12import tools.refinery.store.query.literal.EquivalenceLiteral;
13import tools.refinery.store.query.literal.Literal;
14import tools.refinery.store.query.substitution.Substitution;
15import tools.refinery.store.query.valuation.Valuation;
16
17import java.util.Objects;
18
19public final class DataVariable<T> extends AnyDataVariable implements Term<T> {
20 private final Class<T> type;
21
22 DataVariable(String name, Class<T> type) {
23 super(name);
24 this.type = type;
25 }
26
27 @Override
28 public Class<T> getType() {
29 return type;
30 }
31
32 @Override
33 public DataVariable<T> renew(@Nullable String name) {
34 return new DataVariable<>(name, type);
35 }
36
37 @Override
38 public DataVariable<T> renew() {
39 return renew(getExplicitName());
40 }
41
42 @Override
43 public <U> DataVariable<U> asDataVariable(Class<U> newType) {
44 if (!getType().equals(newType)) {
45 throw new InvalidQueryException("%s is not of type %s but of type %s"
46 .formatted(this, newType.getName(), getType().getName()));
47 }
48 @SuppressWarnings("unchecked")
49 var result = (DataVariable<U>) this;
50 return result;
51 }
52
53 @Override
54 public T evaluate(Valuation valuation) {
55 return valuation.getValue(this);
56 }
57
58 @Override
59 public Term<T> substitute(Substitution substitution) {
60 return substitution.getTypeSafeSubstitute(this);
61 }
62
63 @Override
64 public boolean equalsWithSubstitution(LiteralEqualityHelper helper, AnyTerm other) {
65 return other instanceof DataVariable<?> dataVariable && helper.variableEqual(this, dataVariable);
66 }
67
68 @Override
69 public int hashCodeWithSubstitution(LiteralHashCodeHelper helper) {
70 return helper.getVariableHashCode(this);
71 }
72
73 @Override
74 public int hashCodeWithSubstitution(int sequenceNumber) {
75 return Objects.hash(type, sequenceNumber);
76 }
77
78 public Literal assign(AssignedValue<T> value) {
79 return value.toLiteral(this);
80 }
81
82 @Override
83 public boolean equals(Object o) {
84 if (this == o) return true;
85 if (o == null || getClass() != o.getClass()) return false;
86 if (!super.equals(o)) return false;
87 DataVariable<?> that = (DataVariable<?>) o;
88 return type.equals(that.type);
89 }
90
91 @Override
92 public int hashCode() {
93 return Objects.hash(super.hashCode(), type);
94 }
95
96 public EquivalenceLiteral isEquivalent(DataVariable<T> other) {
97 return new EquivalenceLiteral(true, this, other);
98 }
99
100 public EquivalenceLiteral notEquivalent(DataVariable<T> other) {
101 return new EquivalenceLiteral(false, this, other);
102 }
103}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/ExtremeValueAggregator.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/ExtremeValueAggregator.java
deleted file mode 100644
index 657cb631..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/ExtremeValueAggregator.java
+++ /dev/null
@@ -1,108 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.term;
7
8import java.util.Comparator;
9import java.util.Objects;
10import java.util.SortedMap;
11import java.util.TreeMap;
12
13public class ExtremeValueAggregator<T> implements StatefulAggregator<T, T> {
14 private final Class<T> type;
15 private final T emptyResult;
16 private final Comparator<T> comparator;
17
18 public ExtremeValueAggregator(Class<T> type, T emptyResult) {
19 this(type, emptyResult, null);
20 }
21
22 public ExtremeValueAggregator(Class<T> type, T emptyResult, Comparator<T> comparator) {
23 this.type = type;
24 this.emptyResult = emptyResult;
25 this.comparator = comparator;
26 }
27
28 @Override
29 public Class<T> getResultType() {
30 return getInputType();
31 }
32
33 @Override
34 public Class<T> getInputType() {
35 return type;
36 }
37
38 @Override
39 public StatefulAggregate<T, T> createEmptyAggregate() {
40 return new Aggregate();
41 }
42
43 @Override
44 public T getEmptyResult() {
45 return emptyResult;
46 }
47
48 @Override
49 public boolean equals(Object o) {
50 if (this == o) return true;
51 if (o == null || getClass() != o.getClass()) return false;
52 ExtremeValueAggregator<?> that = (ExtremeValueAggregator<?>) o;
53 return type.equals(that.type) && Objects.equals(emptyResult, that.emptyResult) && Objects.equals(comparator,
54 that.comparator);
55 }
56
57 @Override
58 public int hashCode() {
59 return Objects.hash(type, emptyResult, comparator);
60 }
61
62 private class Aggregate implements StatefulAggregate<T, T> {
63 private final SortedMap<T, Integer> values;
64
65 private Aggregate() {
66 values = new TreeMap<>(comparator);
67 }
68
69 private Aggregate(Aggregate other) {
70 values = new TreeMap<>(other.values);
71 }
72
73 @Override
74 public void add(T value) {
75 values.compute(value, (ignoredValue, currentCount) -> currentCount == null ? 1 : currentCount + 1);
76 }
77
78 @Override
79 public void remove(T value) {
80 values.compute(value, (theValue, currentCount) -> {
81 if (currentCount == null || currentCount <= 0) {
82 throw new IllegalStateException("Invalid count %d for value %s".formatted(currentCount, theValue));
83 }
84 return currentCount.equals(1) ? null : currentCount - 1;
85 });
86 }
87
88 @Override
89 public T getResult() {
90 return isEmpty() ? emptyResult : values.firstKey();
91 }
92
93 @Override
94 public boolean isEmpty() {
95 return values.isEmpty();
96 }
97
98 @Override
99 public StatefulAggregate<T, T> deepCopy() {
100 return new Aggregate(this);
101 }
102
103 @Override
104 public boolean contains(T value) {
105 return StatefulAggregate.super.contains(value);
106 }
107 }
108}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/NodeVariable.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/NodeVariable.java
deleted file mode 100644
index 53c32e20..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/NodeVariable.java
+++ /dev/null
@@ -1,71 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.term;
7
8import org.jetbrains.annotations.Nullable;
9import tools.refinery.store.query.InvalidQueryException;
10import tools.refinery.store.query.literal.ConstantLiteral;
11import tools.refinery.store.query.literal.EquivalenceLiteral;
12
13import java.util.Optional;
14
15public final class NodeVariable extends Variable {
16 NodeVariable(@Nullable String name) {
17 super(name);
18 }
19
20 @Override
21 public Optional<Class<?>> tryGetType() {
22 return Optional.empty();
23 }
24
25 @Override
26 public NodeVariable renew(@Nullable String name) {
27 return Variable.of(name);
28 }
29
30 @Override
31 public NodeVariable renew() {
32 return renew(getExplicitName());
33 }
34
35 @Override
36 public boolean isNodeVariable() {
37 return true;
38 }
39
40 @Override
41 public boolean isDataVariable() {
42 return false;
43 }
44
45 @Override
46 public NodeVariable asNodeVariable() {
47 return this;
48 }
49
50 @Override
51 public <T> DataVariable<T> asDataVariable(Class<T> type) {
52 throw new InvalidQueryException("%s is a node variable".formatted(this));
53 }
54
55 @Override
56 public int hashCodeWithSubstitution(int sequenceNumber) {
57 return sequenceNumber;
58 }
59
60 public ConstantLiteral isConstant(int value) {
61 return new ConstantLiteral(this, value);
62 }
63
64 public EquivalenceLiteral isEquivalent(NodeVariable other) {
65 return new EquivalenceLiteral(true, this, other);
66 }
67
68 public EquivalenceLiteral notEquivalent(NodeVariable other) {
69 return new EquivalenceLiteral(false, this, other);
70 }
71}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/Parameter.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/Parameter.java
deleted file mode 100644
index 577ac6e0..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/Parameter.java
+++ /dev/null
@@ -1,68 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.term;
7
8import java.util.Objects;
9import java.util.Optional;
10
11public class Parameter {
12 public static final Parameter NODE_OUT = new Parameter(null);
13
14 private final Class<?> dataType;
15 private final ParameterDirection direction;
16
17 public Parameter(Class<?> dataType) {
18 this(dataType, ParameterDirection.OUT);
19 }
20
21 public Parameter(Class<?> dataType, ParameterDirection direction) {
22 this.dataType = dataType;
23 this.direction = direction;
24 }
25
26 public boolean isNodeVariable() {
27 return dataType == null;
28 }
29
30 public boolean isDataVariable() {
31 return !isNodeVariable();
32 }
33
34 public Optional<Class<?>> tryGetType() {
35 return Optional.ofNullable(dataType);
36 }
37
38 public ParameterDirection getDirection() {
39 return direction;
40 }
41
42 public boolean matches(Parameter other) {
43 return Objects.equals(dataType, other.dataType) && direction == other.direction;
44 }
45
46 public boolean isAssignable(Variable variable) {
47 if (variable instanceof AnyDataVariable dataVariable) {
48 return dataVariable.getType().equals(dataType);
49 } else if (variable instanceof NodeVariable) {
50 return !isDataVariable();
51 } else {
52 throw new IllegalArgumentException("Unknown variable " + variable);
53 }
54 }
55
56 @Override
57 public boolean equals(Object o) {
58 if (this == o) return true;
59 if (o == null || getClass() != o.getClass()) return false;
60 Parameter parameter = (Parameter) o;
61 return matches(parameter);
62 }
63
64 @Override
65 public int hashCode() {
66 return Objects.hash(dataType, direction);
67 }
68}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/ParameterDirection.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/ParameterDirection.java
deleted file mode 100644
index da83f3c3..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/ParameterDirection.java
+++ /dev/null
@@ -1,22 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.term;
7
8public enum ParameterDirection {
9 OUT("out"),
10 IN("in");
11
12 private final String name;
13
14 ParameterDirection(String name) {
15 this.name = name;
16 }
17
18 @Override
19 public String toString() {
20 return name;
21 }
22}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/StatefulAggregate.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/StatefulAggregate.java
deleted file mode 100644
index ab310556..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/StatefulAggregate.java
+++ /dev/null
@@ -1,22 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.term;
7
8public interface StatefulAggregate<R, T> {
9 void add(T value);
10
11 void remove(T value);
12
13 R getResult();
14
15 boolean isEmpty();
16
17 StatefulAggregate<R, T> deepCopy();
18
19 default boolean contains(T value) {
20 throw new UnsupportedOperationException();
21 }
22}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/StatefulAggregator.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/StatefulAggregator.java
deleted file mode 100644
index df746a90..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/StatefulAggregator.java
+++ /dev/null
@@ -1,28 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.term;
7
8import java.util.stream.Stream;
9
10public interface StatefulAggregator<R, T> extends Aggregator<R, T> {
11 StatefulAggregate<R, T> createEmptyAggregate();
12
13 @Override
14 default R aggregateStream(Stream<T> stream) {
15 var accumulator = createEmptyAggregate();
16 var iterator = stream.iterator();
17 while (iterator.hasNext()) {
18 var value = iterator.next();
19 accumulator.add(value);
20 }
21 return accumulator.getResult();
22 }
23
24 @Override
25 default R getEmptyResult() {
26 return createEmptyAggregate().getResult();
27 }
28}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/StatelessAggregator.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/StatelessAggregator.java
deleted file mode 100644
index a094919e..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/StatelessAggregator.java
+++ /dev/null
@@ -1,25 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.term;
7
8import java.util.stream.Stream;
9
10public interface StatelessAggregator<R, T> extends Aggregator<R, T> {
11 R add(R current, T value);
12
13 R remove(R current, T value);
14
15 @Override
16 default R aggregateStream(Stream<T> stream) {
17 var accumulator = getEmptyResult();
18 var iterator = stream.iterator();
19 while (iterator.hasNext()) {
20 var value = iterator.next();
21 accumulator = add(accumulator, value);
22 }
23 return accumulator;
24 }
25}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/Term.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/Term.java
deleted file mode 100644
index e6818b88..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/Term.java
+++ /dev/null
@@ -1,26 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.term;
7
8import tools.refinery.store.query.literal.AssignLiteral;
9import tools.refinery.store.query.literal.Literal;
10import tools.refinery.store.query.substitution.Substitution;
11import tools.refinery.store.query.valuation.Valuation;
12
13public non-sealed interface Term<T> extends AnyTerm, AssignedValue<T> {
14 @Override
15 Class<T> getType();
16
17 T evaluate(Valuation valuation);
18
19 @Override
20 Term<T> substitute(Substitution substitution);
21
22 @Override
23 default Literal toLiteral(DataVariable<T> targetVariable) {
24 return new AssignLiteral<>(targetVariable, this);
25 }
26}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/UnaryTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/UnaryTerm.java
deleted file mode 100644
index a464ece5..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/UnaryTerm.java
+++ /dev/null
@@ -1,74 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.term;
7
8import tools.refinery.store.query.InvalidQueryException;
9import tools.refinery.store.query.equality.LiteralEqualityHelper;
10import tools.refinery.store.query.equality.LiteralHashCodeHelper;
11import tools.refinery.store.query.substitution.Substitution;
12import tools.refinery.store.query.valuation.Valuation;
13
14import java.util.Objects;
15import java.util.Set;
16
17// {@link Object#equals(Object)} is implemented by {@link AbstractTerm}.
18@SuppressWarnings("squid:S2160")
19public abstract class UnaryTerm<R, T> extends AbstractTerm<R> {
20 private final Class<T> bodyType;
21 private final Term<T> body;
22
23 protected UnaryTerm(Class<R> type, Class<T> bodyType, Term<T> body) {
24 super(type);
25 if (!body.getType().equals(bodyType)) {
26 throw new InvalidQueryException("Expected body %s to be of type %s, got %s instead".formatted(body,
27 bodyType.getName(), body.getType().getName()));
28 }
29 this.bodyType = bodyType;
30 this.body = body;
31 }
32
33 public Class<T> getBodyType() {
34 return bodyType;
35 }
36
37 public Term<T> getBody() {
38 return body;
39 }
40
41 @Override
42 public R evaluate(Valuation valuation) {
43 var bodyValue = body.evaluate(valuation);
44 return bodyValue == null ? null : doEvaluate(bodyValue);
45 }
46
47 protected abstract R doEvaluate(T bodyValue);
48
49 @Override
50 public boolean equalsWithSubstitution(LiteralEqualityHelper helper, AnyTerm other) {
51 if (!super.equalsWithSubstitution(helper, other)) {
52 return false;
53 }
54 var otherUnaryTerm = (UnaryTerm<?, ?>) other;
55 return bodyType.equals(otherUnaryTerm.bodyType) && body.equalsWithSubstitution(helper, otherUnaryTerm.body);
56 }
57
58 @Override
59 public int hashCodeWithSubstitution(LiteralHashCodeHelper helper) {
60 return Objects.hash(super.hashCodeWithSubstitution(helper), bodyType, body.hashCodeWithSubstitution(helper));
61 }
62
63 @Override
64 public Term<R> substitute(Substitution substitution) {
65 return doSubstitute(substitution, body.substitute(substitution));
66 }
67
68 protected abstract Term<R> doSubstitute(Substitution substitution, Term<T> substitutedBody);
69
70 @Override
71 public Set<AnyDataVariable> getInputVariables() {
72 return body.getInputVariables();
73 }
74}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/Variable.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/Variable.java
deleted file mode 100644
index 1b553704..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/Variable.java
+++ /dev/null
@@ -1,88 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.term;
7
8import org.jetbrains.annotations.Nullable;
9import tools.refinery.store.query.dnf.DnfUtils;
10
11import java.util.Objects;
12import java.util.Optional;
13
14public abstract sealed class Variable permits AnyDataVariable, NodeVariable {
15 private final String explicitName;
16 private final String uniqueName;
17
18 protected Variable(String name) {
19 this.explicitName = name;
20 uniqueName = DnfUtils.generateUniqueName(name);
21 }
22
23 public abstract Optional<Class<?>> tryGetType();
24
25 public String getName() {
26 return explicitName == null ? uniqueName : explicitName;
27 }
28
29 protected String getExplicitName() {
30 return explicitName;
31 }
32
33 public boolean isExplicitlyNamed() {
34 return explicitName != null;
35 }
36
37 public String getUniqueName() {
38 return uniqueName;
39 }
40
41 public abstract Variable renew(@Nullable String name);
42
43 public abstract Variable renew();
44
45 public abstract boolean isNodeVariable();
46
47 public abstract boolean isDataVariable();
48
49 public abstract NodeVariable asNodeVariable();
50
51 public abstract <T> DataVariable<T> asDataVariable(Class<T> type);
52
53 public abstract int hashCodeWithSubstitution(int sequenceNumber);
54
55 @Override
56 public String toString() {
57 return getName();
58 }
59
60 @Override
61 public boolean equals(Object o) {
62 if (this == o) return true;
63 if (o == null || getClass() != o.getClass()) return false;
64 Variable variable = (Variable) o;
65 return Objects.equals(uniqueName, variable.uniqueName);
66 }
67
68 @Override
69 public int hashCode() {
70 return Objects.hash(uniqueName);
71 }
72
73 public static NodeVariable of(@Nullable String name) {
74 return new NodeVariable(name);
75 }
76
77 public static NodeVariable of() {
78 return of((String) null);
79 }
80
81 public static <T> DataVariable<T> of(@Nullable String name, Class<T> type) {
82 return new DataVariable<>(name, type);
83 }
84
85 public static <T> DataVariable<T> of(Class<T> type) {
86 return of(null, type);
87 }
88}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/BoolAndTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/BoolAndTerm.java
deleted file mode 100644
index f9e1c06f..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/BoolAndTerm.java
+++ /dev/null
@@ -1,31 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.term.bool;
7
8import tools.refinery.store.query.substitution.Substitution;
9import tools.refinery.store.query.term.Term;
10
11public class BoolAndTerm extends BoolBinaryTerm {
12 public BoolAndTerm(Term<Boolean> left, Term<Boolean> right) {
13 super(left, right);
14 }
15
16 @Override
17 public Term<Boolean> doSubstitute(Substitution substitution, Term<Boolean> substitutedLeft,
18 Term<Boolean> substitutedRight) {
19 return new BoolAndTerm(substitutedLeft, substitutedRight);
20 }
21
22 @Override
23 protected Boolean doEvaluate(Boolean leftValue, Boolean rightValue) {
24 return leftValue && rightValue;
25 }
26
27 @Override
28 public String toString() {
29 return "(%s && %s)".formatted(getLeft(), getRight());
30 }
31}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/BoolBinaryTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/BoolBinaryTerm.java
deleted file mode 100644
index a85aa63a..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/BoolBinaryTerm.java
+++ /dev/null
@@ -1,15 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.term.bool;
7
8import tools.refinery.store.query.term.BinaryTerm;
9import tools.refinery.store.query.term.Term;
10
11public abstract class BoolBinaryTerm extends BinaryTerm<Boolean, Boolean, Boolean> {
12 protected BoolBinaryTerm(Term<Boolean> left, Term<Boolean> right) {
13 super(Boolean.class, Boolean.class, Boolean.class, left, right);
14 }
15}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/BoolNotTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/BoolNotTerm.java
deleted file mode 100644
index 8d3382b3..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/BoolNotTerm.java
+++ /dev/null
@@ -1,31 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.term.bool;
7
8import tools.refinery.store.query.substitution.Substitution;
9import tools.refinery.store.query.term.Term;
10import tools.refinery.store.query.term.UnaryTerm;
11
12public class BoolNotTerm extends UnaryTerm<Boolean, Boolean> {
13 protected BoolNotTerm(Term<Boolean> body) {
14 super(Boolean.class, Boolean.class, body);
15 }
16
17 @Override
18 protected Term<Boolean> doSubstitute(Substitution substitution, Term<Boolean> substitutedBody) {
19 return new BoolNotTerm(substitutedBody);
20 }
21
22 @Override
23 protected Boolean doEvaluate(Boolean bodyValue) {
24 return !bodyValue;
25 }
26
27 @Override
28 public String toString() {
29 return "(!%s)".formatted(getBody());
30 }
31}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/BoolOrTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/BoolOrTerm.java
deleted file mode 100644
index b5195d52..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/BoolOrTerm.java
+++ /dev/null
@@ -1,31 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.term.bool;
7
8import tools.refinery.store.query.substitution.Substitution;
9import tools.refinery.store.query.term.Term;
10
11public class BoolOrTerm extends BoolBinaryTerm {
12 public BoolOrTerm(Term<Boolean> left, Term<Boolean> right) {
13 super(left, right);
14 }
15
16 @Override
17 public Term<Boolean> doSubstitute(Substitution substitution, Term<Boolean> substitutedLeft,
18 Term<Boolean> substitutedRight) {
19 return new BoolOrTerm(substitutedLeft, substitutedRight);
20 }
21
22 @Override
23 protected Boolean doEvaluate(Boolean leftValue, Boolean rightValue) {
24 return leftValue || rightValue;
25 }
26
27 @Override
28 public String toString() {
29 return "(%s || %s)".formatted(getLeft(), getRight());
30 }
31}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/BoolTerms.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/BoolTerms.java
deleted file mode 100644
index fa54f686..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/BoolTerms.java
+++ /dev/null
@@ -1,35 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.term.bool;
7
8import tools.refinery.store.query.term.ConstantTerm;
9import tools.refinery.store.query.term.Term;
10
11public final class BoolTerms {
12 private BoolTerms() {
13 throw new IllegalArgumentException("This is a static utility class and should not be instantiated directly");
14 }
15
16 public static Term<Boolean> constant(Boolean value) {
17 return new ConstantTerm<>(Boolean.class, value);
18 }
19
20 public static Term<Boolean> not(Term<Boolean> body) {
21 return new BoolNotTerm(body);
22 }
23
24 public static Term<Boolean> and(Term<Boolean> left, Term<Boolean> right) {
25 return new BoolAndTerm(left, right);
26 }
27
28 public static Term<Boolean> or(Term<Boolean> left, Term<Boolean> right) {
29 return new BoolOrTerm(left, right);
30 }
31
32 public static Term<Boolean> xor(Term<Boolean> left, Term<Boolean> right) {
33 return new BoolXorTerm(left, right);
34 }
35}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/BoolXorTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/BoolXorTerm.java
deleted file mode 100644
index 7478b8a5..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/BoolXorTerm.java
+++ /dev/null
@@ -1,31 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.term.bool;
7
8import tools.refinery.store.query.substitution.Substitution;
9import tools.refinery.store.query.term.Term;
10
11public class BoolXorTerm extends BoolBinaryTerm {
12 public BoolXorTerm(Term<Boolean> left, Term<Boolean> right) {
13 super(left, right);
14 }
15
16 @Override
17 public Term<Boolean> doSubstitute(Substitution substitution, Term<Boolean> substitutedLeft,
18 Term<Boolean> substitutedRight) {
19 return new BoolXorTerm(substitutedLeft, substitutedRight);
20 }
21
22 @Override
23 protected Boolean doEvaluate(Boolean leftValue, Boolean rightValue) {
24 return leftValue ^ rightValue;
25 }
26
27 @Override
28 public String toString() {
29 return "(%s ^^ %s)".formatted(getLeft(), getRight());
30 }
31}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/comparable/ComparisonTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/comparable/ComparisonTerm.java
deleted file mode 100644
index 5ca5a0a1..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/comparable/ComparisonTerm.java
+++ /dev/null
@@ -1,19 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.term.comparable;
7
8import tools.refinery.store.query.term.BinaryTerm;
9import tools.refinery.store.query.term.Term;
10
11public abstract class ComparisonTerm<T> extends BinaryTerm<Boolean, T, T> {
12 protected ComparisonTerm(Class<T> argumentType, Term<T> left, Term<T> right) {
13 super(Boolean.class, argumentType, argumentType, left, right);
14 }
15
16 public Class<T> getArgumentType() {
17 return getLeftType();
18 }
19}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/comparable/EqTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/comparable/EqTerm.java
deleted file mode 100644
index b8cf36f8..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/comparable/EqTerm.java
+++ /dev/null
@@ -1,30 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.term.comparable;
7
8import tools.refinery.store.query.substitution.Substitution;
9import tools.refinery.store.query.term.Term;
10
11public class EqTerm<T> extends ComparisonTerm<T> {
12 public EqTerm(Class<T> argumentType, Term<T> left, Term<T> right) {
13 super(argumentType, left, right);
14 }
15
16 @Override
17 protected Boolean doEvaluate(T leftValue, T rightValue) {
18 return leftValue.equals(rightValue);
19 }
20
21 @Override
22 public Term<Boolean> doSubstitute(Substitution substitution, Term<T> substitutedLeft, Term<T> substitutedRight) {
23 return new EqTerm<>(getArgumentType(), substitutedLeft, substitutedRight);
24 }
25
26 @Override
27 public String toString() {
28 return "(%s == %s)".formatted(getLeft(), getRight());
29 }
30}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/comparable/GreaterEqTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/comparable/GreaterEqTerm.java
deleted file mode 100644
index b109eb1a..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/comparable/GreaterEqTerm.java
+++ /dev/null
@@ -1,30 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.term.comparable;
7
8import tools.refinery.store.query.substitution.Substitution;
9import tools.refinery.store.query.term.Term;
10
11public class GreaterEqTerm<T extends Comparable<T>> extends ComparisonTerm<T> {
12 public GreaterEqTerm(Class<T> argumentType, Term<T> left, Term<T> right) {
13 super(argumentType, left, right);
14 }
15
16 @Override
17 protected Boolean doEvaluate(T leftValue, T rightValue) {
18 return leftValue.compareTo(rightValue) >= 0;
19 }
20
21 @Override
22 public Term<Boolean> doSubstitute(Substitution substitution, Term<T> substitutedLeft, Term<T> substitutedRight) {
23 return new GreaterEqTerm<>(getArgumentType(), substitutedLeft, substitutedRight);
24 }
25
26 @Override
27 public String toString() {
28 return "(%s >= %s)".formatted(getLeft(), getRight());
29 }
30}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/comparable/GreaterTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/comparable/GreaterTerm.java
deleted file mode 100644
index 1b67f8b5..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/comparable/GreaterTerm.java
+++ /dev/null
@@ -1,30 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.term.comparable;
7
8import tools.refinery.store.query.substitution.Substitution;
9import tools.refinery.store.query.term.Term;
10
11public class GreaterTerm<T extends Comparable<T>> extends ComparisonTerm<T> {
12 public GreaterTerm(Class<T> argumentType, Term<T> left, Term<T> right) {
13 super(argumentType, left, right);
14 }
15
16 @Override
17 protected Boolean doEvaluate(T leftValue, T rightValue) {
18 return leftValue.compareTo(rightValue) > 0;
19 }
20
21 @Override
22 public Term<Boolean> doSubstitute(Substitution substitution, Term<T> substitutedLeft, Term<T> substitutedRight) {
23 return new GreaterTerm<>(getArgumentType(), substitutedLeft, substitutedRight);
24 }
25
26 @Override
27 public String toString() {
28 return "(%s > %s)".formatted(getLeft(), getRight());
29 }
30}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/comparable/LessEqTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/comparable/LessEqTerm.java
deleted file mode 100644
index 1b34535f..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/comparable/LessEqTerm.java
+++ /dev/null
@@ -1,30 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.term.comparable;
7
8import tools.refinery.store.query.substitution.Substitution;
9import tools.refinery.store.query.term.Term;
10
11public class LessEqTerm<T extends Comparable<T>> extends ComparisonTerm<T> {
12 public LessEqTerm(Class<T> argumentType, Term<T> left, Term<T> right) {
13 super(argumentType, left, right);
14 }
15
16 @Override
17 protected Boolean doEvaluate(T leftValue, T rightValue) {
18 return leftValue.compareTo(rightValue) <= 0;
19 }
20
21 @Override
22 public Term<Boolean> doSubstitute(Substitution substitution, Term<T> substitutedLeft, Term<T> substitutedRight) {
23 return new LessEqTerm<>(getArgumentType(), substitutedLeft, substitutedRight);
24 }
25
26 @Override
27 public String toString() {
28 return "(%s <= %s)".formatted(getLeft(), getRight());
29 }
30}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/comparable/LessTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/comparable/LessTerm.java
deleted file mode 100644
index 44e70902..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/comparable/LessTerm.java
+++ /dev/null
@@ -1,30 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.term.comparable;
7
8import tools.refinery.store.query.substitution.Substitution;
9import tools.refinery.store.query.term.Term;
10
11public class LessTerm<T extends Comparable<T>> extends ComparisonTerm<T> {
12 public LessTerm(Class<T> argumentType, Term<T> left, Term<T> right) {
13 super(argumentType, left, right);
14 }
15
16 @Override
17 protected Boolean doEvaluate(T leftValue, T rightValue) {
18 return leftValue.compareTo(rightValue) < 0;
19 }
20
21 @Override
22 public Term<Boolean> doSubstitute(Substitution substitution, Term<T> substitutedLeft, Term<T> substitutedRight) {
23 return new LessTerm<>(getArgumentType(), substitutedLeft, substitutedRight);
24 }
25
26 @Override
27 public String toString() {
28 return "(%s < %s)".formatted(getLeft(), getRight());
29 }
30}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/comparable/NotEqTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/comparable/NotEqTerm.java
deleted file mode 100644
index 1f9734c4..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/comparable/NotEqTerm.java
+++ /dev/null
@@ -1,30 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.term.comparable;
7
8import tools.refinery.store.query.substitution.Substitution;
9import tools.refinery.store.query.term.Term;
10
11public class NotEqTerm<T> extends ComparisonTerm<T> {
12 public NotEqTerm(Class<T> argumentType, Term<T> left, Term<T> right) {
13 super(argumentType, left, right);
14 }
15
16 @Override
17 protected Boolean doEvaluate(T leftValue, T rightValue) {
18 return !leftValue.equals(rightValue);
19 }
20
21 @Override
22 public Term<Boolean> doSubstitute(Substitution substitution, Term<T> substitutedLeft, Term<T> substitutedRight) {
23 return new NotEqTerm<>(getArgumentType(), substitutedLeft, substitutedRight);
24 }
25
26 @Override
27 public String toString() {
28 return "(%s != %s)".formatted(getLeft(), getRight());
29 }
30}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntAddTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntAddTerm.java
deleted file mode 100644
index dbea3efc..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntAddTerm.java
+++ /dev/null
@@ -1,31 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.term.int_;
7
8import tools.refinery.store.query.substitution.Substitution;
9import tools.refinery.store.query.term.Term;
10
11public class IntAddTerm extends IntBinaryTerm {
12 public IntAddTerm(Term<Integer> left, Term<Integer> right) {
13 super(left, right);
14 }
15
16 @Override
17 public Term<Integer> doSubstitute(Substitution substitution, Term<Integer> substitutedLeft,
18 Term<Integer> substitutedRight) {
19 return new IntAddTerm(substitutedLeft, substitutedRight);
20 }
21
22 @Override
23 protected Integer doEvaluate(Integer leftValue, Integer rightValue) {
24 return leftValue + rightValue;
25 }
26
27 @Override
28 public String toString() {
29 return "(%s + %s)".formatted(getLeft(), getRight());
30 }
31}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntBinaryTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntBinaryTerm.java
deleted file mode 100644
index 27ced4e4..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntBinaryTerm.java
+++ /dev/null
@@ -1,15 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.term.int_;
7
8import tools.refinery.store.query.term.BinaryTerm;
9import tools.refinery.store.query.term.Term;
10
11public abstract class IntBinaryTerm extends BinaryTerm<Integer, Integer, Integer> {
12 protected IntBinaryTerm(Term<Integer> left, Term<Integer> right) {
13 super(Integer.class, Integer.class, Integer.class, left, right);
14 }
15}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntDivTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntDivTerm.java
deleted file mode 100644
index 2a35058c..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntDivTerm.java
+++ /dev/null
@@ -1,31 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.term.int_;
7
8import tools.refinery.store.query.substitution.Substitution;
9import tools.refinery.store.query.term.Term;
10
11public class IntDivTerm extends IntBinaryTerm {
12 public IntDivTerm(Term<Integer> left, Term<Integer> right) {
13 super(left, right);
14 }
15
16 @Override
17 public Term<Integer> doSubstitute(Substitution substitution, Term<Integer> substitutedLeft,
18 Term<Integer> substitutedRight) {
19 return new IntDivTerm(substitutedLeft, substitutedRight);
20 }
21
22 @Override
23 protected Integer doEvaluate(Integer leftValue, Integer rightValue) {
24 return rightValue == 0 ? null : leftValue / rightValue;
25 }
26
27 @Override
28 public String toString() {
29 return "(%s / %s)".formatted(getLeft(), getRight());
30 }
31}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntMaxTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntMaxTerm.java
deleted file mode 100644
index f81fc509..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntMaxTerm.java
+++ /dev/null
@@ -1,31 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.term.int_;
7
8import tools.refinery.store.query.substitution.Substitution;
9import tools.refinery.store.query.term.Term;
10
11public class IntMaxTerm extends IntBinaryTerm {
12 public IntMaxTerm(Term<Integer> left, Term<Integer> right) {
13 super(left, right);
14 }
15
16 @Override
17 public Term<Integer> doSubstitute(Substitution substitution, Term<Integer> substitutedLeft,
18 Term<Integer> substitutedRight) {
19 return new IntMaxTerm(substitutedLeft, substitutedRight);
20 }
21
22 @Override
23 protected Integer doEvaluate(Integer leftValue, Integer rightValue) {
24 return Math.max(rightValue, leftValue);
25 }
26
27 @Override
28 public String toString() {
29 return "max(%s, %s)".formatted(getLeft(), getRight());
30 }
31}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntMinTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntMinTerm.java
deleted file mode 100644
index 89182e26..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntMinTerm.java
+++ /dev/null
@@ -1,31 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.term.int_;
7
8import tools.refinery.store.query.substitution.Substitution;
9import tools.refinery.store.query.term.Term;
10
11public class IntMinTerm extends IntBinaryTerm {
12 public IntMinTerm(Term<Integer> left, Term<Integer> right) {
13 super(left, right);
14 }
15
16 @Override
17 public Term<Integer> doSubstitute(Substitution substitution, Term<Integer> substitutedLeft,
18 Term<Integer> substitutedRight) {
19 return new IntMinTerm(substitutedLeft, substitutedRight);
20 }
21
22 @Override
23 protected Integer doEvaluate(Integer leftValue, Integer rightValue) {
24 return Math.min(rightValue, leftValue);
25 }
26
27 @Override
28 public String toString() {
29 return "min(%s, %s)".formatted(getLeft(), getRight());
30 }
31}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntMinusTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntMinusTerm.java
deleted file mode 100644
index 709aa5ba..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntMinusTerm.java
+++ /dev/null
@@ -1,30 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.term.int_;
7
8import tools.refinery.store.query.substitution.Substitution;
9import tools.refinery.store.query.term.Term;
10
11public class IntMinusTerm extends IntUnaryTerm {
12 public IntMinusTerm(Term<Integer> body) {
13 super(body);
14 }
15
16 @Override
17 protected Term<Integer> doSubstitute(Substitution substitution, Term<Integer> substitutedBody) {
18 return new IntMinusTerm(substitutedBody);
19 }
20
21 @Override
22 protected Integer doEvaluate(Integer bodyValue) {
23 return -bodyValue;
24 }
25
26 @Override
27 public String toString() {
28 return "(-%s)".formatted(getBody());
29 }
30}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntMulTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntMulTerm.java
deleted file mode 100644
index 89d4c5f4..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntMulTerm.java
+++ /dev/null
@@ -1,31 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.term.int_;
7
8import tools.refinery.store.query.substitution.Substitution;
9import tools.refinery.store.query.term.Term;
10
11public class IntMulTerm extends IntBinaryTerm {
12 public IntMulTerm(Term<Integer> left, Term<Integer> right) {
13 super(left, right);
14 }
15
16 @Override
17 public Term<Integer> doSubstitute(Substitution substitution, Term<Integer> substitutedLeft,
18 Term<Integer> substitutedRight) {
19 return new IntMulTerm(substitutedLeft, substitutedRight);
20 }
21
22 @Override
23 protected Integer doEvaluate(Integer leftValue, Integer rightValue) {
24 return leftValue * rightValue;
25 }
26
27 @Override
28 public String toString() {
29 return "(%s * %s)".formatted(getLeft(), getRight());
30 }
31}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntPlusTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntPlusTerm.java
deleted file mode 100644
index aef83bb4..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntPlusTerm.java
+++ /dev/null
@@ -1,30 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.term.int_;
7
8import tools.refinery.store.query.substitution.Substitution;
9import tools.refinery.store.query.term.Term;
10
11public class IntPlusTerm extends IntUnaryTerm {
12 public IntPlusTerm(Term<Integer> body) {
13 super(body);
14 }
15
16 @Override
17 protected Term<Integer> doSubstitute(Substitution substitution, Term<Integer> substitutedBody) {
18 return new IntPlusTerm(substitutedBody);
19 }
20
21 @Override
22 protected Integer doEvaluate(Integer bodyValue) {
23 return bodyValue;
24 }
25
26 @Override
27 public String toString() {
28 return "(+%s)".formatted(getBody());
29 }
30}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntPowTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntPowTerm.java
deleted file mode 100644
index d5af97a1..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntPowTerm.java
+++ /dev/null
@@ -1,43 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.term.int_;
7
8import tools.refinery.store.query.substitution.Substitution;
9import tools.refinery.store.query.term.Term;
10
11public class IntPowTerm extends IntBinaryTerm {
12 public IntPowTerm(Term<Integer> left, Term<Integer> right) {
13 super(left, right);
14 }
15
16 @Override
17 public Term<Integer> doSubstitute(Substitution substitution, Term<Integer> substitutedLeft,
18 Term<Integer> substitutedRight) {
19 return new IntPowTerm(substitutedLeft, substitutedRight);
20 }
21
22 @Override
23 protected Integer doEvaluate(Integer leftValue, Integer rightValue) {
24 return rightValue < 0 ? null : power(leftValue, rightValue);
25 }
26
27 private static int power(int base, int exponent) {
28 int accum = 1;
29 while (exponent > 0) {
30 if (exponent % 2 == 1) {
31 accum = accum * base;
32 }
33 base = base * base;
34 exponent = exponent / 2;
35 }
36 return accum;
37 }
38
39 @Override
40 public String toString() {
41 return "(%s ** %s)".formatted(getLeft(), getRight());
42 }
43}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntSubTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntSubTerm.java
deleted file mode 100644
index 2c27afb1..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntSubTerm.java
+++ /dev/null
@@ -1,31 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.term.int_;
7
8import tools.refinery.store.query.substitution.Substitution;
9import tools.refinery.store.query.term.Term;
10
11public class IntSubTerm extends IntBinaryTerm {
12 public IntSubTerm(Term<Integer> left, Term<Integer> right) {
13 super(left, right);
14 }
15
16 @Override
17 public Term<Integer> doSubstitute(Substitution substitution, Term<Integer> substitutedLeft,
18 Term<Integer> substitutedRight) {
19 return new IntSubTerm(substitutedLeft, substitutedRight);
20 }
21
22 @Override
23 protected Integer doEvaluate(Integer leftValue, Integer rightValue) {
24 return leftValue - rightValue;
25 }
26
27 @Override
28 public String toString() {
29 return "(%s - %s)".formatted(getLeft(), getRight());
30 }
31}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntSumAggregator.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntSumAggregator.java
deleted file mode 100644
index cd718c53..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntSumAggregator.java
+++ /dev/null
@@ -1,40 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.term.int_;
7
8import tools.refinery.store.query.term.StatelessAggregator;
9
10public final class IntSumAggregator implements StatelessAggregator<Integer, Integer> {
11 public static final IntSumAggregator INSTANCE = new IntSumAggregator();
12
13 private IntSumAggregator() {
14 }
15
16 @Override
17 public Class<Integer> getResultType() {
18 return Integer.class;
19 }
20
21 @Override
22 public Class<Integer> getInputType() {
23 return Integer.class;
24 }
25
26 @Override
27 public Integer getEmptyResult() {
28 return 0;
29 }
30
31 @Override
32 public Integer add(Integer current, Integer value) {
33 return current + value;
34 }
35
36 @Override
37 public Integer remove(Integer current, Integer value) {
38 return current - value;
39 }
40}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntTerms.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntTerms.java
deleted file mode 100644
index acb98b94..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntTerms.java
+++ /dev/null
@@ -1,94 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.term.int_;
7
8import tools.refinery.store.query.term.Aggregator;
9import tools.refinery.store.query.term.ConstantTerm;
10import tools.refinery.store.query.term.ExtremeValueAggregator;
11import tools.refinery.store.query.term.Term;
12import tools.refinery.store.query.term.comparable.*;
13
14import java.util.Comparator;
15
16public final class IntTerms {
17 public static final Aggregator<Integer, Integer> INT_SUM = IntSumAggregator.INSTANCE;
18 public static final Aggregator<Integer, Integer> INT_MIN = new ExtremeValueAggregator<>(Integer.class,
19 Integer.MAX_VALUE);
20 public static final Aggregator<Integer, Integer> INT_MAX = new ExtremeValueAggregator<>(Integer.class,
21 Integer.MIN_VALUE, Comparator.reverseOrder());
22
23 private IntTerms() {
24 throw new IllegalArgumentException("This is a static utility class and should not be instantiated directly");
25 }
26
27 public static Term<Integer> constant(Integer value) {
28 return new ConstantTerm<>(Integer.class, value);
29 }
30
31 public static Term<Integer> plus(Term<Integer> body) {
32 return new IntPlusTerm(body);
33 }
34
35 public static Term<Integer> minus(Term<Integer> body) {
36 return new IntMinusTerm(body);
37 }
38
39 public static Term<Integer> add(Term<Integer> left, Term<Integer> right) {
40 return new IntAddTerm(left, right);
41 }
42
43 public static Term<Integer> sub(Term<Integer> left, Term<Integer> right) {
44 return new IntSubTerm(left, right);
45 }
46
47 public static Term<Integer> mul(Term<Integer> left, Term<Integer> right) {
48 return new IntMulTerm(left, right);
49 }
50
51 public static Term<Integer> div(Term<Integer> left, Term<Integer> right) {
52 return new IntDivTerm(left, right);
53 }
54
55 public static Term<Integer> pow(Term<Integer> left, Term<Integer> right) {
56 return new IntPowTerm(left, right);
57 }
58
59 public static Term<Integer> min(Term<Integer> left, Term<Integer> right) {
60 return new IntMinTerm(left, right);
61 }
62
63 public static Term<Integer> max(Term<Integer> left, Term<Integer> right) {
64 return new IntMaxTerm(left, right);
65 }
66
67 public static Term<Boolean> eq(Term<Integer> left, Term<Integer> right) {
68 return new EqTerm<>(Integer.class, left, right);
69 }
70
71 public static Term<Boolean> notEq(Term<Integer> left, Term<Integer> right) {
72 return new NotEqTerm<>(Integer.class, left, right);
73 }
74
75 public static Term<Boolean> less(Term<Integer> left, Term<Integer> right) {
76 return new LessTerm<>(Integer.class, left, right);
77 }
78
79 public static Term<Boolean> lessEq(Term<Integer> left, Term<Integer> right) {
80 return new LessEqTerm<>(Integer.class, left, right);
81 }
82
83 public static Term<Boolean> greater(Term<Integer> left, Term<Integer> right) {
84 return new GreaterTerm<>(Integer.class, left, right);
85 }
86
87 public static Term<Boolean> greaterEq(Term<Integer> left, Term<Integer> right) {
88 return new GreaterEqTerm<>(Integer.class, left, right);
89 }
90
91 public static Term<Integer> asInt(Term<Double> body) {
92 return new RealToIntTerm(body);
93 }
94}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntUnaryTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntUnaryTerm.java
deleted file mode 100644
index 49b4c647..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntUnaryTerm.java
+++ /dev/null
@@ -1,15 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.term.int_;
7
8import tools.refinery.store.query.term.Term;
9import tools.refinery.store.query.term.UnaryTerm;
10
11public abstract class IntUnaryTerm extends UnaryTerm<Integer, Integer> {
12 protected IntUnaryTerm(Term<Integer> body) {
13 super(Integer.class, Integer.class, body);
14 }
15}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/RealToIntTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/RealToIntTerm.java
deleted file mode 100644
index 7d383562..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/RealToIntTerm.java
+++ /dev/null
@@ -1,31 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.term.int_;
7
8import tools.refinery.store.query.substitution.Substitution;
9import tools.refinery.store.query.term.Term;
10import tools.refinery.store.query.term.UnaryTerm;
11
12public class RealToIntTerm extends UnaryTerm<Integer, Double> {
13 protected RealToIntTerm(Term<Double> body) {
14 super(Integer.class, Double.class, body);
15 }
16
17 @Override
18 protected Integer doEvaluate(Double bodyValue) {
19 return bodyValue.isNaN() ? null : bodyValue.intValue();
20 }
21
22 @Override
23 protected Term<Integer> doSubstitute(Substitution substitution, Term<Double> substitutedBody) {
24 return new RealToIntTerm(substitutedBody);
25 }
26
27 @Override
28 public String toString() {
29 return "(%s as int)".formatted(getBody());
30 }
31}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/IntToRealTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/IntToRealTerm.java
deleted file mode 100644
index 2f53117a..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/IntToRealTerm.java
+++ /dev/null
@@ -1,31 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.term.real;
7
8import tools.refinery.store.query.substitution.Substitution;
9import tools.refinery.store.query.term.Term;
10import tools.refinery.store.query.term.UnaryTerm;
11
12public class IntToRealTerm extends UnaryTerm<Double, Integer> {
13 protected IntToRealTerm(Term<Integer> body) {
14 super(Double.class, Integer.class, body);
15 }
16
17 @Override
18 protected Term<Double> doSubstitute(Substitution substitution, Term<Integer> substitutedBody) {
19 return new IntToRealTerm(substitutedBody);
20 }
21
22 @Override
23 protected Double doEvaluate(Integer bodyValue) {
24 return bodyValue.doubleValue();
25 }
26
27 @Override
28 public String toString() {
29 return "(%s as real)".formatted(getBody());
30 }
31}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealAddTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealAddTerm.java
deleted file mode 100644
index 33fc9e41..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealAddTerm.java
+++ /dev/null
@@ -1,31 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.term.real;
7
8import tools.refinery.store.query.substitution.Substitution;
9import tools.refinery.store.query.term.Term;
10
11public class RealAddTerm extends RealBinaryTerm {
12 public RealAddTerm(Term<Double> left, Term<Double> right) {
13 super(left, right);
14 }
15
16 @Override
17 public Term<Double> doSubstitute(Substitution substitution, Term<Double> substitutedLeft,
18 Term<Double> substitutedRight) {
19 return new RealAddTerm(substitutedLeft, substitutedRight);
20 }
21
22 @Override
23 protected Double doEvaluate(Double leftValue, Double rightValue) {
24 return leftValue + rightValue;
25 }
26
27 @Override
28 public String toString() {
29 return "(%s + %s)".formatted(getLeft(), getRight());
30 }
31}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealBinaryTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealBinaryTerm.java
deleted file mode 100644
index 000f3623..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealBinaryTerm.java
+++ /dev/null
@@ -1,15 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.term.real;
7
8import tools.refinery.store.query.term.BinaryTerm;
9import tools.refinery.store.query.term.Term;
10
11public abstract class RealBinaryTerm extends BinaryTerm<Double, Double, Double> {
12 protected RealBinaryTerm(Term<Double> left, Term<Double> right) {
13 super(Double.class, Double.class, Double.class, left, right);
14 }
15}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealDivTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealDivTerm.java
deleted file mode 100644
index 1e55bf42..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealDivTerm.java
+++ /dev/null
@@ -1,31 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.term.real;
7
8import tools.refinery.store.query.substitution.Substitution;
9import tools.refinery.store.query.term.Term;
10
11public class RealDivTerm extends RealBinaryTerm {
12 public RealDivTerm(Term<Double> left, Term<Double> right) {
13 super(left, right);
14 }
15
16 @Override
17 public Term<Double> doSubstitute(Substitution substitution, Term<Double> substitutedLeft,
18 Term<Double> substitutedRight) {
19 return new RealDivTerm(substitutedLeft, substitutedRight);
20 }
21
22 @Override
23 protected Double doEvaluate(Double leftValue, Double rightValue) {
24 return leftValue / rightValue;
25 }
26
27 @Override
28 public String toString() {
29 return "(%s / %s)".formatted(getLeft(), getRight());
30 }
31}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealMaxTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealMaxTerm.java
deleted file mode 100644
index 2a249496..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealMaxTerm.java
+++ /dev/null
@@ -1,31 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.term.real;
7
8import tools.refinery.store.query.substitution.Substitution;
9import tools.refinery.store.query.term.Term;
10
11public class RealMaxTerm extends RealBinaryTerm {
12 public RealMaxTerm(Term<Double> left, Term<Double> right) {
13 super(left, right);
14 }
15
16 @Override
17 public Term<Double> doSubstitute(Substitution substitution, Term<Double> substitutedLeft,
18 Term<Double> substitutedRight) {
19 return new RealMaxTerm(substitutedLeft, substitutedRight);
20 }
21
22 @Override
23 protected Double doEvaluate(Double leftValue, Double rightValue) {
24 return Math.max(leftValue, rightValue);
25 }
26
27 @Override
28 public String toString() {
29 return "max(%s, %s)".formatted(getLeft(), getRight());
30 }
31}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealMinTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealMinTerm.java
deleted file mode 100644
index 2eb4cc1e..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealMinTerm.java
+++ /dev/null
@@ -1,31 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.term.real;
7
8import tools.refinery.store.query.substitution.Substitution;
9import tools.refinery.store.query.term.Term;
10
11public class RealMinTerm extends RealBinaryTerm {
12 public RealMinTerm(Term<Double> left, Term<Double> right) {
13 super(left, right);
14 }
15
16 @Override
17 public Term<Double> doSubstitute(Substitution substitution, Term<Double> substitutedLeft,
18 Term<Double> substitutedRight) {
19 return new RealMinTerm(substitutedLeft, substitutedRight);
20 }
21
22 @Override
23 protected Double doEvaluate(Double leftValue, Double rightValue) {
24 return Math.min(leftValue, rightValue);
25 }
26
27 @Override
28 public String toString() {
29 return "min(%s, %s)".formatted(getLeft(), getRight());
30 }
31}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealMinusTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealMinusTerm.java
deleted file mode 100644
index 4afec7a1..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealMinusTerm.java
+++ /dev/null
@@ -1,30 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.term.real;
7
8import tools.refinery.store.query.substitution.Substitution;
9import tools.refinery.store.query.term.Term;
10
11public class RealMinusTerm extends RealUnaryTerm {
12 public RealMinusTerm(Term<Double> body) {
13 super(body);
14 }
15
16 @Override
17 protected Term<Double> doSubstitute(Substitution substitution, Term<Double> substitutedBody) {
18 return new RealMinusTerm(substitutedBody);
19 }
20
21 @Override
22 protected Double doEvaluate(Double bodyValue) {
23 return -bodyValue;
24 }
25
26 @Override
27 public String toString() {
28 return "(-%s)".formatted(getBody());
29 }
30}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealMulTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealMulTerm.java
deleted file mode 100644
index ec95ac6f..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealMulTerm.java
+++ /dev/null
@@ -1,31 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.term.real;
7
8import tools.refinery.store.query.substitution.Substitution;
9import tools.refinery.store.query.term.Term;
10
11public class RealMulTerm extends RealBinaryTerm {
12 public RealMulTerm(Term<Double> left, Term<Double> right) {
13 super(left, right);
14 }
15
16 @Override
17 public Term<Double> doSubstitute(Substitution substitution, Term<Double> substitutedLeft,
18 Term<Double> substitutedRight) {
19 return new RealMulTerm(substitutedLeft, substitutedRight);
20 }
21
22 @Override
23 protected Double doEvaluate(Double leftValue, Double rightValue) {
24 return leftValue * rightValue;
25 }
26
27 @Override
28 public String toString() {
29 return "(%s * %s)".formatted(getLeft(), getRight());
30 }
31}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealPlusTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealPlusTerm.java
deleted file mode 100644
index 64dd2e70..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealPlusTerm.java
+++ /dev/null
@@ -1,30 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.term.real;
7
8import tools.refinery.store.query.substitution.Substitution;
9import tools.refinery.store.query.term.Term;
10
11public class RealPlusTerm extends RealUnaryTerm {
12 public RealPlusTerm(Term<Double> body) {
13 super(body);
14 }
15
16 @Override
17 protected Term<Double> doSubstitute(Substitution substitution, Term<Double> substitutedBody) {
18 return new RealPlusTerm(substitutedBody);
19 }
20
21 @Override
22 protected Double doEvaluate(Double bodyValue) {
23 return bodyValue;
24 }
25
26 @Override
27 public String toString() {
28 return "(+%s)".formatted(getBody());
29 }
30}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealPowTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealPowTerm.java
deleted file mode 100644
index 11c952ea..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealPowTerm.java
+++ /dev/null
@@ -1,31 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.term.real;
7
8import tools.refinery.store.query.substitution.Substitution;
9import tools.refinery.store.query.term.Term;
10
11public class RealPowTerm extends RealBinaryTerm {
12 public RealPowTerm(Term<Double> left, Term<Double> right) {
13 super(left, right);
14 }
15
16 @Override
17 public Term<Double> doSubstitute(Substitution substitution, Term<Double> substitutedLeft,
18 Term<Double> substitutedRight) {
19 return new RealPowTerm(substitutedLeft, substitutedRight);
20 }
21
22 @Override
23 protected Double doEvaluate(Double leftValue, Double rightValue) {
24 return Math.pow(leftValue, rightValue);
25 }
26
27 @Override
28 public String toString() {
29 return "(%s ** %s)".formatted(getLeft(), getRight());
30 }
31}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealSubTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealSubTerm.java
deleted file mode 100644
index 8cc701ed..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealSubTerm.java
+++ /dev/null
@@ -1,31 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.term.real;
7
8import tools.refinery.store.query.substitution.Substitution;
9import tools.refinery.store.query.term.Term;
10
11public class RealSubTerm extends RealBinaryTerm {
12 public RealSubTerm(Term<Double> left, Term<Double> right) {
13 super(left, right);
14 }
15
16 @Override
17 public Term<Double> doSubstitute(Substitution substitution, Term<Double> substitutedLeft,
18 Term<Double> substitutedRight) {
19 return new RealSubTerm(substitutedLeft, substitutedRight);
20 }
21
22 @Override
23 protected Double doEvaluate(Double leftValue, Double rightValue) {
24 return leftValue - rightValue;
25 }
26
27 @Override
28 public String toString() {
29 return "(%s - %s)".formatted(getLeft(), getRight());
30 }
31}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealSumAggregator.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealSumAggregator.java
deleted file mode 100644
index d21048e9..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealSumAggregator.java
+++ /dev/null
@@ -1,90 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.term.real;
7
8import tools.refinery.store.query.term.StatefulAggregate;
9import tools.refinery.store.query.term.StatefulAggregator;
10
11import java.util.Map;
12import java.util.TreeMap;
13
14public final class RealSumAggregator implements StatefulAggregator<Double, Double> {
15 public static final RealSumAggregator INSTANCE = new RealSumAggregator();
16
17 private RealSumAggregator() {
18 }
19
20 @Override
21 public Class<Double> getResultType() {
22 return Double.class;
23 }
24
25 @Override
26 public Class<Double> getInputType() {
27 return Double.class;
28 }
29
30 @Override
31 public StatefulAggregate<Double, Double> createEmptyAggregate() {
32 return new Aggregate();
33 }
34
35 @Override
36 public Double getEmptyResult() {
37 return 0d;
38 }
39
40 private static class Aggregate implements StatefulAggregate<Double, Double> {
41 private final Map<Double, Integer> values;
42
43 public Aggregate() {
44 values = new TreeMap<>();
45 }
46
47 private Aggregate(Aggregate other) {
48 values = new TreeMap<>(other.values);
49 }
50
51 @Override
52 public void add(Double value) {
53 values.compute(value, (ignoredValue, currentCount) -> currentCount == null ? 1 : currentCount + 1);
54 }
55
56 @Override
57 public void remove(Double value) {
58 values.compute(value, (theValue, currentCount) -> {
59 if (currentCount == null || currentCount <= 0) {
60 throw new IllegalStateException("Invalid count %d for value %f".formatted(currentCount, theValue));
61 }
62 return currentCount.equals(1) ? null : currentCount - 1;
63 });
64 }
65
66 @Override
67 public Double getResult() {
68 return values.entrySet()
69 .stream()
70 .mapToDouble(entry -> entry.getKey() * entry.getValue())
71 .reduce(Double::sum)
72 .orElse(0d);
73 }
74
75 @Override
76 public boolean isEmpty() {
77 return values.isEmpty();
78 }
79
80 @Override
81 public StatefulAggregate<Double, Double> deepCopy() {
82 return new Aggregate(this);
83 }
84
85 @Override
86 public boolean contains(Double value) {
87 return values.containsKey(value);
88 }
89 }
90}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealTerms.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealTerms.java
deleted file mode 100644
index 79220358..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealTerms.java
+++ /dev/null
@@ -1,94 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.term.real;
7
8import tools.refinery.store.query.term.Aggregator;
9import tools.refinery.store.query.term.ConstantTerm;
10import tools.refinery.store.query.term.ExtremeValueAggregator;
11import tools.refinery.store.query.term.Term;
12import tools.refinery.store.query.term.comparable.*;
13
14import java.util.Comparator;
15
16public final class RealTerms {
17 public static final Aggregator<Double, Double> REAL_SUM = RealSumAggregator.INSTANCE;
18 public static final Aggregator<Double, Double> REAL_MIN = new ExtremeValueAggregator<>(Double.class,
19 Double.POSITIVE_INFINITY);
20 public static final Aggregator<Double, Double> REAL_MAX = new ExtremeValueAggregator<>(Double.class,
21 Double.NEGATIVE_INFINITY, Comparator.reverseOrder());
22
23 private RealTerms() {
24 throw new IllegalArgumentException("This is a static utility class and should not be instantiated directly");
25 }
26
27 public static Term<Double> constant(Double value) {
28 return new ConstantTerm<>(Double.class, value);
29 }
30
31 public static Term<Double> plus(Term<Double> body) {
32 return new RealPlusTerm(body);
33 }
34
35 public static Term<Double> minus(Term<Double> body) {
36 return new RealMinusTerm(body);
37 }
38
39 public static Term<Double> add(Term<Double> left, Term<Double> right) {
40 return new RealAddTerm(left, right);
41 }
42
43 public static Term<Double> sub(Term<Double> left, Term<Double> right) {
44 return new RealSubTerm(left, right);
45 }
46
47 public static Term<Double> mul(Term<Double> left, Term<Double> right) {
48 return new RealMulTerm(left, right);
49 }
50
51 public static Term<Double> div(Term<Double> left, Term<Double> right) {
52 return new RealDivTerm(left, right);
53 }
54
55 public static Term<Double> pow(Term<Double> left, Term<Double> right) {
56 return new RealPowTerm(left, right);
57 }
58
59 public static Term<Double> min(Term<Double> left, Term<Double> right) {
60 return new RealMinTerm(left, right);
61 }
62
63 public static Term<Double> max(Term<Double> left, Term<Double> right) {
64 return new RealMaxTerm(left, right);
65 }
66
67 public static Term<Boolean> eq(Term<Double> left, Term<Double> right) {
68 return new EqTerm<>(Double.class, left, right);
69 }
70
71 public static Term<Boolean> notEq(Term<Double> left, Term<Double> right) {
72 return new NotEqTerm<>(Double.class, left, right);
73 }
74
75 public static Term<Boolean> less(Term<Double> left, Term<Double> right) {
76 return new LessTerm<>(Double.class, left, right);
77 }
78
79 public static Term<Boolean> lessEq(Term<Double> left, Term<Double> right) {
80 return new LessEqTerm<>(Double.class, left, right);
81 }
82
83 public static Term<Boolean> greater(Term<Double> left, Term<Double> right) {
84 return new GreaterTerm<>(Double.class, left, right);
85 }
86
87 public static Term<Boolean> greaterEq(Term<Double> left, Term<Double> right) {
88 return new GreaterEqTerm<>(Double.class, left, right);
89 }
90
91 public static Term<Double> asReal(Term<Integer> body) {
92 return new IntToRealTerm(body);
93 }
94}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealUnaryTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealUnaryTerm.java
deleted file mode 100644
index d41c4ed9..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealUnaryTerm.java
+++ /dev/null
@@ -1,15 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.term.real;
7
8import tools.refinery.store.query.term.Term;
9import tools.refinery.store.query.term.UnaryTerm;
10
11public abstract class RealUnaryTerm extends UnaryTerm<Double, Double> {
12 protected RealUnaryTerm(Term<Double> body) {
13 super(Double.class, Double.class, body);
14 }
15}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/uppercardinality/UpperCardinalityAddTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/uppercardinality/UpperCardinalityAddTerm.java
deleted file mode 100644
index 68905f51..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/uppercardinality/UpperCardinalityAddTerm.java
+++ /dev/null
@@ -1,31 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.term.uppercardinality;
7
8import tools.refinery.store.query.substitution.Substitution;
9import tools.refinery.store.query.term.Term;
10import tools.refinery.store.representation.cardinality.UpperCardinality;
11
12public class UpperCardinalityAddTerm extends UpperCardinalityBinaryTerm {
13 protected UpperCardinalityAddTerm(Term<UpperCardinality> left, Term<UpperCardinality> right) {
14 super(left, right);
15 }
16
17 @Override
18 protected UpperCardinality doEvaluate(UpperCardinality leftValue, UpperCardinality rightValue) {
19 return leftValue.add(rightValue);
20 }
21
22 @Override
23 public Term<UpperCardinality> doSubstitute(Substitution substitution, Term<UpperCardinality> substitutedLeft, Term<UpperCardinality> substitutedRight) {
24 return new UpperCardinalityAddTerm(substitutedLeft, substitutedRight);
25 }
26
27 @Override
28 public String toString() {
29 return "(%s + %s)".formatted(getLeft(), getRight());
30 }
31}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/uppercardinality/UpperCardinalityBinaryTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/uppercardinality/UpperCardinalityBinaryTerm.java
deleted file mode 100644
index 0cf8fe44..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/uppercardinality/UpperCardinalityBinaryTerm.java
+++ /dev/null
@@ -1,17 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.term.uppercardinality;
7
8import tools.refinery.store.query.term.BinaryTerm;
9import tools.refinery.store.query.term.Term;
10import tools.refinery.store.representation.cardinality.UpperCardinality;
11
12public abstract class UpperCardinalityBinaryTerm extends BinaryTerm<UpperCardinality, UpperCardinality,
13 UpperCardinality> {
14 protected UpperCardinalityBinaryTerm(Term<UpperCardinality> left, Term<UpperCardinality> right) {
15 super(UpperCardinality.class, UpperCardinality.class, UpperCardinality.class, left, right);
16 }
17}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/uppercardinality/UpperCardinalityMaxTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/uppercardinality/UpperCardinalityMaxTerm.java
deleted file mode 100644
index ff75f64e..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/uppercardinality/UpperCardinalityMaxTerm.java
+++ /dev/null
@@ -1,31 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.term.uppercardinality;
7
8import tools.refinery.store.query.substitution.Substitution;
9import tools.refinery.store.query.term.Term;
10import tools.refinery.store.representation.cardinality.UpperCardinality;
11
12public class UpperCardinalityMaxTerm extends UpperCardinalityBinaryTerm {
13 protected UpperCardinalityMaxTerm(Term<UpperCardinality> left, Term<UpperCardinality> right) {
14 super(left, right);
15 }
16
17 @Override
18 protected UpperCardinality doEvaluate(UpperCardinality leftValue, UpperCardinality rightValue) {
19 return leftValue.max(rightValue);
20 }
21
22 @Override
23 public Term<UpperCardinality> doSubstitute(Substitution substitution, Term<UpperCardinality> substitutedLeft, Term<UpperCardinality> substitutedRight) {
24 return new UpperCardinalityMaxTerm(substitutedLeft, substitutedRight);
25 }
26
27 @Override
28 public String toString() {
29 return "max(%s, %s)".formatted(getLeft(), getRight());
30 }
31}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/uppercardinality/UpperCardinalityMinTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/uppercardinality/UpperCardinalityMinTerm.java
deleted file mode 100644
index 1e89e9f4..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/uppercardinality/UpperCardinalityMinTerm.java
+++ /dev/null
@@ -1,31 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.term.uppercardinality;
7
8import tools.refinery.store.query.substitution.Substitution;
9import tools.refinery.store.query.term.Term;
10import tools.refinery.store.representation.cardinality.UpperCardinality;
11
12public class UpperCardinalityMinTerm extends UpperCardinalityBinaryTerm {
13 protected UpperCardinalityMinTerm(Term<UpperCardinality> left, Term<UpperCardinality> right) {
14 super(left, right);
15 }
16
17 @Override
18 protected UpperCardinality doEvaluate(UpperCardinality leftValue, UpperCardinality rightValue) {
19 return leftValue.min(rightValue);
20 }
21
22 @Override
23 public Term<UpperCardinality> doSubstitute(Substitution substitution, Term<UpperCardinality> substitutedLeft, Term<UpperCardinality> substitutedRight) {
24 return new UpperCardinalityMinTerm(substitutedLeft, substitutedRight);
25 }
26
27 @Override
28 public String toString() {
29 return "min(%s, %s)".formatted(getLeft(), getRight());
30 }
31}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/uppercardinality/UpperCardinalityMulTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/uppercardinality/UpperCardinalityMulTerm.java
deleted file mode 100644
index 3b4970f4..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/uppercardinality/UpperCardinalityMulTerm.java
+++ /dev/null
@@ -1,31 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.term.uppercardinality;
7
8import tools.refinery.store.query.substitution.Substitution;
9import tools.refinery.store.query.term.Term;
10import tools.refinery.store.representation.cardinality.UpperCardinality;
11
12public class UpperCardinalityMulTerm extends UpperCardinalityBinaryTerm {
13 protected UpperCardinalityMulTerm(Term<UpperCardinality> left, Term<UpperCardinality> right) {
14 super(left, right);
15 }
16
17 @Override
18 protected UpperCardinality doEvaluate(UpperCardinality leftValue, UpperCardinality rightValue) {
19 return leftValue.multiply(rightValue);
20 }
21
22 @Override
23 public Term<UpperCardinality> doSubstitute(Substitution substitution, Term<UpperCardinality> substitutedLeft, Term<UpperCardinality> substitutedRight) {
24 return new UpperCardinalityMulTerm(substitutedLeft, substitutedRight);
25 }
26
27 @Override
28 public String toString() {
29 return "(%s * %s)".formatted(getLeft(), getRight());
30 }
31}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/uppercardinality/UpperCardinalitySumAggregator.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/uppercardinality/UpperCardinalitySumAggregator.java
deleted file mode 100644
index d31f00a2..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/uppercardinality/UpperCardinalitySumAggregator.java
+++ /dev/null
@@ -1,86 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.term.uppercardinality;
7
8import tools.refinery.store.query.term.StatefulAggregate;
9import tools.refinery.store.query.term.StatefulAggregator;
10import tools.refinery.store.representation.cardinality.FiniteUpperCardinality;
11import tools.refinery.store.representation.cardinality.UnboundedUpperCardinality;
12import tools.refinery.store.representation.cardinality.UpperCardinalities;
13import tools.refinery.store.representation.cardinality.UpperCardinality;
14
15public class UpperCardinalitySumAggregator implements StatefulAggregator<UpperCardinality, UpperCardinality> {
16 public static final UpperCardinalitySumAggregator INSTANCE = new UpperCardinalitySumAggregator();
17
18 private UpperCardinalitySumAggregator() {
19 }
20
21 @Override
22 public Class<UpperCardinality> getResultType() {
23 return UpperCardinality.class;
24 }
25
26 @Override
27 public Class<UpperCardinality> getInputType() {
28 return UpperCardinality.class;
29 }
30
31 @Override
32 public StatefulAggregate<UpperCardinality, UpperCardinality> createEmptyAggregate() {
33 return new Aggregate();
34 }
35
36 private static class Aggregate implements StatefulAggregate<UpperCardinality, UpperCardinality> {
37 private int sumFiniteUpperBounds;
38 private int countUnbounded;
39
40 public Aggregate() {
41 this(0, 0);
42 }
43
44 private Aggregate(int sumFiniteUpperBounds, int countUnbounded) {
45 this.sumFiniteUpperBounds = sumFiniteUpperBounds;
46 this.countUnbounded = countUnbounded;
47 }
48
49 @Override
50 public void add(UpperCardinality value) {
51 if (value instanceof FiniteUpperCardinality finiteUpperCardinality) {
52 sumFiniteUpperBounds += finiteUpperCardinality.finiteUpperBound();
53 } else if (value instanceof UnboundedUpperCardinality) {
54 countUnbounded += 1;
55 } else {
56 throw new IllegalArgumentException("Unknown UpperCardinality: " + value);
57 }
58 }
59
60 @Override
61 public void remove(UpperCardinality value) {
62 if (value instanceof FiniteUpperCardinality finiteUpperCardinality) {
63 sumFiniteUpperBounds -= finiteUpperCardinality.finiteUpperBound();
64 } else if (value instanceof UnboundedUpperCardinality) {
65 countUnbounded -= 1;
66 } else {
67 throw new IllegalArgumentException("Unknown UpperCardinality: " + value);
68 }
69 }
70
71 @Override
72 public UpperCardinality getResult() {
73 return countUnbounded > 0 ? UpperCardinalities.UNBOUNDED : UpperCardinalities.atMost(sumFiniteUpperBounds);
74 }
75
76 @Override
77 public boolean isEmpty() {
78 return sumFiniteUpperBounds == 0 && countUnbounded == 0;
79 }
80
81 @Override
82 public StatefulAggregate<UpperCardinality, UpperCardinality> deepCopy() {
83 return new Aggregate(sumFiniteUpperBounds, countUnbounded);
84 }
85 }
86}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/uppercardinality/UpperCardinalityTerms.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/uppercardinality/UpperCardinalityTerms.java
deleted file mode 100644
index 13914f2d..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/uppercardinality/UpperCardinalityTerms.java
+++ /dev/null
@@ -1,73 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.term.uppercardinality;
7
8import tools.refinery.store.query.term.Aggregator;
9import tools.refinery.store.query.term.ConstantTerm;
10import tools.refinery.store.query.term.ExtremeValueAggregator;
11import tools.refinery.store.query.term.Term;
12import tools.refinery.store.query.term.comparable.*;
13import tools.refinery.store.representation.cardinality.UpperCardinalities;
14import tools.refinery.store.representation.cardinality.UpperCardinality;
15
16import java.util.Comparator;
17
18public final class UpperCardinalityTerms {
19 public static final Aggregator<UpperCardinality, UpperCardinality> UPPER_CARDINALITY_SUM =
20 UpperCardinalitySumAggregator.INSTANCE;
21 public static final Aggregator<UpperCardinality, UpperCardinality> UPPER_CARDINALITY_MIN =
22 new ExtremeValueAggregator<>(UpperCardinality.class, UpperCardinalities.UNBOUNDED);
23 public static final Aggregator<UpperCardinality, UpperCardinality> UPPER_CARDINALITY_MAX =
24 new ExtremeValueAggregator<>(UpperCardinality.class, UpperCardinalities.ZERO, Comparator.reverseOrder());
25
26 private UpperCardinalityTerms() {
27 throw new IllegalStateException("This is a static utility class and should not be instantiated directly");
28 }
29
30 public static Term<UpperCardinality> constant(UpperCardinality value) {
31 return new ConstantTerm<>(UpperCardinality.class, value);
32 }
33
34 public static Term<UpperCardinality> add(Term<UpperCardinality> left, Term<UpperCardinality> right) {
35 return new UpperCardinalityAddTerm(left, right);
36 }
37
38 public static Term<UpperCardinality> mul(Term<UpperCardinality> left, Term<UpperCardinality> right) {
39 return new UpperCardinalityMulTerm(left, right);
40 }
41
42 public static Term<UpperCardinality> min(Term<UpperCardinality> left, Term<UpperCardinality> right) {
43 return new UpperCardinalityMinTerm(left, right);
44 }
45
46 public static Term<UpperCardinality> max(Term<UpperCardinality> left, Term<UpperCardinality> right) {
47 return new UpperCardinalityMaxTerm(left, right);
48 }
49
50 public static Term<Boolean> eq(Term<UpperCardinality> left, Term<UpperCardinality> right) {
51 return new EqTerm<>(UpperCardinality.class, left, right);
52 }
53
54 public static Term<Boolean> notEq(Term<UpperCardinality> left, Term<UpperCardinality> right) {
55 return new NotEqTerm<>(UpperCardinality.class, left, right);
56 }
57
58 public static Term<Boolean> less(Term<UpperCardinality> left, Term<UpperCardinality> right) {
59 return new LessTerm<>(UpperCardinality.class, left, right);
60 }
61
62 public static Term<Boolean> lessEq(Term<UpperCardinality> left, Term<UpperCardinality> right) {
63 return new LessEqTerm<>(UpperCardinality.class, left, right);
64 }
65
66 public static Term<Boolean> greater(Term<UpperCardinality> left, Term<UpperCardinality> right) {
67 return new GreaterTerm<>(UpperCardinality.class, left, right);
68 }
69
70 public static Term<Boolean> greaterEq(Term<UpperCardinality> left, Term<UpperCardinality> right) {
71 return new GreaterEqTerm<>(UpperCardinality.class, left, right);
72 }
73}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/valuation/MapBasedValuation.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/valuation/MapBasedValuation.java
deleted file mode 100644
index 261ceaa5..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/valuation/MapBasedValuation.java
+++ /dev/null
@@ -1,22 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.valuation;
7
8import tools.refinery.store.query.term.AnyDataVariable;
9import tools.refinery.store.query.term.DataVariable;
10
11import java.util.Map;
12
13record MapBasedValuation(Map<AnyDataVariable, Object> values) implements Valuation {
14 @Override
15 public <T> T getValue(DataVariable<T> variable) {
16 if (!values.containsKey(variable)) {
17 throw new IllegalArgumentException("No value for variable %s".formatted(variable));
18 }
19 var value = values.get(variable);
20 return variable.getType().cast(value);
21 }
22}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/valuation/RestrictedValuation.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/valuation/RestrictedValuation.java
deleted file mode 100644
index fc8406aa..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/valuation/RestrictedValuation.java
+++ /dev/null
@@ -1,21 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.valuation;
7
8import tools.refinery.store.query.term.AnyDataVariable;
9import tools.refinery.store.query.term.DataVariable;
10
11import java.util.Set;
12
13public record RestrictedValuation(Valuation valuation, Set<AnyDataVariable> allowedVariables) implements Valuation {
14 @Override
15 public <T> T getValue(DataVariable<T> variable) {
16 if (!allowedVariables.contains(variable)) {
17 throw new IllegalArgumentException("Variable %s is not in scope".formatted(variable));
18 }
19 return valuation.getValue(variable);
20 }
21}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/valuation/SubstitutedValuation.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/valuation/SubstitutedValuation.java
deleted file mode 100644
index 1c14112c..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/valuation/SubstitutedValuation.java
+++ /dev/null
@@ -1,16 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.valuation;
7
8import tools.refinery.store.query.substitution.Substitution;
9import tools.refinery.store.query.term.DataVariable;
10
11public record SubstitutedValuation(Valuation originalValuation, Substitution substitution) implements Valuation {
12 @Override
13 public <T> T getValue(DataVariable<T> variable) {
14 return originalValuation.getValue(substitution.getTypeSafeSubstitute(variable));
15 }
16}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/valuation/Valuation.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/valuation/Valuation.java
deleted file mode 100644
index 1588e957..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/valuation/Valuation.java
+++ /dev/null
@@ -1,37 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.valuation;
7
8import org.jetbrains.annotations.Nullable;
9import tools.refinery.store.query.substitution.Substitution;
10import tools.refinery.store.query.term.AnyDataVariable;
11import tools.refinery.store.query.term.DataVariable;
12
13import java.util.Map;
14import java.util.Set;
15
16public interface Valuation {
17 <T> T getValue(DataVariable<T> variable);
18
19 default Valuation substitute(@Nullable Substitution substitution) {
20 if (substitution == null) {
21 return this;
22 }
23 return new SubstitutedValuation(this, substitution);
24 }
25
26 default Valuation restrict(Set<? extends AnyDataVariable> allowedVariables) {
27 return new RestrictedValuation(this, Set.copyOf(allowedVariables));
28 }
29
30 static ValuationBuilder builder() {
31 return new ValuationBuilder();
32 }
33
34 static Valuation empty() {
35 return new MapBasedValuation(Map.of());
36 }
37}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/valuation/ValuationBuilder.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/valuation/ValuationBuilder.java
deleted file mode 100644
index 7337dbc3..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/valuation/ValuationBuilder.java
+++ /dev/null
@@ -1,40 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.valuation;
7
8import tools.refinery.store.query.term.AnyDataVariable;
9import tools.refinery.store.query.term.DataVariable;
10
11import java.util.Collections;
12import java.util.HashMap;
13import java.util.Map;
14
15public class ValuationBuilder {
16 private final Map<AnyDataVariable, Object> values = new HashMap<>();
17
18 ValuationBuilder() {
19 }
20
21 public <T> ValuationBuilder put(DataVariable<T> variable, T value) {
22 return putChecked(variable, value);
23 }
24
25 public ValuationBuilder putChecked(AnyDataVariable variable, Object value) {
26 if (value != null && !variable.getType().isInstance(value)) {
27 throw new IllegalArgumentException("Value %s is not an instance of %s"
28 .formatted(value, variable.getType().getName()));
29 }
30 if (values.containsKey(variable)) {
31 throw new IllegalArgumentException("Already has value for variable %s".formatted(variable));
32 }
33 values.put(variable, value);
34 return this;
35 }
36
37 public Valuation build() {
38 return new MapBasedValuation(Collections.unmodifiableMap(values));
39 }
40}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/view/AbstractFunctionView.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/view/AbstractFunctionView.java
index f130fa59..d9809991 100644
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/view/AbstractFunctionView.java
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/view/AbstractFunctionView.java
@@ -7,8 +7,8 @@ package tools.refinery.store.query.view;
7 7
8import tools.refinery.store.map.CursorAsIterator; 8import tools.refinery.store.map.CursorAsIterator;
9import tools.refinery.store.model.Model; 9import tools.refinery.store.model.Model;
10import tools.refinery.store.query.dnf.FunctionalDependency; 10import tools.refinery.logic.dnf.FunctionalDependency;
11import tools.refinery.store.query.term.Parameter; 11import tools.refinery.logic.term.Parameter;
12import tools.refinery.store.representation.Symbol; 12import tools.refinery.store.representation.Symbol;
13import tools.refinery.store.tuple.Tuple; 13import tools.refinery.store.tuple.Tuple;
14import tools.refinery.store.tuple.Tuple1; 14import tools.refinery.store.tuple.Tuple1;
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/view/AnySymbolView.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/view/AnySymbolView.java
index 7e9bf6df..b01c3988 100644
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/view/AnySymbolView.java
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/view/AnySymbolView.java
@@ -5,10 +5,10 @@
5 */ 5 */
6package tools.refinery.store.query.view; 6package tools.refinery.store.query.view;
7 7
8import tools.refinery.logic.dnf.FunctionalDependency;
8import tools.refinery.store.model.Model; 9import tools.refinery.store.model.Model;
9import tools.refinery.store.query.dnf.FunctionalDependency; 10import tools.refinery.logic.Constraint;
10import tools.refinery.store.representation.AnySymbol; 11import tools.refinery.store.representation.AnySymbol;
11import tools.refinery.store.query.Constraint;
12 12
13import java.util.Set; 13import java.util.Set;
14 14
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/view/FilteredView.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/view/FilteredView.java
index 924277ed..7ce07442 100644
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/view/FilteredView.java
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/view/FilteredView.java
@@ -5,7 +5,7 @@
5 */ 5 */
6package tools.refinery.store.query.view; 6package tools.refinery.store.query.view;
7 7
8import tools.refinery.store.query.InvalidQueryException; 8import tools.refinery.logic.InvalidQueryException;
9import tools.refinery.store.tuple.Tuple; 9import tools.refinery.store.tuple.Tuple;
10import tools.refinery.store.representation.Symbol; 10import tools.refinery.store.representation.Symbol;
11 11
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/view/ForbiddenView.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/view/ForbiddenView.java
index c312330e..8323ace7 100644
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/view/ForbiddenView.java
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/view/ForbiddenView.java
@@ -6,7 +6,7 @@
6package tools.refinery.store.query.view; 6package tools.refinery.store.query.view;
7 7
8import tools.refinery.store.representation.Symbol; 8import tools.refinery.store.representation.Symbol;
9import tools.refinery.store.representation.TruthValue; 9import tools.refinery.logic.term.truthvalue.TruthValue;
10import tools.refinery.store.tuple.Tuple; 10import tools.refinery.store.tuple.Tuple;
11 11
12public class ForbiddenView extends TuplePreservingView<TruthValue> { 12public class ForbiddenView extends TuplePreservingView<TruthValue> {
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/view/FunctionView.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/view/FunctionView.java
index 74a5be07..5585f5f2 100644
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/view/FunctionView.java
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/view/FunctionView.java
@@ -1,11 +1,11 @@
1/* 1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/> 2 * SPDX-FileCopyrightText: 2021-2024 The Refinery Authors <https://refinery.tools/>
3 * 3 *
4 * SPDX-License-Identifier: EPL-2.0 4 * SPDX-License-Identifier: EPL-2.0
5 */ 5 */
6package tools.refinery.store.query.view; 6package tools.refinery.store.query.view;
7 7
8import tools.refinery.store.query.term.*; 8import tools.refinery.logic.term.*;
9import tools.refinery.store.representation.Symbol; 9import tools.refinery.store.representation.Symbol;
10 10
11import java.util.ArrayList; 11import java.util.ArrayList;
@@ -33,4 +33,18 @@ public final class FunctionView<T> extends AbstractFunctionView<T> {
33 public <R> AssignedValue<R> aggregate(Aggregator<R, T> aggregator, NodeVariable... arguments) { 33 public <R> AssignedValue<R> aggregate(Aggregator<R, T> aggregator, NodeVariable... arguments) {
34 return aggregate(aggregator, List.of(arguments)); 34 return aggregate(aggregator, List.of(arguments));
35 } 35 }
36
37 public AssignedValue<T> leftJoin(T defaultValue, List<NodeVariable> arguments) {
38 return targetVariable -> {
39 var placeholderVariable = Variable.of(getSymbol().valueType());
40 var argumentsWithPlaceholder = new ArrayList<Variable>(arguments.size() + 1);
41 argumentsWithPlaceholder.addAll(arguments);
42 argumentsWithPlaceholder.add(placeholderVariable);
43 return leftJoinBy(placeholderVariable, defaultValue, argumentsWithPlaceholder).toLiteral(targetVariable);
44 };
45 }
46
47 public AssignedValue<T> leftJoin(T defaultValue, NodeVariable... arguments) {
48 return leftJoin(defaultValue, List.of(arguments));
49 }
36} 50}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/view/MayView.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/view/MayView.java
index c322e220..3a6cc93b 100644
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/view/MayView.java
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/view/MayView.java
@@ -6,7 +6,7 @@
6package tools.refinery.store.query.view; 6package tools.refinery.store.query.view;
7 7
8import tools.refinery.store.representation.Symbol; 8import tools.refinery.store.representation.Symbol;
9import tools.refinery.store.representation.TruthValue; 9import tools.refinery.logic.term.truthvalue.TruthValue;
10import tools.refinery.store.tuple.Tuple; 10import tools.refinery.store.tuple.Tuple;
11 11
12public class MayView extends TuplePreservingView<TruthValue> { 12public class MayView extends TuplePreservingView<TruthValue> {
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/view/MustView.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/view/MustView.java
index 65bb4e4c..af984327 100644
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/view/MustView.java
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/view/MustView.java
@@ -6,7 +6,7 @@
6package tools.refinery.store.query.view; 6package tools.refinery.store.query.view;
7 7
8import tools.refinery.store.representation.Symbol; 8import tools.refinery.store.representation.Symbol;
9import tools.refinery.store.representation.TruthValue; 9import tools.refinery.logic.term.truthvalue.TruthValue;
10import tools.refinery.store.tuple.Tuple; 10import tools.refinery.store.tuple.Tuple;
11 11
12public class MustView extends TuplePreservingView<TruthValue> { 12public class MustView extends TuplePreservingView<TruthValue> {
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/view/NodeFunctionView.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/view/NodeFunctionView.java
index fcf11506..01865cbe 100644
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/view/NodeFunctionView.java
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/view/NodeFunctionView.java
@@ -5,7 +5,7 @@
5 */ 5 */
6package tools.refinery.store.query.view; 6package tools.refinery.store.query.view;
7 7
8import tools.refinery.store.query.term.Parameter; 8import tools.refinery.logic.term.Parameter;
9import tools.refinery.store.representation.Symbol; 9import tools.refinery.store.representation.Symbol;
10import tools.refinery.store.tuple.Tuple1; 10import tools.refinery.store.tuple.Tuple1;
11 11
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/view/TuplePreservingView.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/view/TuplePreservingView.java
index ed12cd9d..6841488d 100644
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/view/TuplePreservingView.java
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/view/TuplePreservingView.java
@@ -7,7 +7,7 @@ package tools.refinery.store.query.view;
7 7
8import tools.refinery.store.map.CursorAsIterator; 8import tools.refinery.store.map.CursorAsIterator;
9import tools.refinery.store.model.Model; 9import tools.refinery.store.model.Model;
10import tools.refinery.store.query.term.Parameter; 10import tools.refinery.logic.term.Parameter;
11import tools.refinery.store.representation.Symbol; 11import tools.refinery.store.representation.Symbol;
12import tools.refinery.store.tuple.Tuple; 12import tools.refinery.store.tuple.Tuple;
13import tools.refinery.store.tuple.Tuple1; 13import tools.refinery.store.tuple.Tuple1;
diff --git a/subprojects/store-query/src/test/java/tools/refinery/store/query/dnf/DnfBuilderLiteralEliminationTest.java b/subprojects/store-query/src/test/java/tools/refinery/store/query/dnf/DnfBuilderLiteralEliminationTest.java
deleted file mode 100644
index 6a2dc0c7..00000000
--- a/subprojects/store-query/src/test/java/tools/refinery/store/query/dnf/DnfBuilderLiteralEliminationTest.java
+++ /dev/null
@@ -1,259 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.dnf;
7
8import org.junit.jupiter.api.Test;
9import org.junit.jupiter.params.ParameterizedTest;
10import org.junit.jupiter.params.provider.CsvSource;
11import tools.refinery.store.query.literal.BooleanLiteral;
12import tools.refinery.store.query.term.NodeVariable;
13import tools.refinery.store.query.term.ParameterDirection;
14import tools.refinery.store.query.term.Variable;
15import tools.refinery.store.query.term.bool.BoolTerms;
16import tools.refinery.store.query.view.KeyOnlyView;
17import tools.refinery.store.query.view.SymbolView;
18import tools.refinery.store.representation.Symbol;
19
20import java.util.List;
21
22import static org.hamcrest.MatcherAssert.assertThat;
23import static tools.refinery.store.query.literal.Literals.check;
24import static tools.refinery.store.query.literal.Literals.not;
25import static tools.refinery.store.query.tests.QueryMatchers.structurallyEqualTo;
26
27class DnfBuilderLiteralEliminationTest {
28 private final Symbol<Boolean> friend = Symbol.of("friend", 2);
29 private final SymbolView<Boolean> friendView = new KeyOnlyView<>(friend);
30 private final NodeVariable p = Variable.of("p");
31 private final NodeVariable q = Variable.of("q");
32 private final Dnf trueDnf = Dnf.builder().parameter(p, ParameterDirection.IN).clause().build();
33 private final Dnf falseDnf = Dnf.builder().parameter(p).build();
34
35 @Test
36 void eliminateTrueTest() {
37 var actual = Dnf.builder()
38 .parameters(p, q)
39 .clause(BooleanLiteral.TRUE, friendView.call(p, q))
40 .build();
41 var expected = Dnf.builder().parameters(p, q).clause(friendView.call(p, q)).build();
42
43 assertThat(actual, structurallyEqualTo(expected));
44 }
45
46 @Test
47 void eliminateTrueAssumptionTest() {
48 var actual = Dnf.builder()
49 .parameters(p, q)
50 .clause(check(BoolTerms.constant(true)), friendView.call(p, q))
51 .build();
52 var expected = Dnf.builder().parameters(p, q).clause(friendView.call(p, q)).build();
53
54 assertThat(actual, structurallyEqualTo(expected));
55 }
56
57 @Test
58 void eliminateFalseTest() {
59 var actual = Dnf.builder()
60 .parameters(p, q)
61 .clause(friendView.call(p, q))
62 .clause(friendView.call(q, p), BooleanLiteral.FALSE)
63 .build();
64 var expected = Dnf.builder().parameters(p, q).clause(friendView.call(p, q)).build();
65
66 assertThat(actual, structurallyEqualTo(expected));
67 }
68
69 @ParameterizedTest
70 @CsvSource(value = {
71 "false",
72 "null"
73 }, nullValues = "null")
74 void eliminateFalseAssumptionTest(Boolean value) {
75 var actual = Dnf.builder()
76 .parameters(p, q)
77 .clause(friendView.call(p, q))
78 .clause(friendView.call(q, p), check(BoolTerms.constant(value)))
79 .build();
80 var expected = Dnf.builder().parameters(p, q).clause(friendView.call(p, q)).build();
81
82 assertThat(actual, structurallyEqualTo(expected));
83 }
84
85 @Test
86 void alwaysTrueTest() {
87 var actual = Dnf.builder()
88 .parameters(List.of(p, q), ParameterDirection.IN)
89 .clause(friendView.call(p, q))
90 .clause(BooleanLiteral.TRUE)
91 .build();
92 var expected = Dnf.builder().parameters(List.of(p, q), ParameterDirection.IN).clause().build();
93
94 assertThat(actual, structurallyEqualTo(expected));
95 }
96
97 @Test
98 void alwaysFalseTest() {
99 var actual = Dnf.builder()
100 .parameters(p, q)
101 .clause(friendView.call(p, q), BooleanLiteral.FALSE)
102 .build();
103 var expected = Dnf.builder().parameters(p, q).build();
104
105 assertThat(actual, structurallyEqualTo(expected));
106 }
107
108 @Test
109 void eliminateTrueDnfTest() {
110 var actual = Dnf.builder()
111 .parameters(p, q)
112 .clause(trueDnf.call(q), friendView.call(p, q))
113 .build();
114 var expected = Dnf.builder().parameters(p, q).clause(friendView.call(p, q)).build();
115
116 assertThat(actual, structurallyEqualTo(expected));
117 }
118
119 @Test
120 void eliminateFalseDnfTest() {
121 var actual = Dnf.builder()
122 .parameters(p, q)
123 .clause(friendView.call(p, q))
124 .clause(friendView.call(q, p), falseDnf.call(q))
125 .build();
126 var expected = Dnf.builder().parameters(p, q).clause(friendView.call(p, q)).build();
127
128 assertThat(actual, structurallyEqualTo(expected));
129 }
130
131 @Test
132 void alwaysTrueDnfTest() {
133 var actual = Dnf.builder()
134 .parameters(List.of(p, q), ParameterDirection.IN)
135 .clause(friendView.call(p, q))
136 .clause(trueDnf.call(q))
137 .build();
138 var expected = Dnf.builder().parameters(List.of(p, q), ParameterDirection.IN).clause().build();
139
140 assertThat(actual, structurallyEqualTo(expected));
141 }
142
143 @Test
144 void alwaysFalseDnfTest() {
145 var actual = Dnf.builder()
146 .parameters(p, q)
147 .clause(friendView.call(p, q), falseDnf.call(q))
148 .build();
149 var expected = Dnf.builder().parameters(p, q).build();
150
151 assertThat(actual, structurallyEqualTo(expected));
152 }
153
154 @Test
155 void eliminateNotFalseDnfTest() {
156 var actual = Dnf.builder()
157 .parameters(p, q)
158 .clause(not(falseDnf.call(q)), friendView.call(p, q))
159 .build();
160 var expected = Dnf.builder().parameters(p, q).clause(friendView.call(p, q)).build();
161
162 assertThat(actual, structurallyEqualTo(expected));
163 }
164
165 @Test
166 void eliminateNotTrueDnfTest() {
167 var actual = Dnf.builder()
168 .parameters(p, q)
169 .clause(friendView.call(p, q))
170 .clause(friendView.call(q, p), not(trueDnf.call(q)))
171 .build();
172 var expected = Dnf.builder().parameters(p, q).clause(friendView.call(p, q)).build();
173
174 assertThat(actual, structurallyEqualTo(expected));
175 }
176
177 @Test
178 void alwaysNotFalseDnfTest() {
179 var actual = Dnf.builder()
180 .parameters(List.of(p, q), ParameterDirection.IN)
181 .clause(friendView.call(p, q))
182 .clause(not(falseDnf.call(q)))
183 .build();
184 var expected = Dnf.builder().parameters(List.of(p, q), ParameterDirection.IN).clause().build();
185
186 assertThat(actual, structurallyEqualTo(expected));
187 }
188
189 @Test
190 void alwaysNotTrueDnfTest() {
191 var actual = Dnf.builder()
192 .parameters(p, q)
193 .clause(friendView.call(p, q), not(trueDnf.call(q)))
194 .build();
195 var expected = Dnf.builder().parameters(p, q).build();
196
197 assertThat(actual, structurallyEqualTo(expected));
198 }
199
200 @Test
201 void removeDuplicateTest() {
202 var actual = Dnf.of(builder -> builder.clause((p, q) -> List.of(
203 friendView.call(p, q),
204 friendView.call(p, q)
205 )));
206 var expected = Dnf.of(builder -> builder.clause((p, q) -> List.of(friendView.call(p, q))));
207
208 assertThat(actual, structurallyEqualTo(expected));
209 }
210
211 @Test
212 void removeContradictoryTest() {
213 var actual = Dnf.of(builder -> builder.clause((p, q) -> List.of(
214 friendView.call(p, q),
215 not(friendView.call(p, q))
216 )));
217 var expected = Dnf.builder().build();
218
219 assertThat(actual, structurallyEqualTo(expected));
220 }
221
222 @Test
223 void removeContradictoryUniversalTest() {
224 var actual = Dnf.of(builder -> builder.clause((p, q) -> List.of(
225 friendView.call(q, q),
226 friendView.call(p, q),
227 not(friendView.call(p, Variable.of()))
228 )));
229 var expected = Dnf.builder().build();
230
231 assertThat(actual, structurallyEqualTo(expected));
232 }
233
234 @Test
235 void removeContradictoryExistentialUniversalTest() {
236 var actual = Dnf.of(builder -> builder.clause((p) -> List.of(
237 friendView.call(p, Variable.of()),
238 not(friendView.call(p, Variable.of()))
239 )));
240 var expected = Dnf.builder().build();
241
242 assertThat(actual, structurallyEqualTo(expected));
243 }
244
245 @Test
246 void removeContradictoryUniversalParameterTest() {
247 var actual = Dnf.of(builder -> {
248 var p = builder.parameter("p");
249 builder.clause((q) -> List.of(
250 friendView.call(q, q),
251 friendView.call(p, q),
252 not(friendView.call(p, Variable.of()))
253 ));
254 });
255 var expected = Dnf.builder().parameter(p).build();
256
257 assertThat(actual, structurallyEqualTo(expected));
258 }
259}
diff --git a/subprojects/store-query/src/test/java/tools/refinery/store/query/dnf/DnfBuilderVariableUnificationTest.java b/subprojects/store-query/src/test/java/tools/refinery/store/query/dnf/DnfBuilderVariableUnificationTest.java
deleted file mode 100644
index fc40c7b3..00000000
--- a/subprojects/store-query/src/test/java/tools/refinery/store/query/dnf/DnfBuilderVariableUnificationTest.java
+++ /dev/null
@@ -1,325 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.dnf;
7
8import org.junit.jupiter.api.Test;
9import tools.refinery.store.query.term.ParameterDirection;
10import tools.refinery.store.query.term.Variable;
11import tools.refinery.store.query.view.KeyOnlyView;
12import tools.refinery.store.query.view.SymbolView;
13import tools.refinery.store.representation.Symbol;
14
15import java.util.List;
16
17import static org.hamcrest.MatcherAssert.assertThat;
18import static tools.refinery.store.query.tests.QueryMatchers.structurallyEqualTo;
19
20class DnfBuilderVariableUnificationTest {
21 private final Symbol<Boolean> friend = Symbol.of("friend", 2);
22 private final Symbol<Boolean> children = Symbol.of("children", 2);
23 private final SymbolView<Boolean> friendView = new KeyOnlyView<>(friend);
24 private final SymbolView<Boolean> childrenView = new KeyOnlyView<>(children);
25
26 @Test
27 void equalToParameterTest() {
28 var actual = Dnf.of(builder -> {
29 var p = builder.parameter("p");
30 builder.clause(q -> List.of(
31 friendView.call(p, q),
32 p.isEquivalent(q)
33 ));
34 });
35
36 var expectedP = Variable.of("p");
37 assertThat(actual, structurallyEqualTo(
38 List.of(new SymbolicParameter(expectedP, ParameterDirection.OUT)),
39 List.of(
40 List.of(friendView.call(expectedP, expectedP))
41 )
42 ));
43 }
44
45 @Test
46 void equalToParameterReverseTest() {
47 var actual = Dnf.of(builder -> {
48 var p = builder.parameter("p");
49 builder.clause(q -> List.of(
50 friendView.call(p, q),
51 q.isEquivalent(p)
52 ));
53 });
54
55 var expectedP = Variable.of("p");
56 assertThat(actual, structurallyEqualTo(
57 List.of(new SymbolicParameter(expectedP, ParameterDirection.OUT)),
58 List.of(
59 List.of(friendView.call(expectedP, expectedP))
60 )
61 ));
62 }
63
64 @Test
65 void equalQuantifiedTest() {
66 var actual = Dnf.of(builder -> builder.clause((p, q) -> List.of(
67 friendView.call(p, q),
68 p.isEquivalent(q)
69 )));
70
71 var expectedP = Variable.of("p");
72 assertThat(actual, structurallyEqualTo(
73 List.of(),
74 List.of(
75 List.of(friendView.call(expectedP, expectedP))
76 )
77 ));
78 }
79
80 @Test
81 void equalQuantifiedTransitiveTest() {
82 var actual = Dnf.of(builder -> builder.clause((p, q, r) -> List.of(
83 friendView.call(p, q),
84 p.isEquivalent(q),
85 childrenView.call(p, r),
86 q.isEquivalent(r)
87 )));
88
89 var expectedP = Variable.of("p");
90 assertThat(actual, structurallyEqualTo(
91 List.of(),
92 List.of(
93 List.of(friendView.call(expectedP, expectedP), childrenView.call(expectedP, expectedP))
94 )
95 ));
96 }
97
98 @Test
99 void equalQuantifiedTransitiveRemoveDuplicateTest() {
100 var actual = Dnf.of(builder -> builder.clause((p, q, r) -> List.of(
101 friendView.call(p, q),
102 p.isEquivalent(q),
103 friendView.call(p, r),
104 q.isEquivalent(r)
105 )));
106
107 var expectedP = Variable.of("p");
108 assertThat(actual, structurallyEqualTo(
109 List.of(),
110 List.of(
111 List.of(friendView.call(expectedP, expectedP))
112 )
113 ));
114 }
115
116 @Test
117 void parametersEqualTest() {
118 var actual = Dnf.of(builder -> {
119 var p = builder.parameter("p");
120 var q = builder.parameter("q");
121 builder.clause(
122 friendView.call(p, q),
123 p.isEquivalent(q)
124 );
125 });
126
127 var expectedP = Variable.of("p");
128 var expectedQ = Variable.of("q");
129 assertThat(actual, structurallyEqualTo(
130 List.of(
131 new SymbolicParameter(expectedP, ParameterDirection.OUT),
132 new SymbolicParameter(expectedQ, ParameterDirection.OUT)
133 ),
134 List.of(
135 List.of(friendView.call(expectedP, expectedP), expectedQ.isEquivalent(expectedP))
136 )
137 ));
138 }
139
140 @Test
141 void parametersEqualTransitiveTest() {
142 var actual = Dnf.of(builder -> {
143 var p = builder.parameter("p");
144 var q = builder.parameter("q");
145 var r = builder.parameter("r");
146 builder.clause(
147 friendView.call(p, q),
148 childrenView.call(p, r),
149 p.isEquivalent(q),
150 r.isEquivalent(q)
151 );
152 });
153
154 var expectedP = Variable.of("p");
155 var expectedQ = Variable.of("q");
156 var expectedR = Variable.of("r");
157 assertThat(actual, structurallyEqualTo(
158 List.of(
159 new SymbolicParameter(expectedP, ParameterDirection.OUT),
160 new SymbolicParameter(expectedQ, ParameterDirection.OUT),
161 new SymbolicParameter(expectedR, ParameterDirection.OUT)
162 ),
163 List.of(
164 List.of(
165 friendView.call(expectedP, expectedP),
166 expectedQ.isEquivalent(expectedP),
167 expectedR.isEquivalent(expectedP),
168 childrenView.call(expectedP, expectedP)
169 )
170 )
171 ));
172 }
173
174 @Test
175 void parameterAndQuantifiedEqualsTest() {
176 var actual = Dnf.of(builder -> {
177 var p = builder.parameter("p");
178 var q = builder.parameter("q");
179 builder.clause((r) -> List.of(
180 friendView.call(p, r),
181 p.isEquivalent(r),
182 childrenView.call(q, r),
183 q.isEquivalent(r)
184 ));
185 });
186
187
188 var expectedP = Variable.of("p");
189 var expectedQ = Variable.of("q");
190 assertThat(actual, structurallyEqualTo(
191 List.of(
192 new SymbolicParameter(expectedP, ParameterDirection.OUT),
193 new SymbolicParameter(expectedQ, ParameterDirection.OUT)
194 ),
195 List.of(
196 List.of(
197 friendView.call(expectedP, expectedP),
198 expectedQ.isEquivalent(expectedP),
199 childrenView.call(expectedP, expectedP)
200 )
201 )
202 ));
203 }
204
205 @Test
206 void parameterAndQuantifiedEqualsReverseFirstTest() {
207 var actual = Dnf.of(builder -> {
208 var p = builder.parameter("p");
209 var q = builder.parameter("q");
210 builder.clause((r) -> List.of(
211 friendView.call(p, r),
212 r.isEquivalent(p),
213 childrenView.call(q, r),
214 q.isEquivalent(r)
215 ));
216 });
217
218 var expectedP = Variable.of("p");
219 var expectedQ = Variable.of("q");
220 assertThat(actual, structurallyEqualTo(
221 List.of(
222 new SymbolicParameter(expectedP, ParameterDirection.OUT),
223 new SymbolicParameter(expectedQ, ParameterDirection.OUT)
224 ),
225 List.of(
226 List.of(
227 friendView.call(expectedP, expectedP),
228 expectedQ.isEquivalent(expectedP),
229 childrenView.call(expectedP, expectedP)
230 )
231 )
232 ));
233 }
234
235 @Test
236 void parameterAndQuantifiedEqualsReverseSecondTest() {
237 var actual = Dnf.of(builder -> {
238 var p = builder.parameter("p");
239 var q = builder.parameter("q");
240 builder.clause((r) -> List.of(
241 friendView.call(p, r),
242 p.isEquivalent(r),
243 childrenView.call(q, r),
244 r.isEquivalent(q)
245 ));
246 });
247
248 var expectedP = Variable.of("p");
249 var expectedQ = Variable.of("q");
250 assertThat(actual, structurallyEqualTo(
251 List.of(
252 new SymbolicParameter(expectedP, ParameterDirection.OUT),
253 new SymbolicParameter(expectedQ, ParameterDirection.OUT)
254 ),
255 List.of(
256 List.of(
257 friendView.call(expectedP, expectedP),
258 expectedQ.isEquivalent(expectedP),
259 childrenView.call(expectedP, expectedP)
260 )
261 )
262 ));
263 }
264
265 @Test
266 void parameterAndQuantifiedEqualsReverseBoth() {
267 var actual = Dnf.of(builder -> {
268 var p = builder.parameter("p");
269 var q = builder.parameter("q");
270 builder.clause((r) -> List.of(
271 friendView.call(p, r),
272 p.isEquivalent(r),
273 childrenView.call(q, r),
274 r.isEquivalent(q)
275 ));
276 });
277
278 var expectedP = Variable.of("p");
279 var expectedQ = Variable.of("q");
280 assertThat(actual, structurallyEqualTo(
281 List.of(
282 new SymbolicParameter(expectedP, ParameterDirection.OUT),
283 new SymbolicParameter(expectedQ, ParameterDirection.OUT)
284 ),
285 List.of(
286 List.of(
287 friendView.call(expectedP, expectedP),
288 expectedQ.isEquivalent(expectedP),
289 childrenView.call(expectedP, expectedP)
290 )
291 )
292 ));
293 }
294
295 @Test
296 void parameterAndTwoQuantifiedEqualsTest() {
297 var actual = Dnf.of(builder -> {
298 var p = builder.parameter("p");
299 var q = builder.parameter("q");
300 builder.clause((r, s) -> List.of(
301 r.isEquivalent(s),
302 friendView.call(p, r),
303 p.isEquivalent(r),
304 childrenView.call(q, s),
305 q.isEquivalent(s)
306 ));
307 });
308
309 var expectedP = Variable.of("p");
310 var expectedQ = Variable.of("q");
311 assertThat(actual, structurallyEqualTo(
312 List.of(
313 new SymbolicParameter(expectedP, ParameterDirection.OUT),
314 new SymbolicParameter(expectedQ, ParameterDirection.OUT)
315 ),
316 List.of(
317 List.of(
318 friendView.call(expectedP, expectedP),
319 expectedQ.isEquivalent(expectedP),
320 childrenView.call(expectedP, expectedP)
321 )
322 )
323 ));
324 }
325}
diff --git a/subprojects/store-query/src/test/java/tools/refinery/store/query/dnf/DnfToDefinitionStringTest.java b/subprojects/store-query/src/test/java/tools/refinery/store/query/dnf/DnfToDefinitionStringTest.java
deleted file mode 100644
index 12cfaa4e..00000000
--- a/subprojects/store-query/src/test/java/tools/refinery/store/query/dnf/DnfToDefinitionStringTest.java
+++ /dev/null
@@ -1,157 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.dnf;
7
8import org.junit.jupiter.api.Test;
9import tools.refinery.store.query.term.NodeVariable;
10import tools.refinery.store.query.term.ParameterDirection;
11import tools.refinery.store.query.term.Variable;
12import tools.refinery.store.query.view.AnySymbolView;
13import tools.refinery.store.query.view.KeyOnlyView;
14import tools.refinery.store.representation.Symbol;
15
16import static org.hamcrest.MatcherAssert.assertThat;
17import static org.hamcrest.Matchers.is;
18import static tools.refinery.store.query.literal.Literals.not;
19
20class DnfToDefinitionStringTest {
21 private static final Symbol<Boolean> person = Symbol.of("person", 1);
22 private static final Symbol<Boolean> friend = Symbol.of("friend", 2);
23 private static final AnySymbolView personView = new KeyOnlyView<>(person);
24 private static final AnySymbolView friendView = new KeyOnlyView<>(friend);
25 private static final NodeVariable p = Variable.of("p");
26 private static final NodeVariable q = Variable.of("q");
27
28 @Test
29 void noClausesTest() {
30 var dnf = Dnf.builder("Example").parameter(p).build();
31
32 assertThat(dnf.toDefinitionString(), is("""
33 pred Example(p) <->
34 <no clauses>.
35 """));
36 }
37
38 @Test
39 void noParametersTest() {
40 var dnf = Dnf.builder("Example").build();
41
42 assertThat(dnf.toDefinitionString(), is("""
43 pred Example() <->
44 <no clauses>.
45 """));
46 }
47
48 @Test
49 void emptyClauseTest() {
50 var dnf = Dnf.builder("Example").parameter(p, ParameterDirection.IN).clause().build();
51
52 assertThat(dnf.toDefinitionString(), is("""
53 pred Example(in p) <->
54 <empty>.
55 """));
56 }
57
58 @Test
59 void relationViewPositiveTest() {
60 var dnf = Dnf.builder("Example").parameter(p).clause(friendView.call(p, q)).build();
61
62 assertThat(dnf.toDefinitionString(), is("""
63 pred Example(p) <->
64 @RelationView("key") friend(p, q).
65 """));
66 }
67
68 @Test
69 void relationViewNegativeTest() {
70 var dnf = Dnf.builder("Example")
71 .parameter(p, ParameterDirection.IN)
72 .clause(not(friendView.call(p, q)))
73 .build();
74
75 assertThat(dnf.toDefinitionString(), is("""
76 pred Example(in p) <->
77 !(@RelationView("key") friend(p, q)).
78 """));
79 }
80
81 @Test
82 void relationViewTransitiveTest() {
83 var dnf = Dnf.builder("Example").parameter(p).clause(friendView.callTransitive(p, q)).build();
84
85 assertThat(dnf.toDefinitionString(), is("""
86 pred Example(p) <->
87 @RelationView("key") friend+(p, q).
88 """));
89 }
90
91 @Test
92 void multipleParametersTest() {
93 var dnf = Dnf.builder("Example").parameters(p, q).clause(friendView.call(p, q)).build();
94
95 assertThat(dnf.toDefinitionString(), is("""
96 pred Example(p, q) <->
97 @RelationView("key") friend(p, q).
98 """));
99 }
100
101 @Test
102 void multipleLiteralsTest() {
103 var dnf = Dnf.builder("Example")
104 .parameter(p)
105 .clause(
106 personView.call(p),
107 personView.call(q),
108 friendView.call(p, q)
109 )
110 .build();
111
112 assertThat(dnf.toDefinitionString(), is("""
113 pred Example(p) <->
114 @RelationView("key") person(p),
115 @RelationView("key") person(q),
116 @RelationView("key") friend(p, q).
117 """));
118 }
119
120 @Test
121 void multipleClausesTest() {
122 var dnf = Dnf.builder("Example")
123 .parameter(p)
124 .clause(friendView.call(p, q))
125 .clause(friendView.call(q, p))
126 .build();
127
128 assertThat(dnf.toDefinitionString(), is("""
129 pred Example(p) <->
130 @RelationView("key") friend(p, q)
131 ;
132 @RelationView("key") friend(q, p).
133 """));
134 }
135
136 @Test
137 void dnfTest() {
138 var r = Variable.of("r");
139 var s = Variable.of("s");
140 var called = Dnf.builder("Called").parameters(r, s).clause(friendView.call(r, s)).build();
141 var dnf = Dnf.builder("Example")
142 .parameter(p)
143 .clause(
144 personView.call(p),
145 personView.call(q),
146 not(called.call(p, q))
147 )
148 .build();
149
150 assertThat(dnf.toDefinitionString(), is("""
151 pred Example(p) <->
152 @RelationView("key") person(p),
153 @RelationView("key") person(q),
154 !(@Dnf Called(p, q)).
155 """));
156 }
157}
diff --git a/subprojects/store-query/src/test/java/tools/refinery/store/query/dnf/HashCodeTest.java b/subprojects/store-query/src/test/java/tools/refinery/store/query/dnf/HashCodeTest.java
deleted file mode 100644
index 0c8eaeed..00000000
--- a/subprojects/store-query/src/test/java/tools/refinery/store/query/dnf/HashCodeTest.java
+++ /dev/null
@@ -1,67 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.dnf;
7
8import org.junit.jupiter.api.Test;
9import tools.refinery.store.query.term.NodeVariable;
10import tools.refinery.store.query.term.Variable;
11import tools.refinery.store.query.view.AnySymbolView;
12import tools.refinery.store.query.view.KeyOnlyView;
13import tools.refinery.store.representation.Symbol;
14
15import static org.hamcrest.MatcherAssert.assertThat;
16import static org.hamcrest.Matchers.is;
17import static org.hamcrest.Matchers.not;
18
19class HashCodeTest {
20 private static final Symbol<Boolean> person = Symbol.of("Person", 1);
21 private static final Symbol<Boolean> friend = Symbol.of("friend", 2);
22 private static final AnySymbolView personView = new KeyOnlyView<>(person);
23 private static final AnySymbolView friendView = new KeyOnlyView<>(friend);
24 private static final NodeVariable p = Variable.of("p");
25 private static final NodeVariable q = Variable.of("q");
26
27 @Test
28 void flatEqualsTest() {
29 var expected = Dnf.builder("Expected").parameters(q).clause(personView.call(q)).build();
30 var actual = Dnf.builder("Actual").parameters(p).clause(personView.call(p)).build();
31
32 assertThat(actual.hashCodeWithSubstitution(), is(expected.hashCodeWithSubstitution()));
33 }
34
35 @Test
36 void flatNotEqualsTest() {
37 var expected = Dnf.builder("Expected").parameters(q).clause(friendView.call(q, q)).build();
38 var actual = Dnf.builder("Actual").parameters(p).clause(friendView.call(p, q)).build();
39
40 assertThat(actual.hashCodeWithSubstitution(), not(expected.hashCodeWithSubstitution()));
41 }
42
43 @Test
44 void deepEqualsTest() {
45 var expected2 = Dnf.builder("Expected2").parameters(p).clause(personView.call(p)).build();
46 var expected = Dnf.builder("Expected").parameters(q).clause(
47 expected2.call(q)
48 ).build();
49 var actual = Dnf.builder("Actual").parameters(q).clause(
50 expected2.call(q)
51 ).build();
52
53 assertThat(actual.hashCodeWithSubstitution(), is(expected.hashCodeWithSubstitution()));
54 }
55
56 @Test
57 void deepNotEqualsTest() {
58 var expected = Dnf.builder("Expected").parameters(q).clause(
59 Dnf.builder("Expected2").parameters(p).clause(personView.call(p)).build().call(q)
60 ).build();
61 var actual = Dnf.builder("Actual").parameters(q).clause(
62 Dnf.builder("Actual2").parameters(p).clause(personView.call(p)).build().call(q)
63 ).build();
64
65 assertThat(actual.hashCodeWithSubstitution(), not(expected.hashCodeWithSubstitution()));
66 }
67}
diff --git a/subprojects/store-query/src/test/java/tools/refinery/store/query/dnf/TopologicalSortTest.java b/subprojects/store-query/src/test/java/tools/refinery/store/query/dnf/TopologicalSortTest.java
deleted file mode 100644
index 854bd469..00000000
--- a/subprojects/store-query/src/test/java/tools/refinery/store/query/dnf/TopologicalSortTest.java
+++ /dev/null
@@ -1,113 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.dnf;
7
8import org.junit.jupiter.api.Test;
9import tools.refinery.store.query.InvalidQueryException;
10import tools.refinery.store.query.term.NodeVariable;
11import tools.refinery.store.query.term.ParameterDirection;
12import tools.refinery.store.query.term.Variable;
13import tools.refinery.store.query.view.AnySymbolView;
14import tools.refinery.store.query.view.KeyOnlyView;
15import tools.refinery.store.representation.Symbol;
16
17import java.util.List;
18
19import static org.hamcrest.MatcherAssert.assertThat;
20import static org.junit.jupiter.api.Assertions.assertThrows;
21import static tools.refinery.store.query.literal.Literals.not;
22import static tools.refinery.store.query.tests.QueryMatchers.structurallyEqualTo;
23
24class TopologicalSortTest {
25 private static final Symbol<Boolean> friend = Symbol.of("friend", 2);
26 private static final AnySymbolView friendView = new KeyOnlyView<>(friend);
27 private static final Dnf example = Dnf.of("example", builder -> {
28 var a = builder.parameter("a", ParameterDirection.IN);
29 var b = builder.parameter("b", ParameterDirection.IN);
30 var c = builder.parameter("c", ParameterDirection.OUT);
31 var d = builder.parameter("d", ParameterDirection.OUT);
32 builder.clause(
33 friendView.call(a, b),
34 friendView.call(b, c),
35 friendView.call(c, d)
36 );
37 });
38 private static final NodeVariable p = Variable.of("p");
39 private static final NodeVariable q = Variable.of("q");
40 private static final NodeVariable r = Variable.of("r");
41 private static final NodeVariable s = Variable.of("s");
42 private static final NodeVariable t = Variable.of("t");
43
44 @Test
45 void topologicalSortTest() {
46 var actual = Dnf.builder("Actual")
47 .parameter(p, ParameterDirection.IN)
48 .parameter(q, ParameterDirection.OUT)
49 .clause(
50 not(friendView.call(p, q)),
51 example.call(p, q, r, s),
52 example.call(r, t, q, s),
53 friendView.call(r, t)
54 )
55 .build();
56
57 assertThat(actual, structurallyEqualTo(
58 List.of(
59 new SymbolicParameter(p, ParameterDirection.IN),
60 new SymbolicParameter(q, ParameterDirection.OUT)
61 ),
62 List.of(
63 List.of(
64 friendView.call(r, t),
65 example.call(r, t, q, s),
66 not(friendView.call(p, q)),
67 example.call(p, q, r, s)
68 )
69 )
70 ));
71 }
72
73 @Test
74 void missingInputTest() {
75 var builder = Dnf.builder("Actual")
76 .parameter(p, ParameterDirection.OUT)
77 .parameter(q, ParameterDirection.OUT)
78 .clause(
79 not(friendView.call(p, q)),
80 example.call(p, q, r, s),
81 example.call(r, t, q, s),
82 friendView.call(r, t)
83 );
84 assertThrows(InvalidQueryException.class, builder::build);
85 }
86
87 @Test
88 void missingVariableTest() {
89 var builder = Dnf.builder("Actual")
90 .parameter(p, ParameterDirection.IN)
91 .parameter(q, ParameterDirection.OUT)
92 .clause(
93 not(friendView.call(p, q)),
94 example.call(p, q, r, s),
95 example.call(r, t, q, s)
96 );
97 assertThrows(InvalidQueryException.class, builder::build);
98 }
99
100 @Test
101 void circularDependencyTest() {
102 var builder = Dnf.builder("Actual")
103 .parameter(p, ParameterDirection.IN)
104 .parameter(q, ParameterDirection.OUT)
105 .clause(
106 not(friendView.call(p, q)),
107 example.call(p, q, r, s),
108 example.call(r, t, q, s),
109 example.call(p, q, r, t)
110 );
111 assertThrows(InvalidQueryException.class, builder::build);
112 }
113}
diff --git a/subprojects/store-query/src/test/java/tools/refinery/store/query/dnf/VariableDirectionTest.java b/subprojects/store-query/src/test/java/tools/refinery/store/query/dnf/VariableDirectionTest.java
deleted file mode 100644
index fc3f5d48..00000000
--- a/subprojects/store-query/src/test/java/tools/refinery/store/query/dnf/VariableDirectionTest.java
+++ /dev/null
@@ -1,251 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.dnf;
7
8import org.junit.jupiter.params.ParameterizedTest;
9import org.junit.jupiter.params.provider.Arguments;
10import org.junit.jupiter.params.provider.MethodSource;
11import tools.refinery.store.query.literal.BooleanLiteral;
12import tools.refinery.store.query.literal.Literal;
13import tools.refinery.store.query.term.DataVariable;
14import tools.refinery.store.query.term.NodeVariable;
15import tools.refinery.store.query.term.ParameterDirection;
16import tools.refinery.store.query.term.Variable;
17import tools.refinery.store.query.view.AnySymbolView;
18import tools.refinery.store.query.view.FunctionView;
19import tools.refinery.store.query.view.KeyOnlyView;
20import tools.refinery.store.representation.Symbol;
21
22import java.util.ArrayList;
23import java.util.List;
24import java.util.stream.Stream;
25
26import static org.hamcrest.MatcherAssert.assertThat;
27import static org.hamcrest.Matchers.hasItem;
28import static org.hamcrest.Matchers.not;
29import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
30import static org.junit.jupiter.api.Assertions.assertThrows;
31import static tools.refinery.store.query.literal.Literals.not;
32import static tools.refinery.store.query.term.int_.IntTerms.INT_SUM;
33
34class VariableDirectionTest {
35 private static final Symbol<Boolean> person = Symbol.of("Person", 1);
36 private static final Symbol<Boolean> friend = Symbol.of("friend", 2);
37 private static final Symbol<Integer> age = Symbol.of("age", 1, Integer.class);
38 private static final AnySymbolView personView = new KeyOnlyView<>(person);
39 private static final AnySymbolView friendView = new KeyOnlyView<>(friend);
40 private static final FunctionView<Integer> ageView = new FunctionView<>(age);
41 private static final NodeVariable p = Variable.of("p");
42 private static final NodeVariable q = Variable.of("q");
43 private static final DataVariable<Integer> x = Variable.of("x", Integer.class);
44 private static final DataVariable<Integer> y = Variable.of("y", Integer.class);
45 private static final DataVariable<Integer> z = Variable.of("z", Integer.class);
46
47 @ParameterizedTest
48 @MethodSource("clausesWithVariableInput")
49 void unboundOutVariableTest(List<? extends Literal> clause) {
50 var builder = Dnf.builder().parameter(p, ParameterDirection.OUT).clause(clause);
51 assertThrows(InvalidClauseException.class, builder::build);
52 }
53
54 @ParameterizedTest
55 @MethodSource("clausesWithVariableInput")
56 void unboundInVariableTest(List<? extends Literal> clause) {
57 var builder = Dnf.builder().parameter(p, ParameterDirection.IN).clause(clause);
58 var dnf = assertDoesNotThrow(builder::build);
59 var clauses = dnf.getClauses();
60 if (clauses.size() > 0) {
61 assertThat(clauses.get(0).positiveVariables(), hasItem(p));
62 }
63 }
64
65 @ParameterizedTest
66 @MethodSource("clausesWithVariableInput")
67 void boundPrivateVariableTest(List<? extends Literal> clause) {
68 var clauseWithBinding = new ArrayList<Literal>(clause);
69 clauseWithBinding.add(personView.call(p));
70 var builder = Dnf.builder().clause(clauseWithBinding);
71 var dnf = assertDoesNotThrow(builder::build);
72 var clauses = dnf.getClauses();
73 if (clauses.size() > 0) {
74 assertThat(clauses.get(0).positiveVariables(), hasItem(p));
75 }
76 }
77
78 static Stream<Arguments> clausesWithVariableInput() {
79 return Stream.concat(
80 clausesNotBindingVariable(),
81 literalToClauseArgumentStream(literalsWithRequiredVariableInput())
82 );
83 }
84
85 @ParameterizedTest
86 @MethodSource("clausesNotBindingVariable")
87 void unboundPrivateVariableTest(List<? extends Literal> clause) {
88 var builder = Dnf.builder().clause(clause);
89 var dnf = assertDoesNotThrow(builder::build);
90 var clauses = dnf.getClauses();
91 if (clauses.size() > 0) {
92 assertThat(clauses.get(0).positiveVariables(), not(hasItem(p)));
93 }
94 }
95
96 @ParameterizedTest
97 @MethodSource("clausesNotBindingVariable")
98 void unboundByEquivalencePrivateVariableTest(List<? extends Literal> clause) {
99 var r = Variable.of("r");
100 var clauseWithEquivalence = new ArrayList<Literal>(clause);
101 clauseWithEquivalence.add(r.isEquivalent(p));
102 var builder = Dnf.builder().clause(clauseWithEquivalence);
103 assertThrows(InvalidClauseException.class, builder::build);
104 }
105
106 static Stream<Arguments> clausesNotBindingVariable() {
107 return Stream.concat(
108 Stream.of(
109 Arguments.of(List.of()),
110 Arguments.of(List.of(BooleanLiteral.TRUE)),
111 Arguments.of(List.of(BooleanLiteral.FALSE))
112 ),
113 literalToClauseArgumentStream(literalsWithPrivateVariable())
114 );
115 }
116
117 @ParameterizedTest
118 @MethodSource("literalsWithPrivateVariable")
119 void unboundTwicePrivateVariableTest(Literal literal) {
120 var builder = Dnf.builder().clause(not(personView.call(p)), literal);
121 assertThrows(InvalidClauseException.class, builder::build);
122 }
123
124 @ParameterizedTest
125 @MethodSource("literalsWithPrivateVariable")
126 void unboundTwiceByEquivalencePrivateVariableTest(Literal literal) {
127 var r = Variable.of("r");
128 var builder = Dnf.builder().clause(not(personView.call(r)), r.isEquivalent(p), literal);
129 assertThrows(InvalidClauseException.class, builder::build);
130 }
131
132 static Stream<Arguments> literalsWithPrivateVariable() {
133 var dnfWithOutput = Dnf.builder("WithOutput")
134 .parameter(p, ParameterDirection.OUT)
135 .parameter(q, ParameterDirection.OUT)
136 .clause(friendView.call(p, q))
137 .build();
138 var dnfWithOutputToAggregate = Dnf.builder("WithOutputToAggregate")
139 .parameter(p, ParameterDirection.OUT)
140 .parameter(q, ParameterDirection.OUT)
141 .parameter(x, ParameterDirection.OUT)
142 .clause(
143 friendView.call(p, q),
144 ageView.call(q, x)
145 )
146 .build();
147
148 return Stream.of(
149 Arguments.of(not(friendView.call(p, q))),
150 Arguments.of(y.assign(friendView.count(p, q))),
151 Arguments.of(y.assign(ageView.aggregate(INT_SUM, p))),
152 Arguments.of(not(dnfWithOutput.call(p, q))),
153 Arguments.of(y.assign(dnfWithOutput.count(p, q))),
154 Arguments.of(y.assign(dnfWithOutputToAggregate.aggregateBy(z, INT_SUM, p, q, z)))
155 );
156 }
157
158 @ParameterizedTest
159 @MethodSource("literalsWithRequiredVariableInput")
160 void unboundPrivateVariableTest(Literal literal) {
161 var builder = Dnf.builder().clause(literal);
162 assertThrows(InvalidClauseException.class, builder::build);
163 }
164
165 @ParameterizedTest
166 @MethodSource("literalsWithRequiredVariableInput")
167 void boundPrivateVariableInputTest(Literal literal) {
168 var builder = Dnf.builder().clause(personView.call(p), literal);
169 var dnf = assertDoesNotThrow(builder::build);
170 assertThat(dnf.getClauses().get(0).positiveVariables(), hasItem(p));
171 }
172
173 static Stream<Arguments> literalsWithRequiredVariableInput() {
174 var dnfWithInput = Dnf.builder("WithInput")
175 .parameter(p, ParameterDirection.IN)
176 .parameter(q, ParameterDirection.OUT)
177 .clause(friendView.call(p, q)).build();
178 var dnfWithInputToAggregate = Dnf.builder("WithInputToAggregate")
179 .parameter(p, ParameterDirection.IN)
180 .parameter(q, ParameterDirection.OUT)
181 .parameter(x, ParameterDirection.OUT)
182 .clause(
183 friendView.call(p, q),
184 ageView.call(q, x)
185 ).build();
186
187 return Stream.of(
188 Arguments.of(dnfWithInput.call(p, q)),
189 Arguments.of(dnfWithInput.call(p, p)),
190 Arguments.of(not(dnfWithInput.call(p, q))),
191 Arguments.of(not(dnfWithInput.call(p, p))),
192 Arguments.of(y.assign(dnfWithInput.count(p, q))),
193 Arguments.of(y.assign(dnfWithInput.count(p, p))),
194 Arguments.of(y.assign(dnfWithInputToAggregate.aggregateBy(z, INT_SUM, p, q, z))),
195 Arguments.of(y.assign(dnfWithInputToAggregate.aggregateBy(z, INT_SUM, p, p, z)))
196 );
197 }
198
199 @ParameterizedTest
200 @MethodSource("literalsWithVariableOutput")
201 void boundParameterTest(Literal literal) {
202 var builder = Dnf.builder().parameter(p, ParameterDirection.OUT).clause(literal);
203 var dnf = assertDoesNotThrow(builder::build);
204 assertThat(dnf.getClauses().get(0).positiveVariables(), hasItem(p));
205 }
206
207 @ParameterizedTest
208 @MethodSource("literalsWithVariableOutput")
209 void boundTwiceParameterTest(Literal literal) {
210 var builder = Dnf.builder().parameter(p, ParameterDirection.IN).clause(literal);
211 var dnf = assertDoesNotThrow(builder::build);
212 assertThat(dnf.getClauses().get(0).positiveVariables(), hasItem(p));
213 }
214
215 @ParameterizedTest
216 @MethodSource("literalsWithVariableOutput")
217 void boundPrivateVariableOutputTest(Literal literal) {
218 var dnfWithInput = Dnf.builder("WithInput")
219 .parameter(p, ParameterDirection.IN)
220 .clause(personView.call(p))
221 .build();
222 var builder = Dnf.builder().clause(dnfWithInput.call(p), literal);
223 var dnf = assertDoesNotThrow(builder::build);
224 assertThat(dnf.getClauses().get(0).positiveVariables(), hasItem(p));
225 }
226
227 @ParameterizedTest
228 @MethodSource("literalsWithVariableOutput")
229 void boundTwicePrivateVariableOutputTest(Literal literal) {
230 var builder = Dnf.builder().clause(personView.call(p), literal);
231 var dnf = assertDoesNotThrow(builder::build);
232 assertThat(dnf.getClauses().get(0).positiveVariables(), hasItem(p));
233 }
234
235 static Stream<Arguments> literalsWithVariableOutput() {
236 var dnfWithOutput = Dnf.builder("WithOutput")
237 .parameter(p, ParameterDirection.OUT)
238 .parameter(q, ParameterDirection.OUT)
239 .clause(friendView.call(p, q))
240 .build();
241
242 return Stream.of(
243 Arguments.of(friendView.call(p, q)),
244 Arguments.of(dnfWithOutput.call(p, q))
245 );
246 }
247
248 private static Stream<Arguments> literalToClauseArgumentStream(Stream<Arguments> literalArgumentsStream) {
249 return literalArgumentsStream.map(arguments -> Arguments.of(List.of(arguments.get()[0])));
250 }
251}
diff --git a/subprojects/store-query/src/test/java/tools/refinery/store/query/literal/AggregationLiteralTest.java b/subprojects/store-query/src/test/java/tools/refinery/store/query/literal/AggregationLiteralTest.java
deleted file mode 100644
index ddd57e96..00000000
--- a/subprojects/store-query/src/test/java/tools/refinery/store/query/literal/AggregationLiteralTest.java
+++ /dev/null
@@ -1,89 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.literal;
7
8import org.junit.jupiter.api.Test;
9import tools.refinery.store.query.Constraint;
10import tools.refinery.store.query.InvalidQueryException;
11import tools.refinery.store.query.dnf.Dnf;
12import tools.refinery.store.query.dnf.InvalidClauseException;
13import tools.refinery.store.query.term.*;
14
15import java.util.List;
16import java.util.Set;
17
18import static org.hamcrest.MatcherAssert.assertThat;
19import static org.hamcrest.Matchers.*;
20import static org.junit.jupiter.api.Assertions.assertAll;
21import static org.junit.jupiter.api.Assertions.assertThrows;
22import static tools.refinery.store.query.literal.Literals.not;
23import static tools.refinery.store.query.term.int_.IntTerms.INT_SUM;
24import static tools.refinery.store.query.term.int_.IntTerms.constant;
25
26class AggregationLiteralTest {
27 private static final NodeVariable p = Variable.of("p");
28 private static final DataVariable<Integer> x = Variable.of("x", Integer.class);
29 private static final DataVariable<Integer> y = Variable.of("y", Integer.class);
30 private static final DataVariable<Integer> z = Variable.of("z", Integer.class);
31 private static final Constraint fakeConstraint = new Constraint() {
32 @Override
33 public String name() {
34 return getClass().getName();
35 }
36
37 @Override
38 public List<Parameter> getParameters() {
39 return List.of(
40 new Parameter(null, ParameterDirection.OUT),
41 new Parameter(Integer.class, ParameterDirection.OUT)
42 );
43 }
44 };
45
46 @Test
47 void parameterDirectionTest() {
48 var literal = x.assign(fakeConstraint.aggregateBy(y, INT_SUM, p, y));
49 assertAll(
50 () -> assertThat(literal.getOutputVariables(), containsInAnyOrder(x)),
51 () -> assertThat(literal.getInputVariables(Set.of()), empty()),
52 () -> assertThat(literal.getInputVariables(Set.of(p)), containsInAnyOrder(p)),
53 () -> assertThat(literal.getPrivateVariables(Set.of()), containsInAnyOrder(p, y)),
54 () -> assertThat(literal.getPrivateVariables(Set.of(p)), containsInAnyOrder(y))
55 );
56 }
57
58 @Test
59 void missingAggregationVariableTest() {
60 var aggregation = fakeConstraint.aggregateBy(y, INT_SUM, p, z);
61 assertThrows(InvalidQueryException.class, () -> x.assign(aggregation));
62 }
63
64 @Test
65 void circularAggregationVariableTest() {
66 var aggregation = fakeConstraint.aggregateBy(x, INT_SUM, p, x);
67 assertThrows(InvalidQueryException.class, () -> x.assign(aggregation));
68 }
69
70 @Test
71 void unboundTwiceVariableTest() {
72 var builder = Dnf.builder()
73 .clause(
74 not(fakeConstraint.call(p, y)),
75 x.assign(fakeConstraint.aggregateBy(y, INT_SUM, p, y))
76 );
77 assertThrows(InvalidClauseException.class, builder::build);
78 }
79
80 @Test
81 void unboundBoundVariableTest() {
82 var builder = Dnf.builder()
83 .clause(
84 y.assign(constant(27)),
85 x.assign(fakeConstraint.aggregateBy(y, INT_SUM, p, y))
86 );
87 assertThrows(InvalidClauseException.class, builder::build);
88 }
89}
diff --git a/subprojects/store-query/src/test/java/tools/refinery/store/query/literal/CallLiteralTest.java b/subprojects/store-query/src/test/java/tools/refinery/store/query/literal/CallLiteralTest.java
deleted file mode 100644
index a01c6586..00000000
--- a/subprojects/store-query/src/test/java/tools/refinery/store/query/literal/CallLiteralTest.java
+++ /dev/null
@@ -1,94 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.literal;
7
8import org.junit.jupiter.api.Test;
9import tools.refinery.store.query.Constraint;
10import tools.refinery.store.query.term.NodeVariable;
11import tools.refinery.store.query.term.Parameter;
12import tools.refinery.store.query.term.ParameterDirection;
13import tools.refinery.store.query.term.Variable;
14
15import java.util.List;
16import java.util.Set;
17
18import static org.hamcrest.MatcherAssert.assertThat;
19import static org.hamcrest.Matchers.containsInAnyOrder;
20import static org.hamcrest.Matchers.empty;
21import static org.junit.jupiter.api.Assertions.assertAll;
22import static tools.refinery.store.query.literal.Literals.not;
23
24class CallLiteralTest {
25 private static final NodeVariable p = Variable.of("p");
26 private static final NodeVariable q = Variable.of("q");
27 private static final NodeVariable r = Variable.of("r");
28 private static final NodeVariable s = Variable.of("s");
29
30 private static final Constraint fakeConstraint = new Constraint() {
31 @Override
32 public String name() {
33 return getClass().getName();
34 }
35
36 @Override
37 public List<Parameter> getParameters() {
38 return List.of(
39 new Parameter(null, ParameterDirection.IN),
40 new Parameter(null, ParameterDirection.IN),
41 new Parameter(null, ParameterDirection.OUT),
42 new Parameter(null, ParameterDirection.OUT)
43 );
44 }
45 };
46
47 @Test
48 void notRepeatedPositiveDirectionTest() {
49 var literal = fakeConstraint.call(p, q, r, s);
50 assertAll(
51 () -> assertThat(literal.getOutputVariables(), containsInAnyOrder(r, s)),
52 () -> assertThat(literal.getInputVariables(Set.of()), containsInAnyOrder(p, q)),
53 () -> assertThat(literal.getInputVariables(Set.of(p, q, r)), containsInAnyOrder(p, q)),
54 () -> assertThat(literal.getPrivateVariables(Set.of()), empty()),
55 () -> assertThat(literal.getPrivateVariables(Set.of(p, q, r)), empty())
56 );
57 }
58
59 @Test
60 void notRepeatedNegativeDirectionTest() {
61 var literal = not(fakeConstraint.call(p, q, r, s));
62 assertAll(
63 () -> assertThat(literal.getOutputVariables(), empty()),
64 () -> assertThat(literal.getInputVariables(Set.of()), containsInAnyOrder(p, q)),
65 () -> assertThat(literal.getInputVariables(Set.of(p, q, r)), containsInAnyOrder(p, q, r)),
66 () -> assertThat(literal.getPrivateVariables(Set.of()), containsInAnyOrder(r, s)),
67 () -> assertThat(literal.getPrivateVariables(Set.of(p, q, r)), containsInAnyOrder(s))
68 );
69 }
70
71 @Test
72 void repeatedPositiveDirectionTest() {
73 var literal = fakeConstraint.call(p, p, q, q);
74 assertAll(
75 () -> assertThat(literal.getOutputVariables(), containsInAnyOrder(q)),
76 () -> assertThat(literal.getInputVariables(Set.of()), containsInAnyOrder(p)),
77 () -> assertThat(literal.getInputVariables(Set.of(p, q)), containsInAnyOrder(p)),
78 () -> assertThat(literal.getPrivateVariables(Set.of()), empty()),
79 () -> assertThat(literal.getPrivateVariables(Set.of(p, q)), empty())
80 );
81 }
82
83 @Test
84 void repeatedNegativeDirectionTest() {
85 var literal = not(fakeConstraint.call(p, p, q, q));
86 assertAll(
87 () -> assertThat(literal.getOutputVariables(), empty()),
88 () -> assertThat(literal.getInputVariables(Set.of()), containsInAnyOrder(p)),
89 () -> assertThat(literal.getInputVariables(Set.of(p, q)), containsInAnyOrder(p, q)),
90 () -> assertThat(literal.getPrivateVariables(Set.of()), containsInAnyOrder(q)),
91 () -> assertThat(literal.getPrivateVariables(Set.of(p, q)), empty())
92 );
93 }
94}
diff --git a/subprojects/store-query/src/test/java/tools/refinery/store/query/rewriter/DuplicateDnfRemoverTest.java b/subprojects/store-query/src/test/java/tools/refinery/store/query/rewriter/DuplicateDnfRemoverTest.java
deleted file mode 100644
index ebb24ab5..00000000
--- a/subprojects/store-query/src/test/java/tools/refinery/store/query/rewriter/DuplicateDnfRemoverTest.java
+++ /dev/null
@@ -1,164 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.rewriter;
7
8import org.junit.jupiter.api.BeforeEach;
9import org.junit.jupiter.api.Test;
10import tools.refinery.store.query.dnf.Query;
11import tools.refinery.store.query.literal.AbstractCallLiteral;
12import tools.refinery.store.query.literal.Reduction;
13import tools.refinery.store.query.term.Variable;
14import tools.refinery.store.query.view.AnySymbolView;
15import tools.refinery.store.query.view.KeyOnlyView;
16import tools.refinery.store.representation.Symbol;
17
18import java.util.List;
19
20import static org.hamcrest.MatcherAssert.assertThat;
21import static org.hamcrest.Matchers.is;
22import static org.hamcrest.Matchers.not;
23import static tools.refinery.store.query.literal.Literals.not;
24
25class DuplicateDnfRemoverTest {
26 private final static Symbol<Boolean> friend = Symbol.of("friend", 2);
27 private final static AnySymbolView friendView = new KeyOnlyView<>(friend);
28
29 private DuplicateDnfRemover sut;
30
31 @BeforeEach
32 void beforeEach() {
33 sut = new DuplicateDnfRemover();
34 }
35
36 @Test
37 void removeDuplicateSimpleTest() {
38 var one = Query.of("One", (builder, x, y) -> builder.clause(
39 friendView.call(x, y),
40 friendView.call(y, x)
41 ));
42 var two = Query.of("Two", (builder, x, y) -> builder.clause(
43 friendView.call(x, y),
44 friendView.call(y, x)
45 ));
46
47 var oneResult = sut.rewrite(one);
48 var twoResult = sut.rewrite(two);
49
50 assertThat(oneResult, is(twoResult));
51 assertThat(one, is(oneResult));
52 }
53
54 @Test
55 void notDuplicateSimpleTest() {
56 var one = Query.of("One", (builder, x, y) -> builder.clause(
57 friendView.call(x, y),
58 friendView.call(y, x)
59 ));
60 var two = Query.of("Two", (builder, x, y) -> builder.clause((z) -> List.of(
61 friendView.call(x, y),
62 friendView.call(y, z)
63 )));
64
65 var oneResult = sut.rewrite(one);
66 var twoResult = sut.rewrite(two);
67
68 assertThat(one, is(oneResult));
69 assertThat(two, is(twoResult));
70 }
71
72 @Test
73 void removeDuplicateRecursiveTest() {
74 var oneSubQuery = Query.of("OneSubQuery", (builder, x, y) -> builder.clause(
75 friendView.call(x, y),
76 friendView.call(y, x)
77 ));
78 var one = Query.of("One", (builder, x) -> builder.clause(
79 oneSubQuery.call(x, Variable.of())
80 ));
81 var twoSubQuery = Query.of("TwoSubQuery", (builder, x, y) -> builder.clause(
82 friendView.call(x, y),
83 friendView.call(y, x)
84 ));
85 var two = Query.of("Two", (builder, x) -> builder.clause(
86 twoSubQuery.call(x, Variable.of())
87 ));
88
89 var oneResult = sut.rewrite(one);
90 var twoResult = sut.rewrite(two);
91
92 assertThat(oneResult, is(twoResult));
93 assertThat(one, is(oneResult));
94 }
95
96 @Test
97 void notDuplicateRecursiveTest() {
98 var oneSubQuery = Query.of("OneSubQuery", (builder, x, y) -> builder.clause(
99 friendView.call(x, y),
100 friendView.call(y, x)
101 ));
102 var one = Query.of("One", (builder, x) -> builder.clause(
103 oneSubQuery.call(x, Variable.of())
104 ));
105 var twoSubQuery = Query.of("TwoSubQuery", (builder, x, y) -> builder.clause(
106 friendView.call(x, y),
107 friendView.call(y, x)
108 ));
109 var two = Query.of("Two", (builder, x) -> builder.clause(
110 twoSubQuery.call(Variable.of(), x)
111 ));
112
113 var oneResult = sut.rewrite(one);
114 var twoResult = sut.rewrite(two);
115
116 assertThat(one, is(oneResult));
117 assertThat(oneResult, is(not(twoResult)));
118
119 var oneCall = (AbstractCallLiteral) oneResult.getDnf().getClauses().get(0).literals().get(0);
120 var twoCall = (AbstractCallLiteral) twoResult.getDnf().getClauses().get(0).literals().get(0);
121
122 assertThat(oneCall.getTarget(), is(twoCall.getTarget()));
123 }
124
125 @Test
126 void removeContradictionTest() {
127 var oneSubQuery = Query.of("OneSubQuery", (builder, x, y) -> builder.clause(
128 friendView.call(x, y),
129 friendView.call(y, x)
130 ));
131 var twoSubQuery = Query.of("TwoSubQuery", (builder, x, y) -> builder.clause(
132 friendView.call(x, y),
133 friendView.call(y, x)
134 ));
135 var query = Query.of("Contradiction", (builder, x, y) -> builder.clause(
136 oneSubQuery.call(x, y),
137 not(twoSubQuery.call(x, y))
138 ));
139
140 var result = sut.rewrite(query);
141
142 assertThat(result.getDnf().getReduction(), is(Reduction.ALWAYS_FALSE));
143 }
144
145 @Test
146 void removeQuantifiedContradictionTest() {
147 var oneSubQuery = Query.of("OneSubQuery", (builder, x, y) -> builder.clause(
148 friendView.call(x, y),
149 friendView.call(y, x)
150 ));
151 var twoSubQuery = Query.of("TwoSubQuery", (builder, x, y) -> builder.clause(
152 friendView.call(x, y),
153 friendView.call(y, x)
154 ));
155 var query = Query.of("Contradiction", (builder, x) -> builder.clause(
156 oneSubQuery.call(x, Variable.of()),
157 not(twoSubQuery.call(x, Variable.of()))
158 ));
159
160 var result = sut.rewrite(query);
161
162 assertThat(result.getDnf().getReduction(), is(Reduction.ALWAYS_FALSE));
163 }
164}
diff --git a/subprojects/store-query/src/test/java/tools/refinery/store/query/rewriter/InputParameterResolverTest.java b/subprojects/store-query/src/test/java/tools/refinery/store/query/rewriter/InputParameterResolverTest.java
deleted file mode 100644
index ef0077e4..00000000
--- a/subprojects/store-query/src/test/java/tools/refinery/store/query/rewriter/InputParameterResolverTest.java
+++ /dev/null
@@ -1,228 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.rewriter;
7
8import org.junit.jupiter.api.BeforeEach;
9import org.junit.jupiter.api.Test;
10import tools.refinery.store.query.dnf.Dnf;
11import tools.refinery.store.query.dnf.Query;
12import tools.refinery.store.query.term.ParameterDirection;
13import tools.refinery.store.query.term.Variable;
14import tools.refinery.store.query.view.AnySymbolView;
15import tools.refinery.store.query.view.KeyOnlyView;
16import tools.refinery.store.representation.Symbol;
17
18import java.util.List;
19
20import static org.hamcrest.MatcherAssert.assertThat;
21import static org.hamcrest.Matchers.is;
22import static tools.refinery.store.query.literal.Literals.not;
23import static tools.refinery.store.query.tests.QueryMatchers.structurallyEqualTo;
24
25class InputParameterResolverTest {
26 private final static Symbol<Boolean> person = Symbol.of("Person", 1);
27 private final static Symbol<Boolean> friend = Symbol.of("friend", 2);
28 private final static AnySymbolView personView = new KeyOnlyView<>(person);
29 private final static AnySymbolView friendView = new KeyOnlyView<>(friend);
30
31 private InputParameterResolver sut;
32
33 @BeforeEach
34 void beforeEach() {
35 sut = new InputParameterResolver();
36 }
37
38 @Test
39 void inlineSingleClauseTest() {
40 var dnf = Dnf.of("SubQuery", builder -> {
41 var x = builder.parameter("x", ParameterDirection.OUT);
42 builder.clause(friendView.call(x, Variable.of()));
43 });
44 var query = Query.of("Actual", (builder, x) -> builder.clause(
45 dnf.call(x),
46 personView.call(x)
47 ));
48
49 var actual = sut.rewrite(query);
50
51 var expected = Query.of("Expected", (builder, x) -> builder.clause(
52 friendView.call(x, Variable.of()),
53 personView.call(x)
54 ));
55
56 assertThat(actual.getDnf(), structurallyEqualTo(expected.getDnf()));
57 }
58
59 @Test
60 void inlineSingleClauseWIthInputTest() {
61 var dnf = Dnf.of("SubQuery", builder -> {
62 var x = builder.parameter("x", ParameterDirection.IN);
63 builder.clause(not(friendView.call(x, Variable.of())));
64 });
65 var query = Query.of("Actual", (builder, x) -> builder.clause(
66 dnf.call(x),
67 personView.call(x)
68 ));
69
70 var actual = sut.rewrite(query);
71
72 var expected = Query.of("Expected", (builder, x) -> builder.clause(
73 personView.call(x),
74 not(friendView.call(x, Variable.of()))
75 ));
76
77 assertThat(actual.getDnf(), structurallyEqualTo(expected.getDnf()));
78 }
79
80 @Test
81 void singleLiteralDemandSetTest() {
82 var dnf = Dnf.of("SubQuery", builder -> {
83 var x = builder.parameter("x", ParameterDirection.IN);
84 builder.clause(not(friendView.call(x, Variable.of())));
85 builder.clause(not(friendView.call(Variable.of(), x)));
86 });
87 var query = Query.of("Actual", (builder, x) -> builder.clause(
88 dnf.call(x),
89 personView.call(x)
90 ));
91
92 var actual = sut.rewrite(query);
93
94 var expectedSubQuery = Dnf.of("ExpectedSubQuery", builder -> {
95 var x = builder.parameter("x", ParameterDirection.OUT);
96 builder.clause(
97 personView.call(x),
98 not(friendView.call(x, Variable.of()))
99 );
100 builder.clause(
101 personView.call(x),
102 not(friendView.call(Variable.of(), x))
103 );
104 });
105 var expected = Query.of("Expected", (builder, x) -> builder.clause(
106 personView.call(x),
107 expectedSubQuery.call(x)
108 ));
109
110 assertThat(actual.getDnf(), structurallyEqualTo(expected.getDnf()));
111 }
112
113 @Test
114 void multipleLiteralDemandSetTest() {
115 var dnf = Dnf.of("SubQuery", builder -> {
116 var x = builder.parameter("x", ParameterDirection.IN);
117 var y = builder.parameter("y", ParameterDirection.IN);
118 builder.clause(not(friendView.call(x, y)));
119 builder.clause(not(friendView.call(y, x)));
120 });
121 var query = Query.of("Actual", (builder, p1) -> builder.clause(p2 -> List.of(
122 not(dnf.call(p1, p2)),
123 personView.call(p1),
124 personView.call(p2)
125 )));
126
127 var actual = sut.rewrite(query);
128
129 var context = Dnf.of("Context", builder -> {
130 var x = builder.parameter("x", ParameterDirection.OUT);
131 var y = builder.parameter("y", ParameterDirection.OUT);
132 builder.clause(
133 personView.call(x),
134 personView.call(y)
135 );
136 });
137 var expectedSubQuery = Dnf.of("ExpectedSubQuery", builder -> {
138 var x = builder.parameter("x", ParameterDirection.OUT);
139 var y = builder.parameter("x", ParameterDirection.OUT);
140 builder.clause(
141 context.call(x, y),
142 not(friendView.call(x, y))
143 );
144 builder.clause(
145 context.call(x, y),
146 not(friendView.call(y, x))
147 );
148 });
149 var expected = Query.of("Expected", (builder, p1) -> builder.clause(p2 -> List.of(
150 context.call(p1, p2),
151 not(expectedSubQuery.call(p1, p2))
152 )));
153
154 assertThat(actual.getDnf(), structurallyEqualTo(expected.getDnf()));
155 }
156
157 @Test
158 void multipleParameterDemandSetTest() {
159 var dnf = Dnf.of("SubQuery", builder -> {
160 var x = builder.parameter("x", ParameterDirection.IN);
161 var y = builder.parameter("y", ParameterDirection.IN);
162 builder.clause(not(friendView.call(x, y)));
163 builder.clause(not(friendView.call(y, x)));
164 });
165 var query = Query.of("Actual", (builder, p1) -> builder.clause(
166 not(dnf.call(p1, p1)),
167 personView.call(p1)
168 ));
169
170 var actual = sut.rewrite(query);
171
172 var expectedSubQuery = Dnf.of("ExpectedSubQuery", builder -> {
173 var x = builder.parameter("x", ParameterDirection.OUT);
174 var y = builder.parameter("y", ParameterDirection.OUT);
175 builder.clause(
176 y.isEquivalent(x),
177 personView.call(x),
178 not(friendView.call(x, x))
179 );
180 });
181 var expected = Query.of("Expected", (builder, p1) -> builder.clause(
182 personView.call(p1),
183 not(expectedSubQuery.call(p1, p1))
184 ));
185
186 assertThat(actual.getDnf(), structurallyEqualTo(expected.getDnf()));
187 }
188
189 @Test
190 void eliminateDoubleNegationTest() {
191 var dnf = Dnf.of("SubQuery", builder -> {
192 var x = builder.parameter("x", ParameterDirection.IN);
193 builder.clause(not(friendView.call(x, Variable.of())));
194 });
195 var query = Query.of("Actual", (builder, p1) -> builder.clause(
196 personView.call(p1),
197 not(dnf.call(p1))
198 ));
199
200 var actual = sut.rewrite(query);
201
202 var expected = Query.of("Actual", (builder, p1) -> builder.clause(
203 personView.call(p1),
204 friendView.call(p1, Variable.of())
205 ));
206
207 assertThat(actual.getDnf(), structurallyEqualTo(expected.getDnf()));
208 }
209
210 @Test
211 void identityWhenNoWorkToDoTest() {
212 var dnf = Dnf.of("SubQuery", builder -> {
213 var x = builder.parameter("x", ParameterDirection.OUT);
214 builder.clause(
215 personView.call(x),
216 not(friendView.call(x, Variable.of()))
217 );
218 });
219 var query = Query.of("Actual", (builder, p1) -> builder.clause(
220 personView.call(p1),
221 not(dnf.call(p1))
222 ));
223
224 var actual = sut.rewrite(query);
225
226 assertThat(actual, is(query));
227 }
228}
diff --git a/subprojects/store-query/src/test/java/tools/refinery/store/query/term/TermSubstitutionTest.java b/subprojects/store-query/src/test/java/tools/refinery/store/query/term/TermSubstitutionTest.java
deleted file mode 100644
index 1fae2492..00000000
--- a/subprojects/store-query/src/test/java/tools/refinery/store/query/term/TermSubstitutionTest.java
+++ /dev/null
@@ -1,97 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.term;
7
8import org.junit.jupiter.api.Assertions;
9import org.junit.jupiter.params.ParameterizedTest;
10import org.junit.jupiter.params.provider.Arguments;
11import org.junit.jupiter.params.provider.MethodSource;
12import tools.refinery.store.query.equality.DnfEqualityChecker;
13import tools.refinery.store.query.equality.SubstitutingLiteralEqualityHelper;
14import tools.refinery.store.query.substitution.Substitution;
15import tools.refinery.store.query.term.bool.BoolTerms;
16import tools.refinery.store.query.term.int_.IntTerms;
17import tools.refinery.store.query.term.real.RealTerms;
18import tools.refinery.store.query.term.uppercardinality.UpperCardinalityTerms;
19import tools.refinery.store.representation.cardinality.UpperCardinality;
20
21import java.util.List;
22import java.util.stream.Stream;
23
24class TermSubstitutionTest {
25 private final static DataVariable<Integer> intA = Variable.of("intA", Integer.class);
26 private final static DataVariable<Integer> intB = Variable.of("intB", Integer.class);
27 private final static DataVariable<Double> realA = Variable.of("realA", Double.class);
28 private final static DataVariable<Double> realB = Variable.of("realB", Double.class);
29 private final static DataVariable<Boolean> boolA = Variable.of("boolA", Boolean.class);
30 private final static DataVariable<Boolean> boolB = Variable.of("boolB", Boolean.class);
31 private final static DataVariable<UpperCardinality> upperCardinalityA = Variable.of("upperCardinalityA",
32 UpperCardinality.class);
33 private final static DataVariable<UpperCardinality> upperCardinalityB = Variable.of("upperCardinalityB",
34 UpperCardinality.class);
35 private final static Substitution substitution = Substitution.builder()
36 .put(intA, intB)
37 .put(intB, intA)
38 .put(realA, realB)
39 .put(realB, realA)
40 .put(boolA, boolB)
41 .put(boolB, boolA)
42 .put(upperCardinalityA, upperCardinalityB)
43 .put(upperCardinalityB, upperCardinalityA)
44 .build();
45
46 @ParameterizedTest
47 @MethodSource
48 void substitutionTest(AnyTerm term) {
49 var substitutedTerm1 = term.substitute(substitution);
50 Assertions.assertNotEquals(term, substitutedTerm1, "Original term is not equal to substituted term");
51 var helper = new SubstitutingLiteralEqualityHelper(DnfEqualityChecker.DEFAULT, List.of(), List.of());
52 Assertions.assertTrue(term.equalsWithSubstitution(helper, substitutedTerm1), "Terms are equal by helper");
53 // The {@link #substitution} is its own inverse.
54 var substitutedTerm2 = substitutedTerm1.substitute(substitution);
55 Assertions.assertEquals(term, substitutedTerm2, "Original term is not equal to back-substituted term");
56 }
57
58 static Stream<Arguments> substitutionTest() {
59 return Stream.of(
60 Arguments.of(IntTerms.plus(intA)),
61 Arguments.of(IntTerms.minus(intA)),
62 Arguments.of(IntTerms.add(intA, intB)),
63 Arguments.of(IntTerms.sub(intA, intB)),
64 Arguments.of(IntTerms.mul(intA, intB)),
65 Arguments.of(IntTerms.div(intA, intB)),
66 Arguments.of(IntTerms.pow(intA, intB)),
67 Arguments.of(IntTerms.min(intA, intB)),
68 Arguments.of(IntTerms.max(intA, intB)),
69 Arguments.of(IntTerms.eq(intA, intB)),
70 Arguments.of(IntTerms.notEq(intA, intB)),
71 Arguments.of(IntTerms.less(intA, intB)),
72 Arguments.of(IntTerms.lessEq(intA, intB)),
73 Arguments.of(IntTerms.greater(intA, intB)),
74 Arguments.of(IntTerms.greaterEq(intA, intB)),
75 Arguments.of(IntTerms.asInt(realA)),
76 Arguments.of(RealTerms.plus(realA)),
77 Arguments.of(RealTerms.minus(realA)),
78 Arguments.of(RealTerms.add(realA, realB)),
79 Arguments.of(RealTerms.sub(realA, realB)),
80 Arguments.of(RealTerms.mul(realA, realB)),
81 Arguments.of(RealTerms.div(realA, realB)),
82 Arguments.of(RealTerms.pow(realA, realB)),
83 Arguments.of(RealTerms.min(realA, realB)),
84 Arguments.of(RealTerms.max(realA, realB)),
85 Arguments.of(RealTerms.asReal(intA)),
86 Arguments.of(BoolTerms.not(boolA)),
87 Arguments.of(BoolTerms.and(boolA, boolB)),
88 Arguments.of(BoolTerms.or(boolA, boolB)),
89 Arguments.of(BoolTerms.xor(boolA, boolB)),
90 Arguments.of(RealTerms.eq(realA, realB)),
91 Arguments.of(UpperCardinalityTerms.add(upperCardinalityA, upperCardinalityB)),
92 Arguments.of(UpperCardinalityTerms.mul(upperCardinalityA, upperCardinalityB)),
93 Arguments.of(UpperCardinalityTerms.min(upperCardinalityA, upperCardinalityB)),
94 Arguments.of(UpperCardinalityTerms.max(upperCardinalityA, upperCardinalityB))
95 );
96 }
97}
diff --git a/subprojects/store-query/src/test/java/tools/refinery/store/query/term/bool/BoolTermsEvaluateTest.java b/subprojects/store-query/src/test/java/tools/refinery/store/query/term/bool/BoolTermsEvaluateTest.java
deleted file mode 100644
index beff705e..00000000
--- a/subprojects/store-query/src/test/java/tools/refinery/store/query/term/bool/BoolTermsEvaluateTest.java
+++ /dev/null
@@ -1,75 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.term.bool;
7
8import org.junit.jupiter.params.ParameterizedTest;
9import org.junit.jupiter.params.provider.CsvSource;
10import tools.refinery.store.query.valuation.Valuation;
11
12import static org.hamcrest.MatcherAssert.assertThat;
13import static org.hamcrest.Matchers.is;
14
15class BoolTermsEvaluateTest {
16 @ParameterizedTest(name = "!{0} == {1}")
17 @CsvSource(value = {
18 "false, true",
19 "true, false",
20 "null, null"
21 }, nullValues = "null")
22 void notTest(Boolean a, Boolean result) {
23 var term = BoolTerms.not(BoolTerms.constant(a));
24 assertThat(term.getType(), is(Boolean.class));
25 assertThat(term.evaluate(Valuation.empty()), is(result));
26 }
27
28 @ParameterizedTest(name = "{0} && {1} == {2}")
29 @CsvSource(value = {
30 "false, false, false",
31 "false, true, false",
32 "true, false, false",
33 "true, true, true",
34 "false, null, null",
35 "null, false, null",
36 "null, null, null"
37 }, nullValues = "null")
38 void andTest(Boolean a, Boolean b, Boolean result) {
39 var term = BoolTerms.and(BoolTerms.constant(a), BoolTerms.constant(b));
40 assertThat(term.getType(), is(Boolean.class));
41 assertThat(term.evaluate(Valuation.empty()), is(result));
42 }
43
44 @ParameterizedTest(name = "{0} || {1} == {2}")
45 @CsvSource(value = {
46 "false, false, false",
47 "false, true, true",
48 "true, false, true",
49 "true, true, true",
50 "true, null, null",
51 "null, true, null",
52 "null, null, null"
53 }, nullValues = "null")
54 void orTest(Boolean a, Boolean b, Boolean result) {
55 var term = BoolTerms.or(BoolTerms.constant(a), BoolTerms.constant(b));
56 assertThat(term.getType(), is(Boolean.class));
57 assertThat(term.evaluate(Valuation.empty()), is(result));
58 }
59
60 @ParameterizedTest(name = "{0} ^^ {1} == {2}")
61 @CsvSource(value = {
62 "false, false, false",
63 "false, true, true",
64 "true, false, true",
65 "true, true, false",
66 "false, null, null",
67 "null, false, null",
68 "null, null, null"
69 }, nullValues = "null")
70 void xorTest(Boolean a, Boolean b, Boolean result) {
71 var term = BoolTerms.xor(BoolTerms.constant(a), BoolTerms.constant(b));
72 assertThat(term.getType(), is(Boolean.class));
73 assertThat(term.evaluate(Valuation.empty()), is(result));
74 }
75}
diff --git a/subprojects/store-query/src/test/java/tools/refinery/store/query/term/int_/IntTermsEvaluateTest.java b/subprojects/store-query/src/test/java/tools/refinery/store/query/term/int_/IntTermsEvaluateTest.java
deleted file mode 100644
index abe50d75..00000000
--- a/subprojects/store-query/src/test/java/tools/refinery/store/query/term/int_/IntTermsEvaluateTest.java
+++ /dev/null
@@ -1,259 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.term.int_;
7
8import org.junit.jupiter.params.ParameterizedTest;
9import org.junit.jupiter.params.provider.Arguments;
10import org.junit.jupiter.params.provider.CsvSource;
11import org.junit.jupiter.params.provider.MethodSource;
12import tools.refinery.store.query.term.real.RealTerms;
13import tools.refinery.store.query.valuation.Valuation;
14
15import java.util.stream.Stream;
16
17import static org.hamcrest.Matchers.is;
18import static org.hamcrest.MatcherAssert.assertThat;
19
20class IntTermsEvaluateTest {
21 @ParameterizedTest(name = "+{0} == {1}")
22 @CsvSource(value = {
23 "2, 2",
24 "null, null"
25 }, nullValues = "null")
26 void plusTest(Integer a, Integer result) {
27 var term = IntTerms.plus(IntTerms.constant(a));
28 assertThat(term.getType(), is(Integer.class));
29 assertThat(term.evaluate(Valuation.empty()), is(result));
30 }
31
32 @ParameterizedTest(name = "-{0} == {1}")
33 @CsvSource(value = {
34 "2, -2",
35 "null, null"
36 }, nullValues = "null")
37 void minusTest(Integer a, Integer result) {
38 var term = IntTerms.minus(IntTerms.constant(a));
39 assertThat(term.getType(), is(Integer.class));
40 assertThat(term.evaluate(Valuation.empty()), is(result));
41 }
42
43 @ParameterizedTest(name = "{0} + {1} == {2}")
44 @CsvSource(value = {
45 "1, 2, 3",
46 "null, 2, null",
47 "1, null, null",
48 "null, null, null"
49 }, nullValues = "null")
50 void addTest(Integer a, Integer b, Integer result) {
51 var term = IntTerms.add(IntTerms.constant(a), IntTerms.constant(b));
52 assertThat(term.getType(), is(Integer.class));
53 assertThat(term.evaluate(Valuation.empty()), is(result));
54 }
55
56 @ParameterizedTest(name = "{0} - {1} == {2}")
57 @CsvSource(value = {
58 "1, 3, -2",
59 "null, 3, null",
60 "1, null, null",
61 "null, null, null"
62 }, nullValues = "null")
63 void subTest(Integer a, Integer b, Integer result) {
64 var term = IntTerms.sub(IntTerms.constant(a), IntTerms.constant(b));
65 assertThat(term.getType(), is(Integer.class));
66 assertThat(term.evaluate(Valuation.empty()), is(result));
67 }
68
69 @ParameterizedTest(name = "{0} * {1} == {2}")
70 @CsvSource(value = {
71 "2, 3, 6",
72 "null, 3, null",
73 "2, null, null",
74 "null, null, null"
75 }, nullValues = "null")
76 void mulTest(Integer a, Integer b, Integer result) {
77 var term = IntTerms.mul(IntTerms.constant(a), IntTerms.constant(b));
78 assertThat(term.getType(), is(Integer.class));
79 assertThat(term.evaluate(Valuation.empty()), is(result));
80 }
81
82 @ParameterizedTest(name = "{0} * {1} == {2}")
83 @CsvSource(value = {
84 "6, 3, 2",
85 "7, 3, 2",
86 "6, 0, null",
87 "null, 3, null",
88 "6, null, null",
89 "null, null, null"
90 }, nullValues = "null")
91 void divTest(Integer a, Integer b, Integer result) {
92 var term = IntTerms.div(IntTerms.constant(a), IntTerms.constant(b));
93 assertThat(term.getType(), is(Integer.class));
94 assertThat(term.evaluate(Valuation.empty()), is(result));
95 }
96
97 @ParameterizedTest(name = "{0} ** {1} == {2}")
98 @CsvSource(value = {
99 "1, 0, 1",
100 "1, 3, 1",
101 "1, -3, null",
102 "2, 0, 1",
103 "2, 2, 4",
104 "2, 3, 8",
105 "2, 4, 16",
106 "2, 5, 32",
107 "2, 6, 64",
108 "2, -3, null",
109 "null, 3, null",
110 "2, null, null",
111 "null, null, null"
112 }, nullValues = "null")
113 void powTest(Integer a, Integer b, Integer result) {
114 var term = IntTerms.pow(IntTerms.constant(a), IntTerms.constant(b));
115 assertThat(term.getType(), is(Integer.class));
116 assertThat(term.evaluate(Valuation.empty()), is(result));
117 }
118
119 @ParameterizedTest(name = "min({0}, {1}) == {2}")
120 @CsvSource(value = {
121 "1, 2, 1",
122 "2, 1, 1",
123 "null, 2, null",
124 "1, null, null",
125 "null, null, null"
126 }, nullValues = "null")
127 void minTest(Integer a, Integer b, Integer result) {
128 var term = IntTerms.min(IntTerms.constant(a), IntTerms.constant(b));
129 assertThat(term.getType(), is(Integer.class));
130 assertThat(term.evaluate(Valuation.empty()), is(result));
131 }
132
133 @ParameterizedTest(name = "max({0}, {1}) == {2}")
134 @CsvSource(value = {
135 "1, 2, 2",
136 "2, 1, 2",
137 "null, 2, null",
138 "1, null, null",
139 "null, null, null"
140 }, nullValues = "null")
141 void maxTest(Integer a, Integer b, Integer result) {
142 var term = IntTerms.max(IntTerms.constant(a), IntTerms.constant(b));
143 assertThat(term.getType(), is(Integer.class));
144 assertThat(term.evaluate(Valuation.empty()), is(result));
145 }
146
147 @ParameterizedTest(name = "({0} == {1}) == {2}")
148 @CsvSource(value = {
149 "1, 1, true",
150 "1, 2, false",
151 "null, 1, null",
152 "1, null, null",
153 "null, null, null"
154 }, nullValues = "null")
155 void eqTest(Integer a, Integer b, Boolean result) {
156 var term = IntTerms.eq(IntTerms.constant(a), IntTerms.constant(b));
157 assertThat(term.getType(), is(Boolean.class));
158 assertThat(term.evaluate(Valuation.empty()), is(result));
159 }
160
161 @ParameterizedTest(name = "({0} != {1}) == {2}")
162 @CsvSource(value = {
163 "1, 1, false",
164 "1, 2, true",
165 "null, 1, null",
166 "1, null, null",
167 "null, null, null"
168 }, nullValues = "null")
169 void notEqTest(Integer a, Integer b, Boolean result) {
170 var term = IntTerms.notEq(IntTerms.constant(a), IntTerms.constant(b));
171 assertThat(term.getType(), is(Boolean.class));
172 assertThat(term.evaluate(Valuation.empty()), is(result));
173 }
174
175 @ParameterizedTest(name = "({0} < {1}) == {2}")
176 @CsvSource(value = {
177 "1, -2, false",
178 "1, 1, false",
179 "1, 2, true",
180 "null, 1, null",
181 "1, null, null",
182 "null, null, null"
183 }, nullValues = "null")
184 void lessTest(Integer a, Integer b, Boolean result) {
185 var term = IntTerms.less(IntTerms.constant(a), IntTerms.constant(b));
186 assertThat(term.getType(), is(Boolean.class));
187 assertThat(term.evaluate(Valuation.empty()), is(result));
188 }
189
190 @ParameterizedTest(name = "({0} <= {1}) == {2}")
191 @CsvSource(value = {
192 "1, -2, false",
193 "1, 1, true",
194 "1, 2, true",
195 "null, 1, null",
196 "1, null, null",
197 "null, null, null"
198 }, nullValues = "null")
199 void lessEqTest(Integer a, Integer b, Boolean result) {
200 var term = IntTerms.lessEq(IntTerms.constant(a), IntTerms.constant(b));
201 assertThat(term.getType(), is(Boolean.class));
202 assertThat(term.evaluate(Valuation.empty()), is(result));
203 }
204
205 @ParameterizedTest(name = "({0} > {1}) == {2}")
206 @CsvSource(value = {
207 "1, -2, true",
208 "1, 1, false",
209 "1, 2, false",
210 "null, 1, null",
211 "1, null, null",
212 "null, null, null"
213 }, nullValues = "null")
214 void greaterTest(Integer a, Integer b, Boolean result) {
215 var term = IntTerms.greater(IntTerms.constant(a), IntTerms.constant(b));
216 assertThat(term.getType(), is(Boolean.class));
217 assertThat(term.evaluate(Valuation.empty()), is(result));
218 }
219
220 @ParameterizedTest(name = "({0} >= {1}) == {2}")
221 @CsvSource(value = {
222 "1, -2, true",
223 "1, 1, true",
224 "1, 2, false",
225 "null, 1, null",
226 "1, null, null",
227 "null, null, null"
228 }, nullValues = "null")
229 void greaterEqTest(Integer a, Integer b, Boolean result) {
230 var term = IntTerms.greaterEq(IntTerms.constant(a), IntTerms.constant(b));
231 assertThat(term.getType(), is(Boolean.class));
232 assertThat(term.evaluate(Valuation.empty()), is(result));
233 }
234
235 @ParameterizedTest(name = "{0} as int == {1}")
236 @MethodSource
237 void asIntTest(Double a, Integer result) {
238 var term = IntTerms.asInt(RealTerms.constant(a));
239 assertThat(term.getType(), is(Integer.class));
240 assertThat(term.evaluate(Valuation.empty()), is(result));
241 }
242
243 static Stream<Arguments> asIntTest() {
244 return Stream.of(
245 Arguments.of(2.0, 2),
246 Arguments.of(2.1, 2),
247 Arguments.of(2.9, 2),
248 Arguments.of(-2.0, -2),
249 Arguments.of(-2.1, -2),
250 Arguments.of(-2.9, -2),
251 Arguments.of(0.0, 0),
252 Arguments.of(-0.0, 0),
253 Arguments.of(Double.POSITIVE_INFINITY, Integer.MAX_VALUE),
254 Arguments.of(Double.NEGATIVE_INFINITY, Integer.MIN_VALUE),
255 Arguments.of(Double.NaN, null),
256 Arguments.of(null, null)
257 );
258 }
259}
diff --git a/subprojects/store-query/src/test/java/tools/refinery/store/query/term/real/RealTermEvaluateTest.java b/subprojects/store-query/src/test/java/tools/refinery/store/query/term/real/RealTermEvaluateTest.java
deleted file mode 100644
index 6a8eebf1..00000000
--- a/subprojects/store-query/src/test/java/tools/refinery/store/query/term/real/RealTermEvaluateTest.java
+++ /dev/null
@@ -1,238 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.term.real;
7
8import org.hamcrest.Matcher;
9import org.junit.jupiter.params.ParameterizedTest;
10import org.junit.jupiter.params.provider.CsvSource;
11import tools.refinery.store.query.term.int_.IntTerms;
12import tools.refinery.store.query.valuation.Valuation;
13
14import static org.hamcrest.MatcherAssert.assertThat;
15import static org.hamcrest.Matchers.*;
16
17class RealTermEvaluateTest {
18 public static final double TOLERANCE = 1e-6;
19
20 private static Matcher<Double> closeToOrNull(Double expected) {
21 return expected == null ? nullValue(Double.class) : closeTo(expected, TOLERANCE);
22 }
23
24 @ParameterizedTest(name = "+{0} == {1}")
25 @CsvSource(value = {
26 "2.5, 2.5",
27 "null, null"
28 }, nullValues = "null")
29 void plusTest(Double a, Double result) {
30 var term = RealTerms.plus(RealTerms.constant(a));
31 assertThat(term.getType(), is(Double.class));
32 assertThat(term.evaluate(Valuation.empty()), closeToOrNull(result));
33 }
34
35 @ParameterizedTest(name = "-{0} == {1}")
36 @CsvSource(value = {
37 "2.5, -2.5",
38 "null, null"
39 }, nullValues = "null")
40 void minusTest(Double a, Double result) {
41 var term = RealTerms.minus(RealTerms.constant(a));
42 assertThat(term.getType(), is(Double.class));
43 assertThat(term.evaluate(Valuation.empty()), closeToOrNull(result));
44 }
45
46 @ParameterizedTest(name = "{0} + {1} == {2}")
47 @CsvSource(value = {
48 "1.2, 2.3, 3.5",
49 "null, 2.3, null",
50 "1.2, null, null",
51 "null, null, null"
52 }, nullValues = "null")
53 void addTest(Double a, Double b, Double result) {
54 var term = RealTerms.add(RealTerms.constant(a), RealTerms.constant(b));
55 assertThat(term.getType(), is(Double.class));
56 assertThat(term.evaluate(Valuation.empty()), closeToOrNull(result));
57 }
58
59 @ParameterizedTest(name = "{0} - {1} == {2}")
60 @CsvSource(value = {
61 "1.2, 3.4, -2.2",
62 "null, 3.4, null",
63 "1.2, null, null",
64 "null, null, null"
65 }, nullValues = "null")
66 void subTest(Double a, Double b, Double result) {
67 var term = RealTerms.sub(RealTerms.constant(a), RealTerms.constant(b));
68 assertThat(term.getType(), is(Double.class));
69 assertThat(term.evaluate(Valuation.empty()), closeToOrNull(result));
70 }
71
72 @ParameterizedTest(name = "{0} * {1} == {2}")
73 @CsvSource(value = {
74 "2.3, 3.4, 7.82",
75 "null, 3.4, null",
76 "2.3, null, null",
77 "null, null, null"
78 }, nullValues = "null")
79 void mulTest(Double a, Double b, Double result) {
80 var term = RealTerms.mul(RealTerms.constant(a), RealTerms.constant(b));
81 assertThat(term.getType(), is(Double.class));
82 assertThat(term.evaluate(Valuation.empty()), closeToOrNull(result));
83 }
84
85 @ParameterizedTest(name = "{0} * {1} == {2}")
86 @CsvSource(value = {
87 "7.82, 3.4, 2.3",
88 "null, 3.4, null",
89 "7.82, null, null",
90 "null, null, null"
91 }, nullValues = "null")
92 void divTest(Double a, Double b, Double result) {
93 var term = RealTerms.div(RealTerms.constant(a), RealTerms.constant(b));
94 assertThat(term.getType(), is(Double.class));
95 assertThat(term.evaluate(Valuation.empty()), closeToOrNull(result));
96 }
97
98 @ParameterizedTest(name = "{0} ** {1} == {2}")
99 @CsvSource(value = {
100 "2.0, 6.0, 64.0",
101 "null, 6.0, null",
102 "2.0, null, null",
103 "null, null, null"
104 }, nullValues = "null")
105 void powTest(Double a, Double b, Double result) {
106 var term = RealTerms.pow(RealTerms.constant(a), RealTerms.constant(b));
107 assertThat(term.getType(), is(Double.class));
108 assertThat(term.evaluate(Valuation.empty()), closeToOrNull(result));
109 }
110
111 @ParameterizedTest(name = "min({0}, {1}) == {2}")
112 @CsvSource(value = {
113 "1.5, 2.7, 1.5",
114 "2.7, 1.5, 1.5",
115 "null, 2.7, null",
116 "1.5, null, null",
117 "null, null, null"
118 }, nullValues = "null")
119 void minTest(Double a, Double b, Double result) {
120 var term = RealTerms.min(RealTerms.constant(a), RealTerms.constant(b));
121 assertThat(term.getType(), is(Double.class));
122 assertThat(term.evaluate(Valuation.empty()), closeToOrNull(result));
123 }
124
125 @ParameterizedTest(name = "max({0}, {1}) == {2}")
126 @CsvSource(value = {
127 "1.5, 2.7, 2.7",
128 "2.7, 1.7, 2.7",
129 "null, 2.7, null",
130 "1.5, null, null",
131 "null, null, null"
132 }, nullValues = "null")
133 void maxTest(Double a, Double b, Double result) {
134 var term = RealTerms.max(RealTerms.constant(a), RealTerms.constant(b));
135 assertThat(term.getType(), is(Double.class));
136 assertThat(term.evaluate(Valuation.empty()), closeToOrNull(result));
137 }
138
139 @ParameterizedTest(name = "({0} == {1}) == {2}")
140 @CsvSource(value = {
141 "1.5, 1.5, true",
142 "1.5, 2.7, false",
143 "null, 1.5, null",
144 "1.5, null, null",
145 "null, null, null"
146 }, nullValues = "null")
147 void eqTest(Double a, Double b, Boolean result) {
148 var term = RealTerms.eq(RealTerms.constant(a), RealTerms.constant(b));
149 assertThat(term.getType(), is(Boolean.class));
150 assertThat(term.evaluate(Valuation.empty()), is(result));
151 }
152
153 @ParameterizedTest(name = "({0} != {1}) == {2}")
154 @CsvSource(value = {
155 "1.5, 1.5, false",
156 "1.5, 2.7, true",
157 "null, 1.5, null",
158 "1.5, null, null",
159 "null, null, null"
160 }, nullValues = "null")
161 void notEqTest(Double a, Double b, Boolean result) {
162 var term = RealTerms.notEq(RealTerms.constant(a), RealTerms.constant(b));
163 assertThat(term.getType(), is(Boolean.class));
164 assertThat(term.evaluate(Valuation.empty()), is(result));
165 }
166
167 @ParameterizedTest(name = "({0} < {1}) == {2}")
168 @CsvSource(value = {
169 "1.5, -2.7, false",
170 "1.5, 1.5, false",
171 "1.5, 2.7, true",
172 "null, 1.5, null",
173 "1.5, null, null",
174 "null, null, null"
175 }, nullValues = "null")
176 void lessTest(Double a, Double b, Boolean result) {
177 var term = RealTerms.less(RealTerms.constant(a), RealTerms.constant(b));
178 assertThat(term.getType(), is(Boolean.class));
179 assertThat(term.evaluate(Valuation.empty()), is(result));
180 }
181
182 @ParameterizedTest(name = "({0} <= {1}) == {2}")
183 @CsvSource(value = {
184 "1.5, -2.7, false",
185 "1.5, 1.5, true",
186 "1.5, 2.7, true",
187 "null, 1.5, null",
188 "1.5, null, null",
189 "null, null, null"
190 }, nullValues = "null")
191 void lessEqTest(Double a, Double b, Boolean result) {
192 var term = RealTerms.lessEq(RealTerms.constant(a), RealTerms.constant(b));
193 assertThat(term.getType(), is(Boolean.class));
194 assertThat(term.evaluate(Valuation.empty()), is(result));
195 }
196
197 @ParameterizedTest(name = "({0} > {1}) == {2}")
198 @CsvSource(value = {
199 "1.5, -2.7, true",
200 "1.5, 1.5, false",
201 "1.5, 2.7, false",
202 "null, 1.5, null",
203 "1.5, null, null",
204 "null, null, null"
205 }, nullValues = "null")
206 void greaterTest(Double a, Double b, Boolean result) {
207 var term = RealTerms.greater(RealTerms.constant(a), RealTerms.constant(b));
208 assertThat(term.getType(), is(Boolean.class));
209 assertThat(term.evaluate(Valuation.empty()), is(result));
210 }
211
212 @ParameterizedTest(name = "({0} >= {1}) == {2}")
213 @CsvSource(value = {
214 "1.5, -2.7, true",
215 "1.5, 1.5, true",
216 "1.5, 2.7, false",
217 "null, 1.5, null",
218 "1.5, null, null",
219 "null, null, null"
220 }, nullValues = "null")
221 void greaterEqTest(Double a, Double b, Boolean result) {
222 var term = RealTerms.greaterEq(RealTerms.constant(a), RealTerms.constant(b));
223 assertThat(term.getType(), is(Boolean.class));
224 assertThat(term.evaluate(Valuation.empty()), is(result));
225 }
226
227 @ParameterizedTest(name = "{0} as real == {1}")
228 @CsvSource(value = {
229 "0, 0.0",
230 "5, 5.0",
231 "null, null"
232 }, nullValues = "null")
233 void asRealTest(Integer a, Double result) {
234 var term = RealTerms.asReal(IntTerms.constant(a));
235 assertThat(term.getType(), is(Double.class));
236 assertThat(term.evaluate(Valuation.empty()), closeToOrNull(result));
237 }
238}
diff --git a/subprojects/store-query/src/test/java/tools/refinery/store/query/term/uppercardinality/UpperCardinalitySumAggregatorStreamTest.java b/subprojects/store-query/src/test/java/tools/refinery/store/query/term/uppercardinality/UpperCardinalitySumAggregatorStreamTest.java
deleted file mode 100644
index 31baf36e..00000000
--- a/subprojects/store-query/src/test/java/tools/refinery/store/query/term/uppercardinality/UpperCardinalitySumAggregatorStreamTest.java
+++ /dev/null
@@ -1,56 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.term.uppercardinality;
7
8import org.junit.jupiter.params.ParameterizedTest;
9import org.junit.jupiter.params.provider.Arguments;
10import org.junit.jupiter.params.provider.MethodSource;
11import tools.refinery.store.representation.cardinality.UpperCardinalities;
12import tools.refinery.store.representation.cardinality.UpperCardinality;
13
14import java.util.List;
15import java.util.stream.Stream;
16
17import static org.hamcrest.MatcherAssert.assertThat;
18import static org.hamcrest.Matchers.is;
19
20class UpperCardinalitySumAggregatorStreamTest {
21 @ParameterizedTest
22 @MethodSource
23 void testStream(List<UpperCardinality> list, UpperCardinality expected) {
24 var result = UpperCardinalitySumAggregator.INSTANCE.aggregateStream(list.stream());
25 assertThat(result, is(expected));
26 }
27
28 static Stream<Arguments> testStream() {
29 return Stream.of(
30 Arguments.of(List.of(), UpperCardinalities.ZERO),
31 Arguments.of(List.of(UpperCardinality.of(3)), UpperCardinality.of(3)),
32 Arguments.of(
33 List.of(
34 UpperCardinality.of(2),
35 UpperCardinality.of(3)
36 ),
37 UpperCardinality.of(5)
38 ),
39 Arguments.of(List.of(UpperCardinalities.UNBOUNDED), UpperCardinalities.UNBOUNDED),
40 Arguments.of(
41 List.of(
42 UpperCardinalities.UNBOUNDED,
43 UpperCardinalities.UNBOUNDED
44 ),
45 UpperCardinalities.UNBOUNDED
46 ),
47 Arguments.of(
48 List.of(
49 UpperCardinalities.UNBOUNDED,
50 UpperCardinality.of(3)
51 ),
52 UpperCardinalities.UNBOUNDED
53 )
54 );
55 }
56}
diff --git a/subprojects/store-query/src/test/java/tools/refinery/store/query/term/uppercardinality/UpperCardinalitySumAggregatorTest.java b/subprojects/store-query/src/test/java/tools/refinery/store/query/term/uppercardinality/UpperCardinalitySumAggregatorTest.java
deleted file mode 100644
index 780cd0ab..00000000
--- a/subprojects/store-query/src/test/java/tools/refinery/store/query/term/uppercardinality/UpperCardinalitySumAggregatorTest.java
+++ /dev/null
@@ -1,80 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.term.uppercardinality;
7
8import org.junit.jupiter.api.BeforeEach;
9import org.junit.jupiter.api.Test;
10import tools.refinery.store.query.term.StatefulAggregate;
11import tools.refinery.store.representation.cardinality.UpperCardinalities;
12import tools.refinery.store.representation.cardinality.UpperCardinality;
13
14import static org.hamcrest.MatcherAssert.assertThat;
15import static org.hamcrest.Matchers.is;
16
17class UpperCardinalitySumAggregatorTest {
18 private StatefulAggregate<UpperCardinality, UpperCardinality> accumulator;
19
20 @BeforeEach
21 void beforeEach() {
22 accumulator = UpperCardinalitySumAggregator.INSTANCE.createEmptyAggregate();
23 }
24
25 @Test
26 void emptyAggregationTest() {
27 assertThat(accumulator.getResult(), is(UpperCardinality.of(0)));
28 }
29
30 @Test
31 void singleBoundedTest() {
32 accumulator.add(UpperCardinality.of(3));
33 assertThat(accumulator.getResult(), is(UpperCardinality.of(3)));
34 }
35
36 @Test
37 void multipleBoundedTest() {
38 accumulator.add(UpperCardinality.of(2));
39 accumulator.add(UpperCardinality.of(3));
40 assertThat(accumulator.getResult(), is(UpperCardinality.of(5)));
41 }
42
43 @Test
44 void singleUnboundedTest() {
45 accumulator.add(UpperCardinalities.UNBOUNDED);
46 assertThat(accumulator.getResult(), is(UpperCardinalities.UNBOUNDED));
47 }
48
49 @Test
50 void multipleUnboundedTest() {
51 accumulator.add(UpperCardinalities.UNBOUNDED);
52 accumulator.add(UpperCardinalities.UNBOUNDED);
53 assertThat(accumulator.getResult(), is(UpperCardinalities.UNBOUNDED));
54 }
55
56 @Test
57 void removeBoundedTest() {
58 accumulator.add(UpperCardinality.of(2));
59 accumulator.add(UpperCardinality.of(3));
60 accumulator.remove(UpperCardinality.of(2));
61 assertThat(accumulator.getResult(), is(UpperCardinality.of(3)));
62 }
63
64 @Test
65 void removeAllUnboundedTest() {
66 accumulator.add(UpperCardinalities.UNBOUNDED);
67 accumulator.add(UpperCardinality.of(3));
68 accumulator.remove(UpperCardinalities.UNBOUNDED);
69 assertThat(accumulator.getResult(), is(UpperCardinality.of(3)));
70 }
71
72 @Test
73 void removeSomeUnboundedTest() {
74 accumulator.add(UpperCardinalities.UNBOUNDED);
75 accumulator.add(UpperCardinalities.UNBOUNDED);
76 accumulator.add(UpperCardinality.of(3));
77 accumulator.remove(UpperCardinalities.UNBOUNDED);
78 assertThat(accumulator.getResult(), is(UpperCardinalities.UNBOUNDED));
79 }
80}
diff --git a/subprojects/store-query/src/test/java/tools/refinery/store/query/term/uppercardinality/UpperCardinalityTermsEvaluateTest.java b/subprojects/store-query/src/test/java/tools/refinery/store/query/term/uppercardinality/UpperCardinalityTermsEvaluateTest.java
deleted file mode 100644
index 9d0f3bde..00000000
--- a/subprojects/store-query/src/test/java/tools/refinery/store/query/term/uppercardinality/UpperCardinalityTermsEvaluateTest.java
+++ /dev/null
@@ -1,104 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.term.uppercardinality;
7
8import org.junit.jupiter.params.ParameterizedTest;
9import org.junit.jupiter.params.provider.Arguments;
10import org.junit.jupiter.params.provider.MethodSource;
11import tools.refinery.store.query.valuation.Valuation;
12import tools.refinery.store.representation.cardinality.UpperCardinalities;
13import tools.refinery.store.representation.cardinality.UpperCardinality;
14
15import java.util.stream.Stream;
16
17import static org.hamcrest.MatcherAssert.assertThat;
18import static org.hamcrest.Matchers.is;
19
20class UpperCardinalityTermsEvaluateTest {
21 @ParameterizedTest(name = "min({0}, {1}) == {2}")
22 @MethodSource
23 void minTest(UpperCardinality a, UpperCardinality b, UpperCardinality expected) {
24 var term = UpperCardinalityTerms.min(UpperCardinalityTerms.constant(a), UpperCardinalityTerms.constant(b));
25 assertThat(term.getType(), is(UpperCardinality.class));
26 assertThat(term.evaluate(Valuation.empty()), is(expected));
27 }
28
29 static Stream<Arguments> minTest() {
30 return Stream.of(
31 Arguments.of(UpperCardinality.of(0), UpperCardinality.of(0), UpperCardinality.of(0)),
32 Arguments.of(UpperCardinality.of(0), UpperCardinality.of(1), UpperCardinality.of(0)),
33 Arguments.of(UpperCardinality.of(1), UpperCardinality.of(0), UpperCardinality.of(0)),
34 Arguments.of(UpperCardinality.of(0), UpperCardinalities.UNBOUNDED, UpperCardinality.of(0)),
35 Arguments.of(UpperCardinalities.UNBOUNDED, UpperCardinality.of(0), UpperCardinality.of(0)),
36 Arguments.of(UpperCardinalities.UNBOUNDED, UpperCardinalities.UNBOUNDED, UpperCardinalities.UNBOUNDED),
37 Arguments.of(UpperCardinality.of(1), null, null),
38 Arguments.of(null, UpperCardinality.of(1), null),
39 Arguments.of(null, null, null)
40 );
41 }
42
43 @ParameterizedTest(name = "max({0}, {1}) == {2}")
44 @MethodSource
45 void maxTest(UpperCardinality a, UpperCardinality b, UpperCardinality expected) {
46 var term = UpperCardinalityTerms.max(UpperCardinalityTerms.constant(a), UpperCardinalityTerms.constant(b));
47 assertThat(term.getType(), is(UpperCardinality.class));
48 assertThat(term.evaluate(Valuation.empty()), is(expected));
49 }
50
51 static Stream<Arguments> maxTest() {
52 return Stream.of(
53 Arguments.of(UpperCardinality.of(0), UpperCardinality.of(0), UpperCardinality.of(0)),
54 Arguments.of(UpperCardinality.of(0), UpperCardinality.of(1), UpperCardinality.of(1)),
55 Arguments.of(UpperCardinality.of(1), UpperCardinality.of(0), UpperCardinality.of(1)),
56 Arguments.of(UpperCardinality.of(0), UpperCardinalities.UNBOUNDED, UpperCardinalities.UNBOUNDED),
57 Arguments.of(UpperCardinalities.UNBOUNDED, UpperCardinality.of(0), UpperCardinalities.UNBOUNDED),
58 Arguments.of(UpperCardinalities.UNBOUNDED, UpperCardinalities.UNBOUNDED, UpperCardinalities.UNBOUNDED),
59 Arguments.of(UpperCardinality.of(1), null, null),
60 Arguments.of(null, UpperCardinality.of(1), null),
61 Arguments.of(null, null, null)
62 );
63 }
64
65 @ParameterizedTest(name = "{0} + {1} == {2}")
66 @MethodSource
67 void addTest(UpperCardinality a, UpperCardinality b, UpperCardinality expected) {
68 var term = UpperCardinalityTerms.add(UpperCardinalityTerms.constant(a), UpperCardinalityTerms.constant(b));
69 assertThat(term.getType(), is(UpperCardinality.class));
70 assertThat(term.evaluate(Valuation.empty()), is(expected));
71 }
72
73 static Stream<Arguments> addTest() {
74 return Stream.of(
75 Arguments.of(UpperCardinality.of(2), UpperCardinality.of(3), UpperCardinality.of(5)),
76 Arguments.of(UpperCardinality.of(2), UpperCardinalities.UNBOUNDED, UpperCardinalities.UNBOUNDED),
77 Arguments.of(UpperCardinalities.UNBOUNDED, UpperCardinality.of(2), UpperCardinalities.UNBOUNDED),
78 Arguments.of(UpperCardinalities.UNBOUNDED, UpperCardinalities.UNBOUNDED, UpperCardinalities.UNBOUNDED),
79 Arguments.of(UpperCardinality.of(1), null, null),
80 Arguments.of(null, UpperCardinality.of(1), null),
81 Arguments.of(null, null, null)
82 );
83 }
84
85 @ParameterizedTest(name = "{0} * {1} == {2}")
86 @MethodSource
87 void mulTest(UpperCardinality a, UpperCardinality b, UpperCardinality expected) {
88 var term = UpperCardinalityTerms.mul(UpperCardinalityTerms.constant(a), UpperCardinalityTerms.constant(b));
89 assertThat(term.getType(), is(UpperCardinality.class));
90 assertThat(term.evaluate(Valuation.empty()), is(expected));
91 }
92
93 static Stream<Arguments> mulTest() {
94 return Stream.of(
95 Arguments.of(UpperCardinality.of(2), UpperCardinality.of(3), UpperCardinality.of(6)),
96 Arguments.of(UpperCardinality.of(2), UpperCardinalities.UNBOUNDED, UpperCardinalities.UNBOUNDED),
97 Arguments.of(UpperCardinalities.UNBOUNDED, UpperCardinality.of(2), UpperCardinalities.UNBOUNDED),
98 Arguments.of(UpperCardinalities.UNBOUNDED, UpperCardinalities.UNBOUNDED, UpperCardinalities.UNBOUNDED),
99 Arguments.of(UpperCardinality.of(1), null, null),
100 Arguments.of(null, UpperCardinality.of(1), null),
101 Arguments.of(null, null, null)
102 );
103 }
104}
diff --git a/subprojects/store-query/src/test/java/tools/refinery/store/query/tests/StructurallyEqualToRawTest.java b/subprojects/store-query/src/test/java/tools/refinery/store/query/tests/StructurallyEqualToRawTest.java
deleted file mode 100644
index d447e99c..00000000
--- a/subprojects/store-query/src/test/java/tools/refinery/store/query/tests/StructurallyEqualToRawTest.java
+++ /dev/null
@@ -1,159 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.tests;
7
8import org.junit.jupiter.api.Test;
9import tools.refinery.store.query.dnf.Dnf;
10import tools.refinery.store.query.dnf.SymbolicParameter;
11import tools.refinery.store.query.term.NodeVariable;
12import tools.refinery.store.query.term.ParameterDirection;
13import tools.refinery.store.query.term.Variable;
14import tools.refinery.store.query.view.AnySymbolView;
15import tools.refinery.store.query.view.KeyOnlyView;
16import tools.refinery.store.representation.Symbol;
17
18import java.util.List;
19
20import static org.hamcrest.CoreMatchers.containsString;
21import static org.hamcrest.MatcherAssert.assertThat;
22import static org.hamcrest.Matchers.allOf;
23import static org.junit.jupiter.api.Assertions.assertThrows;
24import static tools.refinery.store.query.tests.QueryMatchers.structurallyEqualTo;
25
26class StructurallyEqualToRawTest {
27 private static final Symbol<Boolean> person = Symbol.of("Person", 1);
28 private static final Symbol<Boolean> friend = Symbol.of("friend", 2);
29 private static final AnySymbolView personView = new KeyOnlyView<>(person);
30 private static final AnySymbolView friendView = new KeyOnlyView<>(friend);
31 private static final NodeVariable p = Variable.of("p");
32 private static final NodeVariable q = Variable.of("q");
33
34 @Test
35 void flatEqualsTest() {
36 var actual = Dnf.builder("Actual").parameters(p).clause(personView.call(p)).build();
37
38 assertThat(actual, structurallyEqualTo(
39 List.of(new SymbolicParameter(q, ParameterDirection.OUT)),
40 List.of(List.of(personView.call(q)))
41 ));
42 }
43
44 @Test
45 void flatNotEqualsTest() {
46 var actual = Dnf.builder("Actual").parameters(p).clause(friendView.call(p, q)).build();
47
48 var assertion = structurallyEqualTo(
49 List.of(new SymbolicParameter(q, ParameterDirection.OUT)),
50 List.of(List.of(friendView.call(q, q)))
51 );
52 assertThrows(AssertionError.class, () -> assertThat(actual, assertion));
53 }
54
55 @Test
56 void deepEqualsTest() {
57 var actual = Dnf.builder("Actual").parameters(q).clause(
58 Dnf.builder("Actual2").parameters(p).clause(personView.call(p)).build().call(q)
59 ).build();
60
61 assertThat(actual, structurallyEqualTo(
62 List.of(new SymbolicParameter(q, ParameterDirection.OUT)),
63 List.of(
64 List.of(
65 Dnf.builder("Expected2").parameters(p).clause(personView.call(p)).build().call(q)
66 )
67 )
68 ));
69 }
70
71 @Test
72 void deepNotEqualsTest() {
73 var actual = Dnf.builder("Actual").parameter(q).clause(
74 Dnf.builder("Actual2").parameters(p).clause(friendView.call(p, q)).build().call(q)
75 ).build();
76
77 var assertion = structurallyEqualTo(
78 List.of(new SymbolicParameter(q, ParameterDirection.OUT)),
79 List.of(
80 List.of(
81 Dnf.builder("Expected2")
82 .parameters(p)
83 .clause(friendView.call(p, p))
84 .build()
85 .call(q)
86 )
87 )
88 );
89 var error = assertThrows(AssertionError.class, () -> assertThat(actual, assertion));
90 assertThat(error.getMessage(), allOf(containsString("Expected2"), containsString("Actual2")));
91 }
92
93 @Test
94 void parameterListLengthMismatchTest() {
95 var actual = Dnf.builder("Actual").parameters(p, q).clause(
96 friendView.call(p, q)
97 ).build();
98
99 var assertion = structurallyEqualTo(
100 List.of(new SymbolicParameter(p, ParameterDirection.OUT)),
101 List.of(List.of(friendView.call(p, p)))
102 );
103
104 assertThrows(AssertionError.class, () -> assertThat(actual, assertion));
105 }
106
107 @Test
108 void parameterDirectionMismatchTest() {
109 var actual = Dnf.builder("Actual").parameter(p, ParameterDirection.IN).clause(
110 personView.call(p)
111 ).build();
112
113 var assertion = structurallyEqualTo(
114 List.of(new SymbolicParameter(p, ParameterDirection.OUT)),
115 List.of(List.of(personView.call(p)))
116 );
117
118 assertThrows(AssertionError.class, () -> assertThat(actual, assertion));
119 }
120
121 @Test
122 void clauseCountMismatchTest() {
123 var actual = Dnf.builder("Actual").parameters(p, q).clause(
124 friendView.call(p, q)
125 ).build();
126
127 var assertion = structurallyEqualTo(
128 List.of(
129 new SymbolicParameter(p, ParameterDirection.OUT),
130 new SymbolicParameter(q, ParameterDirection.OUT)
131 ),
132 List.of(
133 List.of(friendView.call(p, q)),
134 List.of(friendView.call(q, p))
135 )
136 );
137
138 assertThrows(AssertionError.class, () -> assertThat(actual, assertion));
139 }
140
141 @Test
142 void literalCountMismatchTest() {
143 var actual = Dnf.builder("Actual").parameters(p, q).clause(
144 friendView.call(p, q)
145 ).build();
146
147 var assertion = structurallyEqualTo(
148 List.of(
149 new SymbolicParameter(p, ParameterDirection.OUT),
150 new SymbolicParameter(q, ParameterDirection.OUT)
151 ),
152 List.of(
153 List.of(friendView.call(p, q), friendView.call(q, p))
154 )
155 );
156
157 assertThrows(AssertionError.class, () -> assertThat(actual, assertion));
158 }
159}
diff --git a/subprojects/store-query/src/test/java/tools/refinery/store/query/tests/StructurallyEqualToTest.java b/subprojects/store-query/src/test/java/tools/refinery/store/query/tests/StructurallyEqualToTest.java
deleted file mode 100644
index f716b805..00000000
--- a/subprojects/store-query/src/test/java/tools/refinery/store/query/tests/StructurallyEqualToTest.java
+++ /dev/null
@@ -1,127 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.tests;
7
8import org.junit.jupiter.api.Test;
9import tools.refinery.store.query.dnf.Dnf;
10import tools.refinery.store.query.term.NodeVariable;
11import tools.refinery.store.query.term.ParameterDirection;
12import tools.refinery.store.query.term.Variable;
13import tools.refinery.store.query.view.AnySymbolView;
14import tools.refinery.store.query.view.KeyOnlyView;
15import tools.refinery.store.representation.Symbol;
16
17import static org.hamcrest.CoreMatchers.containsString;
18import static org.hamcrest.MatcherAssert.assertThat;
19import static org.junit.jupiter.api.Assertions.assertThrows;
20import static tools.refinery.store.query.tests.QueryMatchers.structurallyEqualTo;
21
22class StructurallyEqualToTest {
23 private static final Symbol<Boolean> person = Symbol.of("Person", 1);
24 private static final Symbol<Boolean> friend = Symbol.of("friend", 2);
25 private static final AnySymbolView personView = new KeyOnlyView<>(person);
26 private static final AnySymbolView friendView = new KeyOnlyView<>(friend);
27 private static final NodeVariable p = Variable.of("p");
28 private static final NodeVariable q = Variable.of("q");
29
30 @Test
31 void flatEqualsTest() {
32 var expected = Dnf.builder("Expected").parameters(q).clause(personView.call(q)).build();
33 var actual = Dnf.builder("Actual").parameters(p).clause(personView.call(p)).build();
34
35 assertThat(actual, structurallyEqualTo(expected));
36 }
37
38 @Test
39 void flatNotEqualsTest() {
40 var expected = Dnf.builder("Expected").parameters(q).clause(friendView.call(q, q)).build();
41 var actual = Dnf.builder("Actual").parameters(p).clause(friendView.call(p, q)).build();
42
43 var assertion = structurallyEqualTo(expected);
44 assertThrows(AssertionError.class, () -> assertThat(actual, assertion));
45 }
46
47 @Test
48 void deepEqualsTest() {
49 var expected = Dnf.builder("Expected").parameters(q).clause(
50 Dnf.builder("Expected2").parameters(p).clause(personView.call(p)).build().call(q)
51 ).build();
52 var actual = Dnf.builder("Actual").parameters(q).clause(
53 Dnf.builder("Actual2").parameters(p).clause(personView.call(p)).build().call(q)
54 ).build();
55
56 assertThat(actual, structurallyEqualTo(expected));
57 }
58
59 @Test
60 void deepNotEqualsTest() {
61 var expected = Dnf.builder("Expected").parameters(q).clause(
62 Dnf.builder("Expected2").parameters(p).clause(friendView.call(p, p)).build().call(q)
63 ).build();
64 var actual = Dnf.builder("Actual").parameter(q).clause(
65 Dnf.builder("Actual2").parameters(p).clause(friendView.call(p, q)).build().call(q)
66 ).build();
67
68 var assertion = structurallyEqualTo(expected);
69 var error = assertThrows(AssertionError.class, () -> assertThat(actual, assertion));
70 assertThat(error.getMessage(), containsString(" called from Expected/1 "));
71 }
72
73 @Test
74 void parameterListLengthMismatchTest() {
75 var expected = Dnf.builder("Expected").parameter(p).clause(
76 friendView.call(p, p)
77 ).build();
78 var actual = Dnf.builder("Actual").parameters(p, q).clause(
79 friendView.call(p, q)
80 ).build();
81
82 var assertion = structurallyEqualTo(expected);
83 assertThrows(AssertionError.class, () -> assertThat(actual, assertion));
84 }
85
86 @Test
87 void parameterDirectionMismatchTest() {
88 var expected = Dnf.builder("Expected").parameter(p, ParameterDirection.OUT).clause(
89 personView.call(p)
90 ).build();
91 var actual = Dnf.builder("Actual").parameter(p, ParameterDirection.IN).clause(
92 personView.call(p)
93 ).build();
94
95 var assertion = structurallyEqualTo(expected);
96 assertThrows(AssertionError.class, () -> assertThat(actual, assertion));
97 }
98
99 @Test
100 void clauseCountMismatchTest() {
101 var expected = Dnf.builder("Expected")
102 .parameters(p, q)
103 .clause(friendView.call(p, q))
104 .clause(friendView.call(q, p))
105 .build();
106 var actual = Dnf.builder("Actual").parameters(p, q).clause(
107 friendView.call(p, q)
108 ).build();
109
110 var assertion = structurallyEqualTo(expected);
111 assertThrows(AssertionError.class, () -> assertThat(actual, assertion));
112 }
113
114 @Test
115 void literalCountMismatchTest() {
116 var expected = Dnf.builder("Expected").parameters(p, q).clause(
117 friendView.call(p, q),
118 friendView.call(q, p)
119 ).build();
120 var actual = Dnf.builder("Actual").parameters(p, q).clause(
121 friendView.call(p, q)
122 ).build();
123
124 var assertion = structurallyEqualTo(expected);
125 assertThrows(AssertionError.class, () -> assertThat(actual, assertion));
126 }
127}
diff --git a/subprojects/store-query/src/testFixtures/java/tools/refinery/store/query/tests/MismatchDescribingDnfEqualityChecker.java b/subprojects/store-query/src/testFixtures/java/tools/refinery/store/query/tests/MismatchDescribingDnfEqualityChecker.java
deleted file mode 100644
index 6a3301b3..00000000
--- a/subprojects/store-query/src/testFixtures/java/tools/refinery/store/query/tests/MismatchDescribingDnfEqualityChecker.java
+++ /dev/null
@@ -1,68 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.tests;
7
8import org.hamcrest.Description;
9import tools.refinery.store.query.dnf.Dnf;
10import tools.refinery.store.query.dnf.SymbolicParameter;
11import tools.refinery.store.query.equality.DeepDnfEqualityChecker;
12import tools.refinery.store.query.literal.Literal;
13
14import java.util.List;
15
16class MismatchDescribingDnfEqualityChecker extends DeepDnfEqualityChecker {
17 private final Description description;
18 private boolean raw;
19 private boolean needsDescription = true;
20
21 MismatchDescribingDnfEqualityChecker(Description description) {
22 this.description = description;
23 }
24
25 public boolean needsDescription() {
26 return needsDescription;
27 }
28
29 @Override
30 public boolean dnfEqualRaw(List<SymbolicParameter> symbolicParameters, List<? extends List<? extends Literal>> clauses, Dnf other) {
31 try {
32 raw = true;
33 boolean result = super.dnfEqualRaw(symbolicParameters, clauses, other);
34 if (!result && needsDescription) {
35 description.appendText("was ").appendText(other.toDefinitionString());
36 }
37 return false;
38 } finally {
39 raw = false;
40 }
41 }
42
43 @Override
44 protected boolean doCheckEqual(Pair pair) {
45 boolean result = super.doCheckEqual(pair);
46 if (!result && needsDescription) {
47 describeMismatch(pair);
48 // Only describe the first found (innermost) mismatch.
49 needsDescription = false;
50 }
51 return result;
52 }
53
54 private void describeMismatch(Pair pair) {
55 var inProgress = getInProgress();
56 int size = inProgress.size();
57 if (size <= 1 && !raw) {
58 description.appendText("was ").appendText(pair.right().toDefinitionString());
59 return;
60 }
61 var last = inProgress.get(size - 1);
62 description.appendText("expected ").appendText(last.left().toDefinitionString());
63 for (int i = size - 2; i >= 0; i--) {
64 description.appendText(" called from ").appendText(inProgress.get(i).left().toString());
65 }
66 description.appendText(" was not structurally equal to ").appendText(last.right().toDefinitionString());
67 }
68}
diff --git a/subprojects/store-query/src/testFixtures/java/tools/refinery/store/query/tests/QueryMatchers.java b/subprojects/store-query/src/testFixtures/java/tools/refinery/store/query/tests/QueryMatchers.java
deleted file mode 100644
index cd449a6a..00000000
--- a/subprojects/store-query/src/testFixtures/java/tools/refinery/store/query/tests/QueryMatchers.java
+++ /dev/null
@@ -1,46 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.tests;
7
8import org.hamcrest.Matcher;
9import tools.refinery.store.query.dnf.Dnf;
10import tools.refinery.store.query.dnf.SymbolicParameter;
11import tools.refinery.store.query.literal.Literal;
12
13import java.util.List;
14
15public final class QueryMatchers {
16 private QueryMatchers() {
17 throw new IllegalStateException("This is a static utility class and should not be instantiated directly");
18 }
19
20 /**
21 * Compare two {@link Dnf} instances up to renaming of variables.
22 *
23 * @param expected The expected {@link Dnf} instance.
24 * @return A Hamcrest matcher for equality up to renaming of variables.
25 */
26 public static Matcher<Dnf> structurallyEqualTo(Dnf expected) {
27 return new StructurallyEqualTo(expected);
28 }
29
30 /**
31 * Compare a {@link Dnf} instance to another predicate in DNF form without constructing it.
32 * <p>
33 * This matcher should be used instead of {@link #structurallyEqualTo(Dnf)} when the validation and
34 * pre-processing associated with the {@link Dnf} constructor, i.e., validation of parameter directions,
35 * topological sorting of literals, and the reduction of trivial predicates is not desired. In particular, this
36 * matcher can be used to test for exact order of literal after pre-processing.
37 *
38 * @param expectedSymbolicParameters The expected list of symbolic parameters.
39 * @param expectedLiterals The expected clauses. Each clause is represented by a list of literals.
40 * @return A Hamcrest matcher for equality up to renaming of variables.
41 */
42 public static Matcher<Dnf> structurallyEqualTo(List<SymbolicParameter> expectedSymbolicParameters,
43 List<? extends List<? extends Literal>> expectedLiterals) {
44 return new StructurallyEqualToRaw(expectedSymbolicParameters, expectedLiterals);
45 }
46}
diff --git a/subprojects/store-query/src/testFixtures/java/tools/refinery/store/query/tests/StructurallyEqualTo.java b/subprojects/store-query/src/testFixtures/java/tools/refinery/store/query/tests/StructurallyEqualTo.java
deleted file mode 100644
index 86149141..00000000
--- a/subprojects/store-query/src/testFixtures/java/tools/refinery/store/query/tests/StructurallyEqualTo.java
+++ /dev/null
@@ -1,41 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.tests;
7
8import org.hamcrest.Description;
9import org.hamcrest.TypeSafeMatcher;
10import tools.refinery.store.query.dnf.Dnf;
11import tools.refinery.store.query.equality.DeepDnfEqualityChecker;
12
13public class StructurallyEqualTo extends TypeSafeMatcher<Dnf> {
14 private final Dnf expected;
15
16 public StructurallyEqualTo(Dnf expected) {
17 this.expected = expected;
18 }
19
20 @Override
21 protected boolean matchesSafely(Dnf item) {
22 var checker = new DeepDnfEqualityChecker();
23 return checker.dnfEqual(expected, item);
24 }
25
26 @Override
27 protected void describeMismatchSafely(Dnf item, Description mismatchDescription) {
28 var describingChecker = new MismatchDescribingDnfEqualityChecker(mismatchDescription);
29 if (describingChecker.dnfEqual(expected, item)) {
30 throw new IllegalStateException("Mismatched Dnf was matching on repeated comparison");
31 }
32 if (describingChecker.needsDescription()) {
33 super.describeMismatchSafely(item, mismatchDescription);
34 }
35 }
36
37 @Override
38 public void describeTo(Description description) {
39 description.appendText("structurally equal to ").appendText(expected.toDefinitionString());
40 }
41}
diff --git a/subprojects/store-query/src/testFixtures/java/tools/refinery/store/query/tests/StructurallyEqualToRaw.java b/subprojects/store-query/src/testFixtures/java/tools/refinery/store/query/tests/StructurallyEqualToRaw.java
deleted file mode 100644
index 2f8c2944..00000000
--- a/subprojects/store-query/src/testFixtures/java/tools/refinery/store/query/tests/StructurallyEqualToRaw.java
+++ /dev/null
@@ -1,51 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.tests;
7
8import org.hamcrest.Description;
9import org.hamcrest.TypeSafeMatcher;
10import tools.refinery.store.query.dnf.Dnf;
11import tools.refinery.store.query.dnf.SymbolicParameter;
12import tools.refinery.store.query.equality.DeepDnfEqualityChecker;
13import tools.refinery.store.query.literal.Literal;
14
15import java.util.List;
16
17public class StructurallyEqualToRaw extends TypeSafeMatcher<Dnf> {
18 private final List<SymbolicParameter> expectedSymbolicParameters;
19 private final List<? extends List<? extends Literal>> expectedClauses;
20
21 public StructurallyEqualToRaw(List<SymbolicParameter> expectedSymbolicParameters,
22 List<? extends List<? extends Literal>> expectedClauses) {
23 this.expectedSymbolicParameters = expectedSymbolicParameters;
24 this.expectedClauses = expectedClauses;
25 }
26
27 @Override
28 protected boolean matchesSafely(Dnf item) {
29 var checker = new DeepDnfEqualityChecker();
30 return checker.dnfEqualRaw(expectedSymbolicParameters, expectedClauses, item);
31 }
32
33 @Override
34 protected void describeMismatchSafely(Dnf item, Description mismatchDescription) {
35 var describingChecker = new MismatchDescribingDnfEqualityChecker(mismatchDescription);
36 if (describingChecker.dnfEqualRaw(expectedSymbolicParameters, expectedClauses, item)) {
37 throw new IllegalStateException("Mismatched Dnf was matching on repeated comparison");
38 }
39 if (describingChecker.needsDescription()) {
40 super.describeMismatchSafely(item, mismatchDescription);
41 }
42 }
43
44 @Override
45 public void describeTo(Description description) {
46 description.appendText("structurally equal to ")
47 .appendValueList("(", ", ", ")", expectedSymbolicParameters)
48 .appendText(" <-> ")
49 .appendValueList("", ", ", ".", expectedClauses);
50 }
51}